mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-27 00:50:45 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
174
js/amount.js
174
js/amount.js
@@ -1,6 +1,8 @@
|
||||
// Represent Ripple amounts and currencies.
|
||||
// - Numbers in hex are big-endian.
|
||||
|
||||
var sjcl = require('./sjcl/core.js');
|
||||
var bn = require('./sjcl/core.js').bn;
|
||||
var utils = require('./utils.js');
|
||||
var jsbn = require('./jsbn.js');
|
||||
|
||||
@@ -8,11 +10,122 @@ var jsbn = require('./jsbn.js');
|
||||
var config = require('../test/config.js');
|
||||
|
||||
var BigInteger = jsbn.BigInteger;
|
||||
var nbi = jsbn.nbi;
|
||||
|
||||
var alphabets = {
|
||||
'ripple' : "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz",
|
||||
'bitcoin' : "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
};
|
||||
|
||||
// --> input: big-endian array of bytes.
|
||||
// <-- string at least as long as input.
|
||||
var encode_base = function (input, alphabet) {
|
||||
var alphabet = alphabets[alphabet || 'ripple'];
|
||||
var bi_base = new BigInteger(String(alphabet.length));
|
||||
var bi_q = nbi();
|
||||
var bi_r = nbi();
|
||||
var bi_value = new BigInteger(input);
|
||||
var buffer = [];
|
||||
|
||||
while (bi_value.compareTo(BigInteger.ZERO) > 0)
|
||||
{
|
||||
bi_value.divRemTo(bi_base, bi_q, bi_r);
|
||||
bi_q.copyTo(bi_value);
|
||||
|
||||
buffer.push(alphabet[bi_r.intValue()]);
|
||||
}
|
||||
|
||||
var i;
|
||||
|
||||
for (i = 0; i != input.length && !input[i]; i += 1) {
|
||||
buffer.push(alphabet[0]);
|
||||
}
|
||||
|
||||
return buffer.reverse().join("");
|
||||
};
|
||||
|
||||
// --> input: String
|
||||
// <-- array of bytes or undefined.
|
||||
var decode_base = function (input, alphabet) {
|
||||
var alphabet = alphabets[alphabet || 'ripple'];
|
||||
var bi_base = new BigInteger(String(alphabet.length));
|
||||
var bi_value = nbi();
|
||||
var i;
|
||||
|
||||
for (i = 0; i != input.length && input[i] === alphabet[0]; i += 1)
|
||||
;
|
||||
|
||||
for (; i != input.length; i += 1) {
|
||||
var v = alphabet.indexOf(input[i]);
|
||||
|
||||
if (v < 0)
|
||||
return undefined;
|
||||
|
||||
var r = nbi();
|
||||
|
||||
r.fromInt(v);
|
||||
|
||||
bi_value = bi_value.multiply(bi_base).add(r);
|
||||
}
|
||||
|
||||
// toByteArray:
|
||||
// - Returns leading zeros!
|
||||
// - Returns signed bytes!
|
||||
var bytes = bi_value.toByteArray().map(function (b) { return b ? b < 0 ? 256+b : b : 0});
|
||||
var extra = 0;
|
||||
|
||||
while (extra != bytes.length && !bytes[extra])
|
||||
extra += 1;
|
||||
|
||||
if (extra)
|
||||
bytes = bytes.slice(extra);
|
||||
|
||||
var zeros = 0;
|
||||
|
||||
while (zeros !== input.length && input[zeros] === alphabet[0])
|
||||
zeros += 1;
|
||||
|
||||
return [].concat(utils.arraySet(zeros, 0), bytes);
|
||||
};
|
||||
|
||||
var sha256 = function (bytes) {
|
||||
return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
||||
};
|
||||
|
||||
var sha256hash = function (bytes) {
|
||||
return sha256(sha256(bytes));
|
||||
};
|
||||
|
||||
// --> input: Array
|
||||
// <-- String
|
||||
var encode_base_check = function (version, input, alphabet) {
|
||||
var buffer = [].concat(version, input);
|
||||
var check = sha256(sha256(buffer)).slice(0, 4);
|
||||
|
||||
return encode_base([].concat(buffer, check), alphabet);
|
||||
}
|
||||
|
||||
// --> input : String
|
||||
// <-- NaN || BigInteger
|
||||
var decode_base_check = function (version, input, alphabet) {
|
||||
var buffer = decode_base(input, alphabet);
|
||||
|
||||
if (!buffer || buffer[0] !== version || buffer.length < 5)
|
||||
return NaN;
|
||||
|
||||
var computed = sha256hash(buffer.slice(0, -4)).slice(0, 4);
|
||||
var checksum = buffer.slice(-4);
|
||||
var i;
|
||||
|
||||
for (i = 0; i != 4; i += 1)
|
||||
if (computed[i] !== checksum[i])
|
||||
return NaN;
|
||||
|
||||
return new BigInteger(buffer.slice(1, -4));
|
||||
}
|
||||
|
||||
var UInt160 = function () {
|
||||
// Internal form:
|
||||
// 0, 1, 'iXXXXX', 20 byte string, or NaN.
|
||||
// XXX Should standardize on 'i' format or 20 format.
|
||||
// Internal form: NaN or BigInteger
|
||||
this.value = NaN;
|
||||
};
|
||||
|
||||
@@ -39,7 +152,7 @@ UInt160.prototype.copyTo = function(d) {
|
||||
};
|
||||
|
||||
UInt160.prototype.equals = function(d) {
|
||||
return this.value === d.value;
|
||||
return isNaN(this.value) || isNaN(d.value) ? false : this.value.equals(d.value);
|
||||
};
|
||||
|
||||
// value = NaN on error.
|
||||
@@ -54,14 +167,15 @@ UInt160.prototype.parse_json = function (j) {
|
||||
case exports.consts.address_xns:
|
||||
case exports.consts.uint160_xns:
|
||||
case exports.consts.hex_xns:
|
||||
this.value = 0;
|
||||
this.value = nbi();
|
||||
break;
|
||||
|
||||
case "1":
|
||||
case exports.consts.address_one:
|
||||
case exports.consts.uint160_one:
|
||||
case exports.consts.hex_one:
|
||||
this.value = 1;
|
||||
this.value = new BigInteger([1]);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -69,15 +183,14 @@ UInt160.prototype.parse_json = function (j) {
|
||||
this.value = NaN;
|
||||
}
|
||||
else if (20 === j.length) {
|
||||
this.value = j;
|
||||
this.value = new BigInteger(utils.stringToArray(j), 256);
|
||||
}
|
||||
else if (40 === j.length) {
|
||||
this.value = utils.hexToString(j);
|
||||
// XXX Check char set!
|
||||
this.value = new BigInteger(j, 16);
|
||||
}
|
||||
else if (j[0] === "r") {
|
||||
// XXX Do more checking convert to string.
|
||||
|
||||
this.value = j;
|
||||
this.value = decode_base_check(0, j);
|
||||
}
|
||||
else {
|
||||
this.value = NaN;
|
||||
@@ -90,25 +203,26 @@ UInt160.prototype.parse_json = function (j) {
|
||||
// Convert from internal form.
|
||||
// XXX Json form should allow 0 and 1, C++ doesn't currently allow it.
|
||||
UInt160.prototype.to_json = function () {
|
||||
if ("0" === this.value) {
|
||||
return exports.consts.hex_xns;
|
||||
}
|
||||
else if ("1" === this.value)
|
||||
{
|
||||
return exports.consts.hex_one;
|
||||
}
|
||||
else if ('string' === typeof this.value && 20 === this.value.length) {
|
||||
return utils.stringToHex(this.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
if (isNaN(this.value))
|
||||
return NaN;
|
||||
|
||||
var bytes = this.value.toByteArray().map(function (b) { return b ? b < 0 ? 256+b : b : 0});
|
||||
var target = 20;
|
||||
|
||||
// XXX Make sure only trim off leading zeros.
|
||||
var array = bytes.length < target
|
||||
? bytes.length
|
||||
? [].concat(utils.arraySet(target - bytes.length, 0), bytes)
|
||||
: utils.arraySet(target, 0)
|
||||
: bytes.slice(target - bytes.length);
|
||||
var output = encode_base_check(0, array);
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
var Currency = function () {
|
||||
// Internal form: 0 = XNS. 3 letter-code.
|
||||
// XXX Internal should be 0 or hex.
|
||||
// XXX Internal should be 0 or hex with three letter annotation when valid.
|
||||
|
||||
// Json form:
|
||||
// '', 'XNS', '0': 0
|
||||
@@ -193,7 +307,7 @@ Amount.prototype.copyTo = function(d, negate) {
|
||||
if ('object' === typeof this.value)
|
||||
{
|
||||
if (this.is_native && negate)
|
||||
this.value.negate.copyTo(d.value);
|
||||
this.value.negate().copyTo(d.value);
|
||||
else
|
||||
this.value.copyTo(d.value);
|
||||
}
|
||||
@@ -204,7 +318,11 @@ Amount.prototype.copyTo = function(d, negate) {
|
||||
|
||||
d.offset = this.offset;
|
||||
d.is_native = this.is_native;
|
||||
d.is_negative = this.is_negative ? undefined : !this.is_negative;
|
||||
d.is_negative = this.is_native
|
||||
? undefined // Native sign in BigInteger.
|
||||
: negate
|
||||
? !this.is_negative // Negating.
|
||||
: this.is_negative; // Just copying.
|
||||
|
||||
this.currency.copyTo(d.currency);
|
||||
this.issuer.copyTo(d.issuer);
|
||||
|
||||
10
js/remote.js
10
js/remote.js
@@ -744,16 +744,16 @@ Remote.prototype.request_ripple_balance = function (account, issuer, currency, c
|
||||
|
||||
var lowLimit = Amount.from_json(node.LowLimit);
|
||||
var highLimit = Amount.from_json(node.HighLimit);
|
||||
// The amount account holds of issuer (after negation if needed).
|
||||
// The amount the low account holds of issuer.
|
||||
var balance = Amount.from_json(node.Balance);
|
||||
// accountHigh implies: for account: balance is negated, highLimit is the limit set by account.
|
||||
var accountHigh = UInt160.from_json(account).equals(highLimit.issuer);
|
||||
// The limit set by issuer.
|
||||
var issuerLimit = (accountHigh ? lowLimit : highLimit).parse_issuer(issuer);
|
||||
// The limit set by account.
|
||||
var accountLimit = (accountHigh ? highLimit : lowLimit).parse_issuer(account);
|
||||
var issuerBalance = (accountHigh ? balance.negate() : balance).parse_issuer(issuer);
|
||||
var accountBalance = issuerBalance.clone().negate().parse_issuer(account);
|
||||
// The limit set by issuer.
|
||||
var issuerLimit = (accountHigh ? lowLimit : highLimit).parse_issuer(issuer);
|
||||
var accountBalance = (accountHigh ? balance.negate() : balance).parse_issuer(account);
|
||||
var issuerBalance = (accountHigh ? balance : balance.negate()).parse_issuer(issuer);
|
||||
|
||||
request.emit('ripple_state', {
|
||||
'issuer_balance' : issuerBalance, // Balance with dst as issuer.
|
||||
|
||||
22
js/utils.js
22
js/utils.js
@@ -44,6 +44,16 @@ var trace = function(comment, func) {
|
||||
};
|
||||
};
|
||||
|
||||
var arraySet = function (count, value) {
|
||||
var a = new Array(count);
|
||||
var i;
|
||||
|
||||
for (i = 0; i != count; i += 1)
|
||||
a[i] = value;
|
||||
|
||||
return a;
|
||||
};
|
||||
|
||||
var hexToString = function (h) {
|
||||
var a = [];
|
||||
var i = 0;
|
||||
@@ -68,9 +78,21 @@ var stringToHex = function (s) {
|
||||
}).join("");
|
||||
};
|
||||
|
||||
var stringToArray = function (s) {
|
||||
var a = new Array(s.length);
|
||||
var i;
|
||||
|
||||
for (i = 0; i != a.length; i += 1)
|
||||
a[i] = s.charCodeAt(i);
|
||||
|
||||
return a;
|
||||
};
|
||||
|
||||
exports.mapOr = mapOr;
|
||||
exports.trace = trace;
|
||||
exports.arraySet = arraySet;
|
||||
exports.hexToString = hexToString;
|
||||
exports.stringToArray = stringToArray;
|
||||
exports.stringToHex = stringToHex;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8
|
||||
|
||||
@@ -166,8 +166,6 @@ STAmount::STAmount(SField::ref n, const Json::Value& v)
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("invalid amount type");
|
||||
|
||||
cLog(lsTRACE) << "Parsed: " << this->getJson(0);
|
||||
}
|
||||
|
||||
std::string STAmount::createHumanCurrency(const uint160& uCurrency)
|
||||
|
||||
@@ -70,8 +70,9 @@ void Application::run()
|
||||
{
|
||||
assert(mTxnDB == NULL);
|
||||
if (!theConfig.DEBUG_LOGFILE.empty())
|
||||
{
|
||||
{ // Let DEBUG messages go to the file but only WARNING or higher to regular output
|
||||
Log::setLogFile(theConfig.DEBUG_LOGFILE);
|
||||
Log::setMinSeverity(lsWARNING);
|
||||
LogPartition::setSeverity(lsDEBUG);
|
||||
}
|
||||
|
||||
@@ -112,6 +113,13 @@ void Application::run()
|
||||
else
|
||||
startNewLedger();
|
||||
|
||||
if (theConfig.FULL_HISTORY && (theConfig.START_UP != Config::LOAD))
|
||||
{
|
||||
Ledger::pointer ledger = Ledger::getLastFullLedger();
|
||||
if (ledger)
|
||||
mMasterLedger.setLastFullLedger(ledger);
|
||||
}
|
||||
|
||||
//
|
||||
// Begin validation and ip maintenance.
|
||||
// - Wallet maintains local information: including identity and network connection persistence information.
|
||||
@@ -214,7 +222,7 @@ void Application::loadOldLedger()
|
||||
{
|
||||
try
|
||||
{
|
||||
Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;");
|
||||
Ledger::pointer lastLedger = Ledger::getLastFullLedger();
|
||||
|
||||
if (!lastLedger)
|
||||
{
|
||||
@@ -243,6 +251,7 @@ void Application::loadOldLedger()
|
||||
cLog(lsFATAL) << "Ledger is not sane.";
|
||||
exit(-1);
|
||||
}
|
||||
mMasterLedger.setLastFullLedger(lastLedger);
|
||||
|
||||
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*lastLedger));
|
||||
mMasterLedger.switchLedgers(lastLedger, openLedger);
|
||||
|
||||
@@ -37,7 +37,7 @@ bool CanonicalTXKey::operator>=(const CanonicalTXKey& key)const
|
||||
return mTXid >= key.mTXid;
|
||||
}
|
||||
|
||||
void CanonicalTXSet::push_back(const SerializedTransaction::pointer& txn)
|
||||
void CanonicalTXSet::push_back(SerializedTransaction::ref txn)
|
||||
{
|
||||
uint256 effectiveAccount = mSetHash;
|
||||
effectiveAccount ^= txn->getSourceAccount().getAccountID().to256();
|
||||
|
||||
@@ -38,7 +38,7 @@ protected:
|
||||
public:
|
||||
CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; }
|
||||
|
||||
void push_back(const SerializedTransaction::pointer& txn);
|
||||
void push_back(SerializedTransaction::ref txn);
|
||||
iterator erase(const iterator& it);
|
||||
|
||||
iterator begin() { return mMap.begin(); }
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create"
|
||||
#define SECTION_FEE_OFFER "fee_offer"
|
||||
#define SECTION_FEE_OPERATION "fee_operation"
|
||||
#define SECTION_FULL_HISTORY "full_history"
|
||||
#define SECTION_IPS "ips"
|
||||
#define SECTION_NETWORK_QUORUM "network_quorum"
|
||||
#define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water"
|
||||
@@ -150,6 +151,8 @@ void Config::setup(const std::string& strConf)
|
||||
FEE_DEFAULT = DEFAULT_FEE_DEFAULT;
|
||||
FEE_CONTRACT_OPERATION = DEFAULT_FEE_OPERATION;
|
||||
|
||||
FULL_HISTORY = false;
|
||||
|
||||
ACCOUNT_PROBE_MAX = 10;
|
||||
|
||||
VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE;
|
||||
@@ -266,6 +269,9 @@ void Config::load()
|
||||
if (sectionSingleB(secConfig, SECTION_FEE_OPERATION, strTemp))
|
||||
FEE_CONTRACT_OPERATION = boost::lexical_cast<int>(strTemp);
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_FULL_HISTORY, strTemp))
|
||||
FULL_HISTORY = boost::lexical_cast<bool>(strTemp);
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp))
|
||||
ACCOUNT_PROBE_MAX = boost::lexical_cast<int>(strTemp);
|
||||
|
||||
|
||||
@@ -102,6 +102,9 @@ public:
|
||||
uint64 FEE_OFFER; // Rate per day.
|
||||
int FEE_CONTRACT_OPERATION; // fee for each contract operation
|
||||
|
||||
// Node storage configuration
|
||||
bool FULL_HISTORY;
|
||||
|
||||
// Client behavior
|
||||
int ACCOUNT_PROBE_MAX; // How far to scan for accounts.
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
|
||||
// Functions to add CKey support for deterministic EC keys
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "Serializer.h"
|
||||
#include "Log.h"
|
||||
|
||||
// <-- seed
|
||||
uint128 CKey::PassPhraseToKey(const std::string& passPhrase)
|
||||
@@ -304,4 +307,34 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& pubGen, cons
|
||||
return pkey;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(DeterministicKeys_test)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DeterminsticKeys_test1)
|
||||
{
|
||||
Log(lsDEBUG) << "Beginning deterministic key test";
|
||||
|
||||
uint128 seed1, seed2;
|
||||
seed1.SetHex("71ED064155FFADFA38782C5E0158CB26");
|
||||
seed2.SetHex("CF0C3BE4485961858C4198515AE5B965");
|
||||
CKey root1(seed1), root2(seed2);
|
||||
|
||||
uint256 priv1, priv2;
|
||||
root1.GetPrivateKeyU(priv1);
|
||||
root2.GetPrivateKeyU(priv2);
|
||||
|
||||
if (priv1.GetHex() != "7CFBA64F771E93E817E15039215430B53F7401C34931D111EAB3510B22DBB0D8")
|
||||
BOOST_FAIL("Incorrect private key for generator");
|
||||
if (priv2.GetHex() != "98BC2EACB26EB021D1A6293C044D88BA2F0B6729A2772DEEBF2E21A263C1740B")
|
||||
BOOST_FAIL("Incorrect private key for generator");
|
||||
|
||||
NewcoinAddress nSeed;
|
||||
nSeed.setSeed(seed1);
|
||||
if (nSeed.humanSeed() != "shHM53KPZ87Gwdqarm1bAmPeXg8Tn")
|
||||
BOOST_FAIL("Incorrect human seed");
|
||||
if (nSeed.humanSeed1751() != "MAD BODY ACE MINT OKAY HUB WHAT DATA SACK FLAT DANA MATH")
|
||||
BOOST_FAIL("Incorrect 1751 seed");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -337,7 +337,7 @@ uint256 Ledger::getHash()
|
||||
return mHash;
|
||||
}
|
||||
|
||||
void Ledger::saveAcceptedLedger()
|
||||
void Ledger::saveAcceptedLedger(bool fromConsensus)
|
||||
{ // can be called in a different thread
|
||||
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;");
|
||||
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;");
|
||||
@@ -428,7 +428,16 @@ void Ledger::saveAcceptedLedger()
|
||||
mAccountHash.GetHex() % mTransHash.GetHex()));
|
||||
}
|
||||
|
||||
if (!fromConsensus)
|
||||
return;
|
||||
|
||||
theApp->getOPs().pubLedger(shared_from_this());
|
||||
|
||||
if(theConfig.FULL_HISTORY)
|
||||
{
|
||||
// WRITEME: check for seamless ledger history
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
@@ -498,6 +507,11 @@ Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash)
|
||||
return getSQL(sql);
|
||||
}
|
||||
|
||||
Ledger::pointer Ledger::getLastFullLedger()
|
||||
{
|
||||
return getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;");
|
||||
}
|
||||
|
||||
void Ledger::addJson(Json::Value& ret, int options)
|
||||
{
|
||||
ret["ledger"] = getJson(options);
|
||||
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
Ledger(Ledger& target, bool isMutable); // snapshot
|
||||
|
||||
static Ledger::pointer getSQL(const std::string& sqlStatement);
|
||||
static Ledger::pointer getLastFullLedger();
|
||||
|
||||
void updateHash();
|
||||
void setClosed() { mClosed = true; }
|
||||
@@ -156,7 +157,7 @@ public:
|
||||
SLE::pointer getAccountRoot(const NewcoinAddress& naAccountID);
|
||||
|
||||
// database functions
|
||||
void saveAcceptedLedger();
|
||||
void saveAcceptedLedger(bool fromConsensus);
|
||||
static Ledger::pointer loadByIndex(uint32 ledgerIndex);
|
||||
static Ledger::pointer loadByHash(const uint256& ledgerHash);
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "SHAMapSync.h"
|
||||
#include "HashPrefixes.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
// #define LA_DEBUG
|
||||
#define LEDGER_ACQUIRE_TIMEOUT 750
|
||||
#define TRUST_NETWORK
|
||||
@@ -72,7 +74,7 @@ void PeerSet::invokeOnTimer()
|
||||
if (!mProgress)
|
||||
{
|
||||
++mTimeouts;
|
||||
Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash;
|
||||
cLog(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash;
|
||||
}
|
||||
else
|
||||
mProgress = false;
|
||||
@@ -89,10 +91,10 @@ void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::err
|
||||
}
|
||||
|
||||
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false)
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false), mAccept(false)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "Acquiring ledger " << mHash;
|
||||
cLog(lsTRACE) << "Acquiring ledger " << mHash;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -156,7 +158,7 @@ void LedgerAcquire::done()
|
||||
return;
|
||||
mSignaled = true;
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "Done acquiring ledger " << mHash;
|
||||
cLog(lsTRACE) << "Done acquiring ledger " << mHash;
|
||||
#endif
|
||||
std::vector< boost::function<void (LedgerAcquire::pointer)> > triggers;
|
||||
|
||||
@@ -167,7 +169,11 @@ void LedgerAcquire::done()
|
||||
mLock.unlock();
|
||||
|
||||
if (mLedger)
|
||||
{
|
||||
if (mAccept)
|
||||
mLedger->setAccepted();
|
||||
theApp->getMasterLedger().storeLedger(mLedger);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < triggers.size(); ++i)
|
||||
triggers[i](shared_from_this());
|
||||
@@ -185,12 +191,12 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
if (mAborted || mComplete || mFailed)
|
||||
return;
|
||||
#ifdef LA_DEBUG
|
||||
if (peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
|
||||
else Log(lsTRACE) << "Trigger acquiring ledger " << mHash;
|
||||
if (peer) cLog(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
|
||||
else cLog(lsTRACE) << "Trigger acquiring ledger " << mHash;
|
||||
if (mComplete || mFailed)
|
||||
Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
cLog(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
else
|
||||
Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
cLog(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
#endif
|
||||
if (!mHaveBase)
|
||||
{
|
||||
@@ -204,7 +210,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
if (mHaveBase && !mHaveTransactions)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "need tx";
|
||||
cLog(lsTRACE) << "need tx";
|
||||
#endif
|
||||
assert(mLedger);
|
||||
if (mLedger->peekTransactionMap()->getHash().isZero())
|
||||
@@ -248,7 +254,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
if (mHaveBase && !mHaveState)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "need as";
|
||||
cLog(lsTRACE) << "need as";
|
||||
#endif
|
||||
assert(mLedger);
|
||||
if (mLedger->peekAccountStateMap()->getHash().isZero())
|
||||
@@ -326,18 +332,41 @@ void PeerSet::sendRequest(const ripple::TMGetLedger& tmGL)
|
||||
}
|
||||
}
|
||||
|
||||
int PeerSet::takePeerSetFrom(const PeerSet& s)
|
||||
{
|
||||
int ret = 0;
|
||||
mPeers.clear();
|
||||
mPeers.reserve(s.mPeers.size());
|
||||
BOOST_FOREACH(const boost::weak_ptr<Peer>& p, s.mPeers)
|
||||
if (p.lock())
|
||||
{
|
||||
mPeers.push_back(p);
|
||||
++ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PeerSet::getPeerCount() const
|
||||
{
|
||||
int ret = 0;
|
||||
BOOST_FOREACH(const boost::weak_ptr<Peer>& p, mPeers)
|
||||
if (p.lock())
|
||||
++ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool LedgerAcquire::takeBase(const std::string& data)
|
||||
{ // Return value: true=normal, false=bad data
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "got base acquiring ledger " << mHash;
|
||||
cLog(lsTRACE) << "got base acquiring ledger " << mHash;
|
||||
#endif
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
if (mHaveBase) return true;
|
||||
mLedger = boost::make_shared<Ledger>(data);
|
||||
if (mLedger->getHash() != mHash)
|
||||
{
|
||||
Log(lsWARNING) << "Acquire hash mismatch";
|
||||
Log(lsWARNING) << mLedger->getHash() << "!=" << mHash;
|
||||
cLog(lsWARNING) << "Acquire hash mismatch";
|
||||
cLog(lsWARNING) << mLedger->getHash() << "!=" << mHash;
|
||||
mLedger = Ledger::pointer();
|
||||
#ifdef TRUST_NETWORK
|
||||
assert(false);
|
||||
@@ -396,7 +425,7 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
const std::list< std::vector<unsigned char> >& data)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "got ASdata acquiring ledger " << mHash;
|
||||
cLog(lsTRACE) << "got ASdata acquiring ledger " << mHash;
|
||||
#endif
|
||||
if (!mHaveBase) return false;
|
||||
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
|
||||
@@ -479,7 +508,7 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash)
|
||||
bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << "got data for acquiring ledger ";
|
||||
cLog(lsTRACE) << "got data for acquiring ledger ";
|
||||
#endif
|
||||
uint256 hash;
|
||||
if (packet.ledgerhash().size() != 32)
|
||||
@@ -489,7 +518,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
}
|
||||
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
|
||||
#ifdef LA_DEBUG
|
||||
Log(lsTRACE) << hash;
|
||||
cLog(lsTRACE) << hash;
|
||||
#endif
|
||||
|
||||
LedgerAcquire::pointer ledger = find(hash);
|
||||
@@ -509,7 +538,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
}
|
||||
if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata())))
|
||||
{
|
||||
Log(lsWARNING) << "Included ASbase invalid";
|
||||
cLog(lsWARNING) << "Included ASbase invalid";
|
||||
}
|
||||
if (packet.nodes().size() == 2)
|
||||
{
|
||||
@@ -517,7 +546,9 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
return true;
|
||||
}
|
||||
if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata())))
|
||||
Log(lsWARNING) << "Invcluded TXbase invalid";
|
||||
{
|
||||
cLog(lsWARNING) << "Invcluded TXbase invalid";
|
||||
}
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
}
|
||||
@@ -548,4 +579,108 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LedgerAcquireSet::LedgerAcquireSet(Ledger::ref targetLedger, Ledger::ref currentLedger) :
|
||||
mTargetLedger(targetLedger), mCheckComplete(true)
|
||||
{
|
||||
updateCurrentLedger(currentLedger);
|
||||
}
|
||||
|
||||
void LedgerAcquireSet::updateCurrentLedger(Ledger::pointer currentLedger)
|
||||
{ // We have 'currentLedger', what do we need to acquire next
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
if ((currentLedger->getHash() == mTargetLedger->getHash()) ||
|
||||
(currentLedger->getParentHash() == mTargetLedger->getHash()))
|
||||
{ // We have completed acquiring the set
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
while (mTargetLedger->getLedgerSeq() >= currentLedger->getLedgerSeq())
|
||||
{ // We need to back up our target
|
||||
mTargetLedger = theApp->getMasterLedger().getLedgerByHash(mTargetLedger->getParentHash());
|
||||
if (!mTargetLedger)
|
||||
{
|
||||
cLog(lsWARNING) << "LedgerAcquireSet encountered a non-present target ledger";
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Ledger::pointer nextLedger =
|
||||
theApp->getMasterLedger().getLedgerByHash(currentLedger->getParentHash());
|
||||
|
||||
if (nextLedger && mCheckComplete && !nextLedger->walkLedger())
|
||||
{
|
||||
cLog(lsINFO) << "Acquire set has encountered a ledger that is missing nodes";
|
||||
nextLedger = Ledger::pointer();
|
||||
}
|
||||
|
||||
if (!nextLedger)
|
||||
{ // the next ledger we need is missing or missing nodes
|
||||
LedgerAcquire::pointer nextAcquire =
|
||||
theApp->getMasterLedgerAcquire().findCreate(currentLedger->getParentHash());
|
||||
nextAcquire->setAccept();
|
||||
if (mCurrentLedger)
|
||||
nextAcquire->takePeerSetFrom(*mCurrentLedger);
|
||||
mCurrentLedger = nextAcquire;
|
||||
if (!mCurrentLedger->getPeerCount())
|
||||
addPeers();
|
||||
mCurrentLedger->addOnComplete(boost::bind(
|
||||
&LedgerAcquireSet::onComplete, boost::weak_ptr<LedgerAcquireSet>(shared_from_this()), _1));
|
||||
return;
|
||||
}
|
||||
currentLedger = nextLedger;
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerAcquireSet::onComplete(boost::weak_ptr<LedgerAcquireSet> set, LedgerAcquire::pointer acquired)
|
||||
{
|
||||
LedgerAcquireSet::pointer lSet = set.lock();
|
||||
if (!lSet)
|
||||
return;
|
||||
|
||||
if (acquired->isComplete())
|
||||
{
|
||||
Ledger::pointer ledger = acquired->getLedger();
|
||||
ledger->setAccepted();
|
||||
lSet->updateCurrentLedger(ledger);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsWARNING) << "Bailing on LedgerAcquireSet due to failure to acquire a ledger";
|
||||
lSet->done();
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerAcquireSet::done()
|
||||
{
|
||||
theApp->getMasterLedgerAcquire().killSet(*this);
|
||||
}
|
||||
|
||||
void LedgerAcquireSet::addPeers()
|
||||
{
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
const uint256& hash = mCurrentLedger->getHash();
|
||||
|
||||
bool found = false;
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
{
|
||||
if (peer->hasLedger(hash))
|
||||
{
|
||||
found = true;
|
||||
mCurrentLedger->peerHas(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
mCurrentLedger->peerHas(peer);
|
||||
}
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
void badPeer(Peer::ref);
|
||||
void resetTimer();
|
||||
|
||||
int takePeerSetFrom(const PeerSet& s);
|
||||
int getPeerCount() const;
|
||||
|
||||
protected:
|
||||
virtual void newPeer(Peer::ref) = 0;
|
||||
virtual void onTimer(void) = 0;
|
||||
@@ -65,7 +68,7 @@ public:
|
||||
|
||||
protected:
|
||||
Ledger::pointer mLedger;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled, mAccept;
|
||||
|
||||
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
|
||||
|
||||
@@ -85,6 +88,7 @@ public:
|
||||
bool isTransComplete() const { return mHaveTransactions; }
|
||||
Ledger::pointer getLedger() { return mLedger; }
|
||||
void abort() { mAborted = true; }
|
||||
void setAccept() { mAccept = true; }
|
||||
|
||||
void addOnComplete(boost::function<void (LedgerAcquire::pointer)>);
|
||||
|
||||
@@ -97,11 +101,32 @@ public:
|
||||
bool tryLocal();
|
||||
};
|
||||
|
||||
class LedgerAcquireSet : public boost::enable_shared_from_this<LedgerAcquireSet>
|
||||
{ // a sequence of ledgers we are retreiving
|
||||
public:
|
||||
typedef boost::shared_ptr<LedgerAcquireSet> pointer;
|
||||
|
||||
protected:
|
||||
Ledger::pointer mTargetLedger; // ledger we have and want to get back to
|
||||
LedgerAcquire::pointer mCurrentLedger; // ledger we are acquiring
|
||||
bool mCheckComplete; // should we check to make sure we have all nodes
|
||||
|
||||
void updateCurrentLedger(Ledger::pointer currentLedger);
|
||||
void done();
|
||||
void addPeers();
|
||||
|
||||
static void onComplete(boost::weak_ptr<LedgerAcquireSet>, LedgerAcquire::pointer);
|
||||
|
||||
public:
|
||||
LedgerAcquireSet(Ledger::ref targetLedger, Ledger::ref currentLedger);
|
||||
};
|
||||
|
||||
class LedgerAcquireMaster
|
||||
{
|
||||
protected:
|
||||
boost::mutex mLock;
|
||||
std::map<uint256, LedgerAcquire::pointer> mLedgers;
|
||||
LedgerAcquireSet::pointer mAcquireSet;
|
||||
|
||||
public:
|
||||
LedgerAcquireMaster() { ; }
|
||||
@@ -111,6 +136,11 @@ public:
|
||||
bool hasLedger(const uint256& ledgerHash);
|
||||
void dropLedger(const uint256& ledgerHash);
|
||||
bool gotLedgerData(ripple::TMLedgerData& packet, Peer::ref);
|
||||
|
||||
void killSet(const LedgerAcquireSet&)
|
||||
{ mAcquireSet = LedgerAcquireSet::pointer(); }
|
||||
void makeSet(Ledger::ref target, Ledger::ref current)
|
||||
{ mAcquireSet = boost::make_shared<LedgerAcquireSet>(boost::ref(target), boost::ref(current)); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -993,7 +993,7 @@ void LedgerConsensus::playbackProposals()
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerConsensus::applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn,
|
||||
void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTransaction::ref txn,
|
||||
Ledger::ref ledger, CanonicalTXSet& failedTransactions, bool openLedger)
|
||||
{
|
||||
TransactionEngineParams parms = openLedger ? tapOPEN_LEDGER : tapNONE;
|
||||
|
||||
@@ -134,7 +134,7 @@ protected:
|
||||
void sendHaveTxSet(const uint256& set, bool direct);
|
||||
void applyTransactions(SHAMap::ref transactionSet, Ledger::ref targetLedger,
|
||||
Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr);
|
||||
void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn,
|
||||
void applyTransaction(TransactionEngine& engine, SerializedTransaction::ref txn,
|
||||
Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr);
|
||||
|
||||
uint32 roundCloseTime(uint32 closeTime);
|
||||
|
||||
@@ -65,8 +65,8 @@ public:
|
||||
void init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID);
|
||||
void clear();
|
||||
|
||||
Ledger::pointer& getLedger() { return mLedger; }
|
||||
const Ledger::pointer& getLedgerRef() const { return mLedger; }
|
||||
Ledger::pointer& getLedger() { return mLedger; }
|
||||
Ledger::ref getLedgerRef() const { return mLedger; }
|
||||
|
||||
// basic entry functions
|
||||
SLE::pointer getEntry(const uint256& index, LedgerEntryAction&);
|
||||
|
||||
@@ -26,7 +26,7 @@ void LedgerHistory::addLedger(Ledger::pointer ledger)
|
||||
mLedgersByHash.canonicalize(ledger->getHash(), ledger, true);
|
||||
}
|
||||
|
||||
void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
|
||||
void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger, bool fromConsensus)
|
||||
{
|
||||
assert(ledger && ledger->isAccepted());
|
||||
uint256 h(ledger->getHash());
|
||||
@@ -37,7 +37,7 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
|
||||
assert(ledger->isImmutable());
|
||||
mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger));
|
||||
|
||||
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger));
|
||||
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger, fromConsensus));
|
||||
thread.detach();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
LedgerHistory();
|
||||
|
||||
void addLedger(Ledger::pointer ledger);
|
||||
void addAcceptedLedger(Ledger::pointer ledger);
|
||||
void addAcceptedLedger(Ledger::pointer ledger, bool fromConsensus);
|
||||
|
||||
Ledger::pointer getLedgerBySeq(uint32 index);
|
||||
Ledger::pointer getLedgerByHash(const uint256& hash);
|
||||
|
||||
@@ -32,6 +32,8 @@ void LedgerMaster::pushLedger(Ledger::ref newLedger)
|
||||
mFinalizedLedger = mCurrentLedger;
|
||||
mCurrentLedger = newLedger;
|
||||
mEngine.setLedger(newLedger);
|
||||
if (mLastFullLedger && (newLedger->getParentHash() == mLastFullLedger->getHash()))
|
||||
mLastFullLedger = newLedger;
|
||||
}
|
||||
|
||||
void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL)
|
||||
@@ -43,7 +45,9 @@ void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL)
|
||||
{
|
||||
assert(newLCL->isClosed());
|
||||
assert(newLCL->isImmutable());
|
||||
mLedgerHistory.addAcceptedLedger(newLCL);
|
||||
mLedgerHistory.addAcceptedLedger(newLCL, false);
|
||||
if (mLastFullLedger && (newLCL->getParentHash() == mLastFullLedger->getHash()))
|
||||
mLastFullLedger = newLCL;
|
||||
Log(lsINFO) << "StashAccepted: " << newLCL->getHash();
|
||||
}
|
||||
|
||||
@@ -68,6 +72,8 @@ void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current)
|
||||
void LedgerMaster::storeLedger(Ledger::ref ledger)
|
||||
{
|
||||
mLedgerHistory.addLedger(ledger);
|
||||
if (ledger->isAccepted())
|
||||
mLedgerHistory.addAcceptedLedger(ledger, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ class LedgerMaster
|
||||
|
||||
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
|
||||
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
|
||||
Ledger::pointer mLastFullLedger; // We have history to this point
|
||||
|
||||
LedgerHistory mLedgerHistory;
|
||||
|
||||
@@ -49,6 +50,11 @@ public:
|
||||
void pushLedger(Ledger::ref newLCL, Ledger::ref newOL);
|
||||
void storeLedger(Ledger::ref);
|
||||
|
||||
void setLastFullLedger(Ledger::ref ledger)
|
||||
{
|
||||
mLastFullLedger = ledger;
|
||||
}
|
||||
|
||||
void switchLedgers(Ledger::ref lastClosed, Ledger::ref newCurrent);
|
||||
|
||||
Ledger::pointer closeLedger();
|
||||
|
||||
@@ -496,7 +496,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
|
||||
|
||||
ValidationCount& ourVC = ledgers[closedLedger];
|
||||
|
||||
if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING))
|
||||
if (mMode >= omTRACKING)
|
||||
{
|
||||
++ourVC.nodesUsing;
|
||||
uint160 ourAddress = theApp->getWallet().getNodePublic().getNodeID();
|
||||
@@ -638,7 +638,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo
|
||||
theApp->getConnectionPool().relayMessage(NULL, packet);
|
||||
}
|
||||
|
||||
int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger)
|
||||
int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::ref closingLedger)
|
||||
{
|
||||
cLog(lsINFO) << "Consensus time for ledger " << closingLedger->getLedgerSeq();
|
||||
cLog(lsINFO) << " LCL is " << closingLedger->getParentHash();
|
||||
@@ -864,7 +864,7 @@ std::vector<NewcoinAddress>
|
||||
|
||||
bool NetworkOPs::recvValidation(const SerializedValidation::pointer& val)
|
||||
{
|
||||
cLog(lsINFO) << "recvValidation " << val->getLedgerHash();
|
||||
cLog(lsDEBUG) << "recvValidation " << val->getLedgerHash();
|
||||
return theApp->getValidations().addValidation(val);
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
void checkState(const boost::system::error_code& result);
|
||||
void switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus); // Used for the "jump" case
|
||||
bool checkLastClosedLedger(const std::vector<Peer::pointer>&, uint256& networkClosed);
|
||||
int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger);
|
||||
int beginConsensus(const uint256& networkClosed, Ledger::ref closingLedger);
|
||||
void endConsensus(bool correctLCL);
|
||||
void setStandAlone() { setMode(omFULL); }
|
||||
void setStateTimer();
|
||||
|
||||
31
src/Peer.cpp
31
src/Peer.cpp
@@ -1053,25 +1053,22 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
ledger->addRaw(nData);
|
||||
reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
|
||||
|
||||
if (packet.nodeids().size() != 0)
|
||||
{ // new-style root request
|
||||
cLog(lsINFO) << "Ledger root w/map roots request";
|
||||
SHAMap::pointer map = ledger->peekAccountStateMap();
|
||||
if (map && map->getHash().isNonZero())
|
||||
{ // return account state root node if possible
|
||||
Serializer rootNode(768);
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
cLog(lsINFO) << "Ledger root w/map roots request";
|
||||
SHAMap::pointer map = ledger->peekAccountStateMap();
|
||||
if (map && map->getHash().isNonZero())
|
||||
{ // return account state root node if possible
|
||||
Serializer rootNode(768);
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
{
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
if (ledger->getTransHash().isNonZero())
|
||||
{
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
if (ledger->getTransHash().isNonZero())
|
||||
map = ledger->peekTransactionMap();
|
||||
if (map && map->getHash().isNonZero())
|
||||
{
|
||||
map = ledger->peekTransactionMap();
|
||||
if (map && map->getHash().isNonZero())
|
||||
{
|
||||
rootNode.resize(0);
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
}
|
||||
rootNode.resize(0);
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ std::size_t hash_value(const aciSource& asValue)
|
||||
// <-- uOfferIndex : 0=end of list.
|
||||
TER RippleCalc::calcNodeAdvance(
|
||||
const unsigned int uIndex, // 0 < uIndex < uLast
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality,
|
||||
const bool bReverse)
|
||||
{
|
||||
@@ -267,7 +267,7 @@ TER RippleCalc::calcNodeAdvance(
|
||||
// Continue process till request is satisified while we the rate does not increase past the initial rate.
|
||||
TER RippleCalc::calcNodeDeliverRev(
|
||||
const unsigned int uIndex, // 0 < uIndex < uLast
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uOutAccountID, // --> Output owner's account.
|
||||
const STAmount& saOutReq, // --> Funds wanted.
|
||||
@@ -459,7 +459,7 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
// Goal: Make progress consuming the offer.
|
||||
TER RippleCalc::calcNodeDeliverFwd(
|
||||
const unsigned int uIndex, // 0 < uIndex < uLast
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uInAccountID, // --> Input owner's account.
|
||||
const STAmount& saInFunds, // --> Funds available for delivery and fees.
|
||||
@@ -610,7 +610,7 @@ TER RippleCalc::calcNodeDeliverFwd(
|
||||
// Called to drive from the last offer node in a chain.
|
||||
TER RippleCalc::calcNodeOfferRev(
|
||||
const unsigned int uIndex, // 0 < uIndex < uLast
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality)
|
||||
{
|
||||
TER terResult;
|
||||
@@ -650,7 +650,7 @@ TER RippleCalc::calcNodeOfferRev(
|
||||
// - Deliver is set without transfer fees.
|
||||
TER RippleCalc::calcNodeOfferFwd(
|
||||
const unsigned int uIndex, // 0 < uIndex < uLast
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality
|
||||
)
|
||||
{
|
||||
@@ -789,7 +789,7 @@ void RippleCalc::calcNodeRipple(
|
||||
|
||||
// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur...
|
||||
// <-- tesSUCCESS or tepPATH_DRY
|
||||
TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality)
|
||||
TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
|
||||
{
|
||||
TER terResult = tesSUCCESS;
|
||||
const unsigned int uLast = pspCur->vpnNodes.size() - 1;
|
||||
@@ -1100,7 +1100,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p
|
||||
// - Output to next node is computed as input minus quality or transfer fee.
|
||||
TER RippleCalc::calcNodeAccountFwd(
|
||||
const unsigned int uIndex, // 0 <= uIndex <= uLast
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality)
|
||||
{
|
||||
TER terResult = tesSUCCESS;
|
||||
@@ -1362,7 +1362,7 @@ TER RippleCalc::calcNodeAccountFwd(
|
||||
}
|
||||
|
||||
// Return true, iff lhs has less priority than rhs.
|
||||
bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs)
|
||||
bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs)
|
||||
{
|
||||
if (lhs->uQuality != rhs->uQuality)
|
||||
return lhs->uQuality > rhs->uQuality; // Bigger is worse.
|
||||
@@ -1713,7 +1713,7 @@ Json::Value PathState::getJson() const
|
||||
return jvPathState;
|
||||
}
|
||||
|
||||
TER RippleCalc::calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality)
|
||||
TER RippleCalc::calcNodeFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
|
||||
{
|
||||
const PaymentNode& pnCur = pspCur->vpnNodes[uIndex];
|
||||
const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount);
|
||||
@@ -1743,7 +1743,7 @@ TER RippleCalc::calcNodeFwd(const unsigned int uIndex, const PathState::pointer&
|
||||
// --> [all]saWanted.mCurrency
|
||||
// --> [all]saAccount
|
||||
// <-> [0]saWanted.mAmount : --> limit, <-- actual
|
||||
TER RippleCalc::calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality)
|
||||
TER RippleCalc::calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
|
||||
{
|
||||
PaymentNode& pnCur = pspCur->vpnNodes[uIndex];
|
||||
const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount);
|
||||
@@ -1785,7 +1785,7 @@ TER RippleCalc::calcNodeRev(const unsigned int uIndex, const PathState::pointer&
|
||||
// Calculate the next increment of a path.
|
||||
// The increment is what can satisfy a portion or all of the requested output at the best quality.
|
||||
// <-- pspCur->uQuality
|
||||
void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent)
|
||||
void RippleCalc::pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent)
|
||||
{
|
||||
// The next state is what is available in preference order.
|
||||
// This is calculated when referenced accounts changed.
|
||||
|
||||
@@ -65,13 +65,14 @@ extern std::size_t hash_value(const aciSource& asValue);
|
||||
class PathState
|
||||
{
|
||||
protected:
|
||||
const Ledger::pointer& mLedger;
|
||||
Ledger::ref mLedger;
|
||||
|
||||
TER pushNode(const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
TER pushImply(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<PathState> pointer;
|
||||
typedef boost::shared_ptr<PathState> pointer;
|
||||
typedef const boost::shared_ptr<PathState>& ref;
|
||||
|
||||
TER terStatus;
|
||||
std::vector<PaymentNode> vpnNodes;
|
||||
@@ -123,7 +124,7 @@ public:
|
||||
return boost::make_shared<PathState>(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax);
|
||||
}
|
||||
|
||||
static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs);
|
||||
static bool lessPriority(PathState::ref lhs, PathState::ref rhs);
|
||||
};
|
||||
|
||||
class RippleCalc
|
||||
@@ -139,18 +140,18 @@ public:
|
||||
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
|
||||
|
||||
PathState::pointer pathCreate(const STPath& spPath);
|
||||
void pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
|
||||
TER calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAdvance(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality, const bool bReverse);
|
||||
void pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
|
||||
TER calcNode(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAdvance(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality, const bool bReverse);
|
||||
TER calcNodeDeliverRev(
|
||||
const unsigned int uIndex,
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uOutAccountID,
|
||||
const STAmount& saOutReq,
|
||||
@@ -158,7 +159,7 @@ public:
|
||||
|
||||
TER calcNodeDeliverFwd(
|
||||
const unsigned int uIndex,
|
||||
const PathState::pointer& pspCur,
|
||||
PathState::ref pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uInAccountID,
|
||||
const STAmount& saInFunds,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
RippleLines::RippleLines(const uint160& accountID, Ledger::pointer ledger)
|
||||
RippleLines::RippleLines(const uint160& accountID, Ledger::ref ledger)
|
||||
{
|
||||
fillLines(accountID,ledger);
|
||||
fillLines(accountID, ledger);
|
||||
}
|
||||
|
||||
void RippleLines::printRippleLines()
|
||||
@@ -25,7 +25,7 @@ RippleLines::RippleLines(const uint160& accountID )
|
||||
fillLines(accountID,theApp->getMasterLedger().getCurrentLedger());
|
||||
}
|
||||
|
||||
void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger)
|
||||
void RippleLines::fillLines(const uint160& accountID, Ledger::ref ledger)
|
||||
{
|
||||
uint256 rootIndex = Ledger::getOwnerDirIndex(accountID);
|
||||
uint256 currentIndex = rootIndex;
|
||||
|
||||
@@ -9,12 +9,12 @@ It provides a vector so you to easily iterate through them
|
||||
class RippleLines
|
||||
{
|
||||
std::vector<RippleState::pointer> mLines;
|
||||
void fillLines(const uint160& accountID, Ledger::pointer ledger);
|
||||
void fillLines(const uint160& accountID, Ledger::ref ledger);
|
||||
public:
|
||||
|
||||
RippleLines(const uint160& accountID, Ledger::pointer ledger);
|
||||
RippleLines(const uint160& accountID, Ledger::ref ledger);
|
||||
RippleLines(const uint160& accountID ); // looks in the current ledger
|
||||
|
||||
std::vector<RippleState::pointer>& getLines(){ return(mLines); }
|
||||
std::vector<RippleState::pointer>& getLines() { return(mLines); }
|
||||
void printRippleLines();
|
||||
};
|
||||
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
bool hasItem() const { return !!mItem; }
|
||||
SHAMapItem::ref peekItem() { return mItem; }
|
||||
SHAMapItem::pointer getItem() const;
|
||||
bool setItem(const SHAMapItem::pointer& i, TNType type);
|
||||
bool setItem(SHAMapItem::ref i, TNType type);
|
||||
const uint256& getTag() const { return mItem->getTag(); }
|
||||
const std::vector<unsigned char>& peekData() { return mItem->peekData(); }
|
||||
std::vector<unsigned char> getData() const { return mItem->getData(); }
|
||||
|
||||
@@ -185,7 +185,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq) : SHAMapN
|
||||
memcpy(mHashes, node.mHashes, sizeof(mHashes));
|
||||
}
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, const SHAMapItem::pointer& item, TNType type, uint32 seq) :
|
||||
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::ref item, TNType type, uint32 seq) :
|
||||
SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true)
|
||||
{
|
||||
assert(item->peekData().size() >= 12);
|
||||
@@ -465,7 +465,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format)
|
||||
assert(false);
|
||||
}
|
||||
|
||||
bool SHAMapTreeNode::setItem(const SHAMapItem::pointer& i, TNType type)
|
||||
bool SHAMapTreeNode::setItem(SHAMapItem::ref i, TNType type)
|
||||
{
|
||||
uint256 hash = getNodeHash();
|
||||
mType = type;
|
||||
|
||||
@@ -164,7 +164,8 @@ bool STObject::setType(const std::vector<SOElement::ptr> &type)
|
||||
{
|
||||
if (elem->flags != SOE_OPTIONAL)
|
||||
{
|
||||
cLog(lsWARNING) << "setType !valid missing " << elem->e_field.fieldName;
|
||||
cLog(lsWARNING) << "setType( " << getFName().getName() << ") invalid missing "
|
||||
<< elem->e_field.fieldName;
|
||||
valid = false;
|
||||
}
|
||||
newData.push_back(makeNonPresentObject(elem->e_field));
|
||||
@@ -178,7 +179,8 @@ bool STObject::setType(const std::vector<SOElement::ptr> &type)
|
||||
{
|
||||
if (!t.getFName().isDiscardable())
|
||||
{
|
||||
cLog(lsWARNING) << "setType !valid leftover: " << t.getFName().getName();
|
||||
cLog(lsWARNING) << "setType( " << getFName().getName() << ") invalid leftover "
|
||||
<< t.getFName().getName();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
@@ -792,6 +794,42 @@ Json::Value STObject::getJson(int options) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool STObject::operator==(const STObject& obj) const
|
||||
{ // This is not particularly efficient, and only compares data elements with binary representations
|
||||
int matches = 0;
|
||||
BOOST_FOREACH(const SerializedType& t, mData)
|
||||
if ((t.getSType() != STI_NOTPRESENT) && t.getFName().isBinary())
|
||||
{ // each present field must have a matching field
|
||||
bool match = false;
|
||||
BOOST_FOREACH(const SerializedType& t2, obj.mData)
|
||||
if (t.getFName() == t2.getFName())
|
||||
{
|
||||
if (t2 != t)
|
||||
return false;
|
||||
match = true;
|
||||
++matches;
|
||||
break;
|
||||
}
|
||||
if (!match)
|
||||
{
|
||||
Log(lsTRACE) << "STObject::operator==: no match for " << t.getFName().getName();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int fields = 0;
|
||||
BOOST_FOREACH(const SerializedType& t2, obj.mData)
|
||||
if ((t2.getSType() != STI_NOTPRESENT) && t2.getFName().isBinary())
|
||||
++fields;
|
||||
|
||||
if (fields != matches)
|
||||
{
|
||||
Log(lsTRACE) << "STObject::operator==: " << fields << " fields, " << matches << " matches";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Json::Value STVector256::getJson(int options) const
|
||||
{
|
||||
Json::Value ret(Json::arrayValue);
|
||||
@@ -1246,7 +1284,6 @@ BOOST_AUTO_TEST_CASE( FieldManipulation_test )
|
||||
if (object1.getFieldVL(sfTestVL) != j) BOOST_FAIL("STObject error");
|
||||
if (object3.getFieldVL(sfTestVL) != j) BOOST_FAIL("STObject error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
@@ -148,6 +148,9 @@ public:
|
||||
{ return makeDefaultObject(STI_NOTPRESENT, name); }
|
||||
static std::auto_ptr<SerializedType> makeDefaultObject(SField::ref name)
|
||||
{ return makeDefaultObject(name.fieldType, name); }
|
||||
|
||||
bool operator==(const STObject& o) const;
|
||||
bool operator!=(const STObject& o) const { return ! (*this == o); }
|
||||
};
|
||||
|
||||
class STArray : public SerializedType
|
||||
|
||||
@@ -25,7 +25,6 @@ SerializedTransaction::SerializedTransaction(const STObject& object) : STObject(
|
||||
throw std::runtime_error("invalid transaction type");
|
||||
if (!setType(mFormat->elements))
|
||||
{
|
||||
assert(false);
|
||||
throw std::runtime_error("transaction not valid");
|
||||
}
|
||||
}
|
||||
@@ -203,8 +202,8 @@ BOOST_AUTO_TEST_CASE( STrans_test )
|
||||
NewcoinAddress seed;
|
||||
seed.setSeedRandom();
|
||||
NewcoinAddress generator = NewcoinAddress::createGeneratorPublic(seed);
|
||||
NewcoinAddress publicAcct = NewcoinAddress::createAccountPublic(generator, 1);
|
||||
NewcoinAddress privateAcct = NewcoinAddress::createAccountPrivate(generator, seed, 1);
|
||||
NewcoinAddress publicAcct = NewcoinAddress::createAccountPublic(generator, 1);
|
||||
NewcoinAddress privateAcct = NewcoinAddress::createAccountPrivate(generator, seed, 1);
|
||||
|
||||
SerializedTransaction j(ttCLAIM);
|
||||
j.setSourceAccount(publicAcct);
|
||||
@@ -224,10 +223,15 @@ BOOST_AUTO_TEST_CASE( STrans_test )
|
||||
Log(lsFATAL) << copy.getJson(0);
|
||||
BOOST_FAIL("Transaction fails serialize/deserialize test");
|
||||
}
|
||||
Log(lsINFO) << "ORIG: " << j.getJson(0);
|
||||
std::auto_ptr<STObject> new_obj = STObject::parseJson(j.getJson(0), sfGeneric);
|
||||
if (new_obj.get() == NULL) BOOST_FAIL("Unable to build object from json");
|
||||
Log(lsINFO) << "BUILT " << new_obj->getJson(0);
|
||||
|
||||
if (STObject(j) != *new_obj)
|
||||
{
|
||||
Log(lsINFO) << "ORIG: " << j.getJson(0);
|
||||
Log(lsINFO) << "BUILT " << new_obj->getJson(0);
|
||||
BOOST_FAIL("Built a different transaction");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
class SerializedTransaction : public STObject
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<SerializedTransaction> pointer;
|
||||
typedef boost::shared_ptr<SerializedTransaction> pointer;
|
||||
typedef const boost::shared_ptr<SerializedTransaction>& ref;
|
||||
|
||||
protected:
|
||||
TransactionType mType;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "SerializedTransaction.h"
|
||||
#include "Log.h"
|
||||
|
||||
Transaction::Transaction(const SerializedTransaction::pointer& sit, bool bValidate)
|
||||
Transaction::Transaction(SerializedTransaction::ref sit, bool bValidate)
|
||||
: mInLedger(0), mStatus(INVALID), mResult(temUNCERTAIN), mTransaction(sit)
|
||||
{
|
||||
try
|
||||
@@ -709,8 +709,8 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg
|
||||
for(it = inMap.begin(); it != inMap.end(); ++it)
|
||||
{
|
||||
const uint256& id = it->first;
|
||||
const SHAMapItem::pointer& first = it->second.first;
|
||||
const SHAMapItem::pointer& second = it->second.second;
|
||||
SHAMapItem::ref first = it->second.first;
|
||||
SHAMapItem::ref second = it->second.second;
|
||||
|
||||
Transaction::pointer firstTrans, secondTrans;
|
||||
if (!!first)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#ifndef __TRANSACTION__
|
||||
#define __TRANSACTION__
|
||||
|
||||
//
|
||||
// Notes: this code contains legacy constructored sharedXYZ and setXYZ. The intent is for these functions to go away. Transactions
|
||||
// should now be constructed in JSON with. Use STObject::parseJson to obtain a binary version.
|
||||
//
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
@@ -129,7 +134,7 @@ private:
|
||||
const std::vector<unsigned char>& vucSignature);
|
||||
|
||||
public:
|
||||
Transaction(const SerializedTransaction::pointer& st, bool bValidate);
|
||||
Transaction(SerializedTransaction::ref st, bool bValidate);
|
||||
|
||||
static Transaction::pointer sharedTransaction(const std::vector<unsigned char>&vucTransaction, bool bValidate);
|
||||
static Transaction::pointer transactionFromSQL(Database* db, bool bValidate);
|
||||
|
||||
@@ -31,7 +31,7 @@ Transaction::pointer TransactionMaster::fetch(const uint256& txnID, bool checkDi
|
||||
return txn;
|
||||
}
|
||||
|
||||
SerializedTransaction::pointer TransactionMaster::fetch(const SHAMapItem::pointer& item, bool checkDisk, uint32 uCommitLedger)
|
||||
SerializedTransaction::pointer TransactionMaster::fetch(SHAMapItem::ref item, bool checkDisk, uint32 uCommitLedger)
|
||||
{
|
||||
SerializedTransaction::pointer txn;
|
||||
Transaction::pointer iTx = theApp->getMasterTransaction().fetch(item->getTag(), false);
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
TransactionMaster();
|
||||
|
||||
Transaction::pointer fetch(const uint256&, bool checkDisk);
|
||||
SerializedTransaction::pointer fetch(const SHAMapItem::pointer& item, bool checkDisk, uint32 uCommitLedger);
|
||||
SerializedTransaction::pointer fetch(SHAMapItem::ref item, bool checkDisk, uint32 uCommitLedger);
|
||||
|
||||
// return value: true = we had the transaction already
|
||||
bool canonicalize(Transaction::pointer& txn, bool maybeNew);
|
||||
|
||||
@@ -1017,7 +1017,18 @@ void WSConnection::doSubmit(Json::Value& jvResult, const Json::Value& jvRequest)
|
||||
|
||||
sopTrans->setFieldVL(sfSigningPubKey, naAccountPublic.getAccountPublic());
|
||||
|
||||
SerializedTransaction::pointer stpTrans = boost::make_shared<SerializedTransaction>(*sopTrans);
|
||||
SerializedTransaction::pointer stpTrans;
|
||||
|
||||
try
|
||||
{
|
||||
stpTrans = boost::make_shared<SerializedTransaction>(*sopTrans);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
jvResult["error"] = "invalidTransaction";
|
||||
jvResult["error_exception"] = e.what();
|
||||
return;
|
||||
}
|
||||
|
||||
stpTrans->sign(naAccountPrivate);
|
||||
|
||||
|
||||
@@ -245,15 +245,20 @@ message TMGetLedger {
|
||||
optional uint32 requestCookie = 6;
|
||||
}
|
||||
|
||||
enum TMReplyError {
|
||||
reNO_LEDGER = 1; // We don't have the ledger you are asking about
|
||||
reNO_NODE = 2; // We don't have any of the nodes you are asking for
|
||||
}
|
||||
|
||||
message TMLedgerData {
|
||||
required bytes ledgerHash = 1;
|
||||
required uint32 ledgerSeq = 2;
|
||||
required TMLedgerInfoType type = 3;
|
||||
repeated TMLedgerNode nodes = 4;
|
||||
optional uint32 requestCookie = 5;
|
||||
optional TMReplyError error = 6;
|
||||
}
|
||||
|
||||
|
||||
message TMPing {
|
||||
enum pingType {
|
||||
PING = 0; // we want a reply
|
||||
|
||||
@@ -1,55 +1,95 @@
|
||||
var buster = require("buster");
|
||||
|
||||
var jsbn = require('../js/jsbn.js');
|
||||
var BigInteger = jsbn.BigInteger;
|
||||
var nbi = jsbn.nbi;
|
||||
|
||||
var amount = require("../js/amount.js");
|
||||
var Amount = require("../js/amount.js").Amount;
|
||||
var UInt160 = require("../js/amount.js").UInt160;
|
||||
|
||||
var config = require('./config.js');
|
||||
|
||||
buster.testCase("Amount", {
|
||||
"UInt160" : {
|
||||
"Parse 0" : function () {
|
||||
buster.assert.equals(0, amount.UInt160.from_json("0").value);
|
||||
buster.assert.equals(nbi(), UInt160.from_json("0").value);
|
||||
},
|
||||
"Parse 0 export" : function () {
|
||||
buster.assert.equals(amount.consts.hex_xns, amount.UInt160.from_json("0").to_json());
|
||||
buster.assert.equals(amount.consts.address_xns, UInt160.from_json("0").to_json());
|
||||
},
|
||||
"Parse 1" : function () {
|
||||
buster.assert.equals(new BigInteger([1]), UInt160.from_json("1").value);
|
||||
},
|
||||
"Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export" : function () {
|
||||
buster.assert.equals(amount.consts.address_xns, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrrhoLvTp").to_json());
|
||||
},
|
||||
"Parse rrrrrrrrrrrrrrrrrrrrBZbvji export" : function () {
|
||||
buster.assert.equals(amount.consts.address_one, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrBZbvji").to_json());
|
||||
},
|
||||
"Parse mtgox export" : function () {
|
||||
buster.assert.equals(config.accounts["mtgox"].account, UInt160.from_json("mtgox").to_json());
|
||||
},
|
||||
},
|
||||
"Amount" : {
|
||||
"Amount parsing" : {
|
||||
"Parse 800/USD/mtgox" : function () {
|
||||
buster.assert.equals("800/USD/"+config.accounts["mtgox"].account, Amount.from_json("800/USD/mtgox").to_text_full());
|
||||
},
|
||||
"Parse native 0" : function () {
|
||||
buster.assert.equals("0/XNS", amount.Amount.from_json("0").to_text_full());
|
||||
buster.assert.equals("0/XNS", Amount.from_json("0").to_text_full());
|
||||
},
|
||||
"Parse native 0.0" : function () {
|
||||
buster.assert.equals("0/XNS", amount.Amount.from_json("0.0").to_text_full());
|
||||
buster.assert.equals("0/XNS", Amount.from_json("0.0").to_text_full());
|
||||
},
|
||||
"Parse native -0" : function () {
|
||||
buster.assert.equals("0/XNS", amount.Amount.from_json("-0").to_text_full());
|
||||
buster.assert.equals("0/XNS", Amount.from_json("-0").to_text_full());
|
||||
},
|
||||
"Parse native -0.0" : function () {
|
||||
buster.assert.equals("0/XNS", amount.Amount.from_json("-0.0").to_text_full());
|
||||
buster.assert.equals("0/XNS", Amount.from_json("-0.0").to_text_full());
|
||||
},
|
||||
"Parse native 1000" : function () {
|
||||
buster.assert.equals("1000/XNS", amount.Amount.from_json("1000").to_text_full());
|
||||
buster.assert.equals("1000/XNS", Amount.from_json("1000").to_text_full());
|
||||
},
|
||||
"Parse native 12.3" : function () {
|
||||
buster.assert.equals("12300000/XNS", amount.Amount.from_json("12.3").to_text_full());
|
||||
buster.assert.equals("12300000/XNS", Amount.from_json("12.3").to_text_full());
|
||||
},
|
||||
"Parse native -12.3" : function () {
|
||||
buster.assert.equals("-12300000/XNS", amount.Amount.from_json("-12.3").to_text_full());
|
||||
buster.assert.equals("-12300000/XNS", Amount.from_json("-12.3").to_text_full());
|
||||
},
|
||||
"Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () {
|
||||
buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
},
|
||||
"Parse 12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () {
|
||||
buster.assert.equals("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
buster.assert.equals("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
},
|
||||
"Parse 12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () {
|
||||
buster.assert.equals("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
buster.assert.equals("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
},
|
||||
"Parse 1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () {
|
||||
buster.assert.equals("1.23/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
buster.assert.equals("1.23/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
},
|
||||
"Parse -0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () {
|
||||
buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("-0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
},
|
||||
"Parse -0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () {
|
||||
buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("-0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full());
|
||||
},
|
||||
},
|
||||
"Amount operations" : {
|
||||
"Negate native 123" : function () {
|
||||
buster.assert.equals("-123/XNS", Amount.from_json("123").negate().to_text_full());
|
||||
},
|
||||
"Negate native -123" : function () {
|
||||
buster.assert.equals("123/XNS", Amount.from_json("-123").negate().to_text_full());
|
||||
},
|
||||
"Negate non-native 123" : function () {
|
||||
buster.assert.equals("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").negate().to_text_full());
|
||||
},
|
||||
"Negate non-native -123" : function () {
|
||||
buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").negate().to_text_full());
|
||||
},
|
||||
"Clone non-native -123" : function () {
|
||||
buster.assert.equals("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").clone().to_text_full());
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,8 +11,8 @@ var testutils = require("./testutils.js");
|
||||
buster.testRunner.timeout = 5000;
|
||||
|
||||
buster.testCase("Offer tests", {
|
||||
'setUp' : testutils.test_setup,
|
||||
'tearDown' : testutils.test_teardown,
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
"offer create then cancel in one ledger" :
|
||||
function (done) {
|
||||
|
||||
@@ -14,8 +14,8 @@ var serverDelay = 1500; // XXX Not implemented.
|
||||
buster.testRunner.timeout = 5000;
|
||||
|
||||
buster.testCase("Remote functions", {
|
||||
'setUp' : testutils.test_setup,
|
||||
'tearDown' : testutils.test_teardown,
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
'request_ledger_current' :
|
||||
function (done) {
|
||||
|
||||
@@ -10,11 +10,11 @@ var testutils = require("./testutils.js");
|
||||
// How long to wait for server to start.
|
||||
var serverDelay = 1500;
|
||||
|
||||
buster.testRunner.timeout = 2000;
|
||||
buster.testRunner.timeout = 5000;
|
||||
|
||||
buster.testCase("Sending", {
|
||||
'setUp' : testutils.test_setup,
|
||||
'tearDown' : testutils.test_teardown,
|
||||
buster.testCase("// Sending", {
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
"send XNS to non-existant account without create." :
|
||||
function (done) {
|
||||
@@ -23,7 +23,7 @@ buster.testCase("Sending", {
|
||||
var got_proposed;
|
||||
|
||||
this.remote.transaction()
|
||||
.payment('root', 'alice', Amount.from_json("10000"))
|
||||
.payment('root', 'alice', "10000")
|
||||
.on('success', function (r) {
|
||||
// Transaction sent.
|
||||
|
||||
@@ -91,21 +91,19 @@ buster.testCase("Sending", {
|
||||
"credit_limit" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
//this.remote.set_trace();
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
this.what = "Create account.";
|
||||
self.what = "Create accounts.";
|
||||
|
||||
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
|
||||
},
|
||||
function (callback) {
|
||||
this.what = "Check a non-existant credit limit.";
|
||||
self.what = "Check a non-existant credit limit.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT')
|
||||
.on('ripple_state', function (m) {
|
||||
buster.assert(false);
|
||||
|
||||
callback();
|
||||
callback(true);
|
||||
})
|
||||
.on('error', function(m) {
|
||||
// console.log("error: %s", JSON.stringify(m));
|
||||
@@ -117,7 +115,8 @@ buster.testCase("Sending", {
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
this.what = "Create a credit limit.";
|
||||
self.what = "Create a credit limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "alice", "800/USD/mtgox", callback);
|
||||
},
|
||||
function (callback) {
|
||||
@@ -138,7 +137,7 @@ buster.testCase("Sending", {
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
this.what = "Modify a credit limit.";
|
||||
self.what = "Modify a credit limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "alice", "700/USD/mtgox", callback);
|
||||
},
|
||||
@@ -155,12 +154,12 @@ buster.testCase("Sending", {
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
this.what = "Zero a credit limit.";
|
||||
self.what = "Zero a credit limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "alice", "0/USD/mtgox", callback);
|
||||
},
|
||||
function (callback) {
|
||||
this.what = "Make sure still exists.";
|
||||
self.what = "Make sure still exists.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT')
|
||||
.on('ripple_state', function (m) {
|
||||
@@ -173,17 +172,285 @@ buster.testCase("Sending", {
|
||||
})
|
||||
.request();
|
||||
},
|
||||
// Check in both owner books.
|
||||
// Set limit on other side.
|
||||
// Set negative limit.
|
||||
//function (callback) {
|
||||
// testutils.credit_limit(self.remote, "alice", "-1/USD/mtgox", callback);
|
||||
//},
|
||||
function (callback) {
|
||||
self.remote.transaction()
|
||||
.ripple_line_set("alice", "-1/USD/mtgox")
|
||||
.on('proposed', function (m) {
|
||||
buster.assert.equals('temBAD_AMOUNT', m.result);
|
||||
|
||||
// After a malformed transaction, need to recover correct sequence.
|
||||
self.remote.set_account_seq("alice", self.remote.account_seq("alice")-1);
|
||||
callback('temBAD_AMOUNT' !== m.result);
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
// TODO Check in both owner books.
|
||||
function (callback) {
|
||||
self.what = "Set another limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "alice", "600/USD/bob", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set limit on other side.";
|
||||
|
||||
testutils.credit_limit(self.remote, "bob", "500/USD/alice", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Check ripple_line's state from alice's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
.on('ripple_state', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
|
||||
buster.assert(m.account_balance.equals("0/USD/alice"));
|
||||
buster.assert(m.account_limit.equals("600/USD/alice"));
|
||||
buster.assert(m.issuer_balance.equals("0/USD/bob"));
|
||||
buster.assert(m.issuer_limit.equals("500/USD/bob"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Check ripple_line's state from bob's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("bob", "alice", "USD", 'CURRENT')
|
||||
.on('ripple_state', function (m) {
|
||||
buster.assert(m.account_balance.equals("0/USD/bob"));
|
||||
buster.assert(m.account_limit.equals("500/USD/bob"));
|
||||
buster.assert(m.issuer_balance.equals("0/USD/alice"));
|
||||
buster.assert(m.issuer_limit.equals("600/USD/alice"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
], function (error) {
|
||||
buster.refute(error, this.what);
|
||||
buster.refute(error, self.what);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// XXX In the future add ledger_accept after partial retry is implemented in the server.
|
||||
buster.testCase("Sending future", {
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
"direct ripple" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
self.remote.set_trace();
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
self.what = "Create accounts.";
|
||||
|
||||
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob"], callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set alice's limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "alice", "600/USD/bob", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set bob's limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "bob", "700/USD/alice", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set alice send bob partial with alice as issuer.";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment('alice', 'bob', "24/USD/alice")
|
||||
.on('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.once('final', function (m) {
|
||||
buster.assert(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify balance.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", '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());
|
||||
|
||||
buster.assert(m.account_balance.equals("-24/USD/alice"));
|
||||
buster.assert(m.issuer_balance.equals("24/USD/bob"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set alice send bob more with bob as issuer.";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment('alice', 'bob', "33/USD/bob")
|
||||
.once('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.once('final', function (m) {
|
||||
buster.assert(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify balance from bob's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("bob", "alice", "USD", 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
buster.assert(m.account_balance.equals("57/USD/bob"));
|
||||
buster.assert(m.issuer_balance.equals("-57/USD/alice"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Bob send back more than sent.";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment('bob', 'alice', "90/USD/bob")
|
||||
.once('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.once('final', function (m) {
|
||||
buster.assert(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify balance from alice's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
buster.assert(m.account_balance.equals("33/USD/alice"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Alice send to limit.";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment('alice', 'bob', "733/USD/bob")
|
||||
.once('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.once('final', function (m) {
|
||||
buster.assert(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify balance from alice's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
buster.assert(m.account_balance.equals("-700/USD/alice"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Bob send to limit.";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment('bob', 'alice', "1300/USD/bob")
|
||||
.once('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.once('final', function (m) {
|
||||
buster.assert(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify balance from alice's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
buster.assert(m.account_balance.equals("600/USD/alice"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
function (callback) {
|
||||
// If this gets applied out of order, it could stop the big payment.
|
||||
self.what = "Bob send past limit.";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment('bob', 'alice', "1/USD/bob")
|
||||
.once('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tepPATH_PARTIAL');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify balance from alice's pov.";
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
buster.assert(m.account_balance.equals("600/USD/alice"));
|
||||
|
||||
callback();
|
||||
})
|
||||
.request();
|
||||
},
|
||||
// function (callback) {
|
||||
// // Make sure all is good after canonical ordering.
|
||||
// self.what = "Close the ledger and check balance.";
|
||||
//
|
||||
// self.remote
|
||||
// .once('ledger_closed', function (ledger_closed, ledger_closed_index) {
|
||||
// // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed);
|
||||
// callback();
|
||||
// })
|
||||
// .ledger_accept();
|
||||
// },
|
||||
// function (callback) {
|
||||
// self.what = "Verify balance from alice's pov.";
|
||||
//
|
||||
// self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
// .once('ripple_state', function (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());
|
||||
//
|
||||
// buster.assert(m.account_balance.equals("600/USD/alice"));
|
||||
//
|
||||
// callback();
|
||||
// })
|
||||
// .request();
|
||||
// },
|
||||
], function (error) {
|
||||
buster.refute(error, self.what);
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
// Ripple without credit path.
|
||||
// Ripple with one-way credit path.
|
||||
});
|
||||
|
||||
// vim:sw=2:sts=2:ts=8
|
||||
|
||||
@@ -6,29 +6,87 @@ var Server = require("./server.js").Server;
|
||||
|
||||
var config = require("./config.js");
|
||||
|
||||
var test_setup = function (done, host) {
|
||||
var self = this;
|
||||
var host = host || config.server_default;
|
||||
/**
|
||||
* Helper called by test cases to generate a setUp routine.
|
||||
*
|
||||
* By default you would call this without options, but it is useful to
|
||||
* be able to plug options in during development for quick and easy
|
||||
* debugging.
|
||||
*
|
||||
* @example
|
||||
* buster.testCase("Foobar", {
|
||||
* setUp: testutils.build_setup({verbose: true}),
|
||||
* // ...
|
||||
* });
|
||||
*
|
||||
* @param opts {Object} These options allow quick-and-dirty test-specific
|
||||
* customizations of your test environment.
|
||||
* @param opts.verbose {Bool} Enable all debug output (then cover your ears
|
||||
* and run)
|
||||
* @param opts.verbose_ws {Bool} Enable tracing in the Remote class. Prints
|
||||
* websocket traffic.
|
||||
* @param opts.verbose_server {Bool} Set the -v option when running rippled.
|
||||
* @param opts.no_server {Bool} Don't auto-run rippled.
|
||||
* @param host {String} Identifier for the host configuration to be used.
|
||||
*/
|
||||
var build_setup = function (opts, host) {
|
||||
opts = opts || {};
|
||||
|
||||
this.store = this.store || {};
|
||||
// Normalize options
|
||||
if (opts.verbose) {
|
||||
opts.verbose_ws = true;
|
||||
opts.verbose_server = true;
|
||||
};
|
||||
|
||||
var data = this.store[host] = this.store[host] || {};
|
||||
return function (done) {
|
||||
var self = this;
|
||||
|
||||
data.server = Server.from_config(host).on('started', function () {
|
||||
self.remote = data.remote = Remote.from_config(host).once('ledger_closed', done).connect();
|
||||
}).start();
|
||||
host = host || config.server_default;
|
||||
|
||||
this.store = this.store || {};
|
||||
|
||||
var data = this.store[host] = this.store[host] || {};
|
||||
|
||||
data.opts = opts;
|
||||
|
||||
async.series([
|
||||
function runServerStep(callback) {
|
||||
if (opts.no_server) return callback();
|
||||
|
||||
data.server = Server.from_config(host, !!opts.verbose_server).on('started', callback).start();
|
||||
},
|
||||
function connectWebsocketStep(callback) {
|
||||
self.remote = data.remote = Remote.from_config(host, !!opts.verbose_ws).once('ledger_closed', callback).connect();
|
||||
}
|
||||
], done);
|
||||
};
|
||||
};
|
||||
|
||||
var test_teardown = function (done, host) {
|
||||
var host = host || config.server_default;
|
||||
/**
|
||||
* Generate tearDown routine.
|
||||
*
|
||||
* @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];
|
||||
var data = this.store[host];
|
||||
var opts = data.opts;
|
||||
|
||||
data.remote
|
||||
.on('disconnected', function () {
|
||||
data.server.on('stopped', done).stop();
|
||||
})
|
||||
.connect(false);
|
||||
async.series([
|
||||
function disconnectWebsocketStep(callback) {
|
||||
data.remote
|
||||
.on('disconnected', callback)
|
||||
.connect(false);
|
||||
},
|
||||
function stopServerStep(callback) {
|
||||
if (opts.no_server) return callback();
|
||||
|
||||
data.server.on('stopped', callback).stop();
|
||||
}
|
||||
], done);
|
||||
};
|
||||
};
|
||||
|
||||
var create_accounts = function (remote, src, amount, accounts, callback) {
|
||||
@@ -60,8 +118,6 @@ var credit_limit = function (remote, src, amount, callback) {
|
||||
.on('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
|
||||
// buster.assert.equals(m.result, 'tesSUCCESS');
|
||||
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.on('error', function (m) {
|
||||
@@ -72,9 +128,9 @@ var credit_limit = function (remote, src, amount, callback) {
|
||||
.submit();
|
||||
};
|
||||
|
||||
exports.create_accounts = create_accounts;
|
||||
exports.credit_limit = credit_limit;
|
||||
exports.test_setup = test_setup;
|
||||
exports.test_teardown = test_teardown;
|
||||
exports.create_accounts = create_accounts;
|
||||
exports.credit_limit = credit_limit;
|
||||
exports.build_setup = build_setup;
|
||||
exports.build_teardown = build_teardown;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8
|
||||
|
||||
Reference in New Issue
Block a user