Merge branch 'master' into ut

Conflicts:
	js/utils.js
	test/server.js
This commit is contained in:
Arthur Britto
2012-09-28 12:34:27 -07:00
51 changed files with 1358 additions and 647 deletions

205
js/remote.js Normal file
View File

@@ -0,0 +1,205 @@
// Remote access to a server.
// - We never send binary data.
// - We use the W3C interface for node and browser compatibility:
// http://www.w3.org/TR/websockets/#the-websocket-interface
//
// YYY Will later provide a network access which use multiple instances of this.
// YYY A better model might be to allow requesting a target state: keep connected or not.
//
var util = require('util');
var WebSocket = require('ws');
// --> trusted: truthy, if remote is trusted
var Remote = function(trusted, websocket_ip, websocket_port, trace) {
this.trusted = trusted;
this.websocket_ip = websocket_ip;
this.websocket_port = websocket_port;
this.id = 0;
this.trace = trace;
};
var remoteConfig = function(config, server, trace) {
var serverConfig = config.servers[server];
return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace);
};
Remote.method('connect_helper', function() {
var self = this;
if (this.trace)
console.log("remote: connect: %s", this.url);
this.ws = new WebSocket(this.url);
var ws = this.ws;
ws.response = {};
ws.onopen = function() {
if (this.trace)
console.log("remote: onopen: %s", ws.readyState);
ws.onclose = undefined;
ws.onerror = undefined;
self.done(ws.readyState);
};
ws.onerror = function() {
if (this.trace)
console.log("remote: onerror: %s", ws.readyState);
ws.onclose = undefined;
if (self.expire) {
if (this.trace)
console.log("remote: was expired");
self.done(ws.readyState);
}
else
{
// Delay and retry.
setTimeout(function() {
if (this.trace)
console.log("remote: retry");
self.connect_helper();
}, 50); // Retry rate 50ms.
}
};
// Covers failure to open.
ws.onclose = function() {
if (this.trace)
console.log("remote: onclose: %s", ws.readyState);
ws.onerror = undefined;
self.done(ws.readyState);
};
// Node's ws module doesn't pass arguments to onmessage.
ws.on('message', function(json, flags) {
var message = JSON.parse(json);
// console.log("message: %s", json);
if (message.type !== 'response') {
console.log("unexpected message: %s", json);
} else {
var done = ws.response[message.id];
if (done) {
done(message);
} else {
console.log("unexpected message id: %s", json);
}
}
});
});
// Target state is connectted.
// done(readyState):
// --> readyState: OPEN, CLOSED
Remote.method('connect', function(done, timeout) {
var self = this;
this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port);
this.done = done;
if (timeout) {
if (this.trace)
console.log("remote: expire: false");
this.expire = false;
setTimeout(function () {
if (this.trace)
console.log("remote: expire: timeout");
self.expire = true;
}, timeout);
}
else {
if (this.trace)
console.log("remote: expire: false");
this.expire = true;
}
this.connect_helper();
});
// Target stated is disconnected.
Remote.method('disconnect', function(done) {
var ws = this.ws;
ws.onclose = function() {
if (this.trace)
console.log("remote: onclose: %s", ws.readyState);
done(ws.readyState);
};
ws.close();
});
// Send a command. The comman should lack the id.
// <-> command: what to send, consumed.
Remote.method('request', function(command, done) {
this.id += 1; // Advance id.
var ws = this.ws;
command.id = this.id;
ws.response[command.id] = done;
if (this.trace)
console.log("remote: send: %s", JSON.stringify(command));
ws.send(JSON.stringify(command));
});
Remote.method('ledger_closed', function(done) {
assert(this.trusted); // If not trusted, need to check proof.
this.request({ 'command' : 'ledger_closed' }, done);
});
// Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning).
// Only for use by unit tests.
Remote.method('ledger_current', function(done) {
this.request({ 'command' : 'ledger_current' }, done);
});
// <-> params:
// --> ledger : optional
// --> ledger_index : optional
Remote.method('ledger_entry', function(params, done) {
assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol.
params.command = 'ledger_entry';
this.request(params, done);
});
// Submit a json transaction.
// done(value)
// <-> value: { 'status', status, 'result' : result, ... }
// done may be called up to 3 times.
Remote.method('submit', function(json, done) {
// this.request(..., function() {
// });
});
exports.Remote = Remote;
exports.remoteConfig = remoteConfig;
// vim:ts=4

View File

@@ -1,10 +1,17 @@
// YYY Should probably have two versions: node vs browser
var fs = require("fs");
var path = require("path");
Function.prototype.method = function(name,func) {
this.prototype[name] = func;
return this;
};
var filterErr = function(code, done) {
return function(e) {
done(e && e.code === code ? undefined : e);
done(e.code !== code ? e : undefined);
};
};

View File

@@ -119,7 +119,7 @@
1
[debug_logfile]
debug.log
log/debug.log
[sntp_servers]
time.windows.com

View File

@@ -12,6 +12,7 @@
uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1));
// --> sCurrency: "", "XNS", or three letter ISO code.
bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency)
{
bool bSuccess = true;
@@ -359,19 +360,16 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name)
if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset))
throw std::runtime_error("invalid currency value");
sapResult = new STAmount(name, uCurrencyID, value, offset, isNegative);
sapResult = new STAmount(name, uCurrencyID, uIssuerID, value, offset, isNegative);
}
else
{
if (offset != 512)
throw std::runtime_error("invalid currency value");
sapResult = new STAmount(name, uCurrencyID);
sapResult = new STAmount(name, uCurrencyID, uIssuerID);
}
if (sapResult)
sapResult->setIssuer(uIssuerID);
return sapResult;
}
@@ -522,7 +520,7 @@ STAmount& STAmount::operator-=(const STAmount& a)
STAmount STAmount::operator-(void) const
{
if (mValue == 0) return *this;
return STAmount(name, mCurrency, mValue, mOffset, mIsNative, !mIsNegative);
return STAmount(name, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative);
}
STAmount& STAmount::operator=(uint64 v)
@@ -620,9 +618,9 @@ STAmount operator+(const STAmount& v1, const STAmount& v2)
int64 fv = vv1 + vv2;
if (fv >= 0)
return STAmount(v1.name, v1.mCurrency, fv, ov1, false);
return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false);
else
return STAmount(v1.name, v1.mCurrency, -fv, ov1, true);
return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true);
}
STAmount operator-(const STAmount& v1, const STAmount& v2)
@@ -652,9 +650,9 @@ STAmount operator-(const STAmount& v1, const STAmount& v2)
int64 fv = vv1 - vv2;
if (fv >= 0)
return STAmount(v1.name, v1.mCurrency, fv, ov1, false);
return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false);
else
return STAmount(v1.name, v1.mCurrency, -fv, ov1, true);
return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true);
}
STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID)

View File

@@ -36,7 +36,7 @@ DatabaseCon::~DatabaseCon()
}
Application::Application() :
mUNL(mIOService),
mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService),
mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300),
mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
mHashNodeDB(NULL), mNetNodeDB(NULL),
@@ -51,10 +51,10 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount
void Application::stop()
{
mAuxService.stop();
mIOService.stop();
mHashedObjectStore.bulkWrite();
mValidations.flush();
mAuxService.stop();
Log(lsINFO) << "Stopped: " << mIOService.stopped();
}

View File

@@ -40,6 +40,7 @@ public:
class Application
{
boost::asio::io_service mIOService, mAuxService;
boost::asio::io_service::work mIOWork, mAuxWork;
Wallet mWallet;
UniqueNodeList mUNL;

View File

@@ -112,7 +112,8 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params)
"If the file does not exist, create it with owner-readable-only file permissions.");
// Connect to localhost
std::cout << "Connecting to port:" << theConfig.RPC_PORT << std::endl;
std::cout << "Connecting to: " << theConfig.RPC_IP << ":" << theConfig.RPC_PORT << std::endl;
boost::asio::ip::tcp::endpoint
endpoint(boost::asio::ip::address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT);
boost::asio::ip::tcp::iostream stream;

View File

@@ -1,50 +0,0 @@
#include "Conversion.h"
#include "base58.h"
using namespace std;
#if 0
uint160 protobufTo160(const std::string& buf)
{
uint160 ret;
// TODO:
return(ret);
}
uint256 protobufTo256(const std::string& hash)
{
uint256 ret;
// TODO:
return(ret);
}
uint160 humanTo160(const std::string& buf)
{
vector<unsigned char> retVec;
DecodeBase58(buf,retVec);
uint160 ret;
memcpy(ret.begin(), &retVec[0], ret.GetSerializeSize());
return(ret);
}
bool humanToPK(const std::string& buf,std::vector<unsigned char>& retVec)
{
return(DecodeBase58(buf,retVec));
}
bool u160ToHuman(uint160& buf, std::string& retStr)
{
retStr=EncodeBase58(buf.begin(),buf.end());
return(true);
}
#endif
base_uint256 uint160::to256() const
{
uint256 m;
memcpy(m.begin(), begin(), size());
return m;
}

View File

@@ -1,11 +0,0 @@
#include "uint256.h"
#include <string>
extern uint160 protobufTo160(const std::string& buf);
extern uint256 protobufTo256(const std::string& hash);
extern uint160 humanTo160(const std::string& buf);
extern bool humanToPK(const std::string& buf,std::vector<unsigned char>& retVec);
extern bool u160ToHuman(uint160& buf, std::string& retStr);

13
src/FieldNames.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "FieldNames.h"
#define FIELD(name, type, index) { sf##name, #name, STI_##type, index },
#define TYPE(name, type, index)
FieldName FieldNames[]=
{
#include "SerializeProto.h"
};
#undef FIELD
#undef TYPE

16
src/FieldNames.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __FIELDNAMES__
#define __FIELDNAMES__
#include "SerializedTypes.h"
#include "SerializedObject.h"
struct FieldName
{
SOE_Field field;
const char *fieldName;
SerializedTypeID fieldType;
int fieldValue;
int fieldID;
};
#endif

View File

@@ -13,7 +13,6 @@
#include "../obj/src/newcoin.pb.h"
#include "PackedMessage.h"
#include "Config.h"
#include "Conversion.h"
#include "BitcoinUtil.h"
#include "Wallet.h"
#include "LedgerTiming.h"
@@ -21,7 +20,7 @@
#include "Log.h"
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0),
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1),
mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
@@ -505,7 +504,6 @@ void Ledger::addJson(Json::Value& ret, int options)
{
SerializerIterator sit(item->peekSerializer());
Serializer sTxn(sit.getVL());
Serializer sMeta(sit.getVL());
SerializerIterator tsit(sTxn);
SerializedTransaction txn(tsit);

View File

@@ -358,6 +358,18 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger)
SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false);
uint256 txSet = initialSet->getHash();
Log(lsINFO) << "initial position " << txSet;
mapComplete(txSet, initialSet, false);
if (mValidating)
mOurPosition = boost::make_shared<LedgerProposal>
(mValSeed, initialLedger.getParentHash(), txSet, mCloseTime);
else
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger.getParentHash(), txSet, mCloseTime);
BOOST_FOREACH(u256_lct_pair& it, mDisputes)
{
it.second->setOurVote(initialLedger.hasTransaction(it.first));
}
// if any peers have taken a contrary position, process disputes
boost::unordered_set<uint256> found;
@@ -365,19 +377,13 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger)
{
uint256 set = it.second->getCurrentHash();
if (found.insert(set).second)
{ // OPTIMIZEME: Don't process the same set more than once
{
boost::unordered_map<uint256, SHAMap::pointer>::iterator iit = mAcquired.find(set);
if (iit != mAcquired.end())
createDisputes(initialSet, iit->second);
}
}
if (mValidating)
mOurPosition = boost::make_shared<LedgerProposal>
(mValSeed, initialLedger.getParentHash(), txSet, mCloseTime);
else
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger.getParentHash(), txSet, mCloseTime);
mapComplete(txSet, initialSet, false);
if (mProposing)
propose();
}
@@ -389,16 +395,17 @@ void LedgerConsensus::createDisputes(SHAMap::ref m1, SHAMap::ref m2)
for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos)
{ // create disputed transactions (from the ledger that has them)
if (pos->second.first)
{
{ // transaction is in first map
assert(!pos->second.second);
addDisputedTransaction(pos->first, pos->second.first->peekData());
}
else if (pos->second.second)
{
{ // transaction is in second map
assert(!pos->second.first);
addDisputedTransaction(pos->first, pos->second.second->peekData());
}
else assert(false);
else // No other disagreement over a transaction should be possible
assert(false);
}
}
@@ -417,7 +424,10 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq
assert(hash == map->getHash());
if (mAcquired.find(hash) != mAcquired.end())
{
mAcquiring.erase(hash);
return; // we already have this map
}
if (mOurPosition && (!mOurPosition->isBowOut()) && (hash != mOurPosition->getCurrentHash()))
{ // this could create disputed transactions
@@ -799,19 +809,20 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
{
Log(lsTRACE) << "Transaction " << txID << " is disputed";
boost::unordered_map<uint256, LCTransaction::pointer>::iterator it = mDisputes.find(txID);
if (it != mDisputes.end()) return;
if (it != mDisputes.end())
return;
bool ourPosition = false;
bool ourVote = false;
if (mOurPosition)
{
boost::unordered_map<uint256, SHAMap::pointer>::iterator mit = mAcquired.find(mOurPosition->getCurrentHash());
if (mit != mAcquired.end())
ourPosition = mit->second->hasItem(txID);
ourVote = mit->second->hasItem(txID);
else
assert(false); // We don't have our own position?
}
LCTransaction::pointer txn = boost::make_shared<LCTransaction>(txID, tx, ourPosition);
LCTransaction::pointer txn = boost::make_shared<LCTransaction>(txID, tx, ourVote);
mDisputes[txID] = txn;
BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions)
@@ -821,6 +832,16 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
if (cit != mAcquired.end() && cit->second)
txn->setVote(pit.first, cit->second->hasItem(txID));
}
if (!ourVote && theApp->isNew(txID))
{
newcoin::TMTransaction msg;
msg.set_rawtransaction(&(tx.front()), tx.size());
msg.set_status(newcoin::tsNEW);
msg.set_receivetimestamp(theApp->getOPs().getNetworkTimeNC());
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(msg, newcoin::mtTRANSACTION);
theApp->getConnectionPool().relayMessage(NULL, packet);
}
}
bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition)

View File

@@ -62,6 +62,7 @@ public:
const uint256& getTransactionID() const { return mTransactionID; }
bool getOurVote() const { return mOurVote; }
Serializer& peekTransaction() { return transaction; }
void setOurVote(bool o) { mOurVote = o; }
void setVote(const uint160& peer, bool votesYes);
void unVote(const uint160& peer);

View File

@@ -291,7 +291,7 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger,
}
bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger,
bool LedgerEntrySet::threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
{
Log(lsTRACE) << "Thread to " << threadTo.getAccountID();
@@ -301,32 +301,36 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddres
assert(false);
return false;
}
return threadTx(metaNode, sle, ledger, newMods);
return threadTx(sle, ledger, newMods);
}
bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
bool LedgerEntrySet::threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods)
{ // node = the node that was modified/deleted/created
// threadTo = the node that needs to know
uint256 prevTxID;
uint32 prevLgrID;
if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID))
return false;
if (metaNode.thread(prevTxID, prevLgrID))
if (mSet.getAffectedNode(threadTo->getIndex(), TMNModifiedNode, false).thread(prevTxID, prevLgrID))
return true;
assert(false);
return false;
}
bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods)
{ // thread new or modified node to owner or owners
if (node->hasOneOwner()) // thread to owner's account
return threadTx(metaNode, node->getOwner(), ledger, newMods);
else if (node->hasTwoOwners()) // thread to owner's accounts
{
Log(lsTRACE) << "Thread to single owner";
return threadTx(node->getOwner(), ledger, newMods);
}
else if (node->hasTwoOwners()) // thread to owner's accounts]
{
Log(lsTRACE) << "Thread to two owners";
return
threadTx(metaNode, node->getFirstOwner(), ledger, newMods) ||
threadTx(metaNode, node->getSecondOwner(), ledger, newMods);
threadTx(node->getFirstOwner(), ledger, newMods) &&
threadTx(node->getSecondOwner(), ledger, newMods);
}
else
return false;
}
@@ -345,14 +349,17 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
switch (it->second.mAction)
{
case taaMODIFY:
Log(lsTRACE) << "Modified Node " << it->first;
nType = TMNModifiedNode;
break;
case taaDELETE:
Log(lsTRACE) << "Deleted Node " << it->first;
nType = TMNDeletedNode;
break;
case taaCREATE:
Log(lsTRACE) << "Created Node " << it->first;
nType = TMNCreatedNode;
break;
@@ -369,12 +376,12 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
continue;
SLE::pointer curNode = it->second.mEntry;
TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType);
TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType, true);
if (nType == TMNDeletedNode)
{
assert(origNode);
threadOwners(metaNode, origNode, mLedger, newMod);
threadOwners(origNode, mLedger, newMod);
if (origNode->getIFieldPresent(sfAmount))
{ // node has an amount, covers ripple state nodes
@@ -408,13 +415,16 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
if (nType == TMNCreatedNode) // if created, thread to owner(s)
{
assert(!origNode);
threadOwners(metaNode, curNode, mLedger, newMod);
threadOwners(curNode, mLedger, newMod);
}
if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode))
{
if (curNode->isThreadedType()) // always thread to self
threadTx(metaNode, curNode, mLedger, newMod);
{
Log(lsTRACE) << "Thread to self";
threadTx(curNode, mLedger, newMod);
}
}
if (nType == TMNModifiedNode)
@@ -934,21 +944,16 @@ STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160&
SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID));
saAmount = sleAccount->getIValueFieldAmount(sfBalance);
Log(lsINFO) << "accountHolds: stamps: " << saAmount.getText();
}
else
{
saAmount = rippleHolds(uAccountID, uCurrencyID, uIssuerID);
Log(lsINFO) << "accountHolds: "
<< saAmount.getFullText()
<< " : "
<< STAmount::createHumanCurrency(uCurrencyID)
<< "/"
<< NewcoinAddress::createHumanAccountID(uIssuerID);
}
Log(lsINFO) << boost::str(boost::format("accountHolds: uAccountID=%s saAmount=%s")
% NewcoinAddress::createHumanAccountID(uAccountID)
% saAmount.getFullText());
return saAmount;
}
@@ -961,30 +966,22 @@ STAmount LedgerEntrySet::accountFunds(const uint160& uAccountID, const STAmount&
{
STAmount saFunds;
Log(lsINFO) << "accountFunds: uAccountID="
<< NewcoinAddress::createHumanAccountID(uAccountID);
Log(lsINFO) << "accountFunds: saDefault.isNative()=" << saDefault.isNative();
Log(lsINFO) << "accountFunds: saDefault.getIssuer()="
<< NewcoinAddress::createHumanAccountID(saDefault.getIssuer());
if (!saDefault.isNative() && saDefault.getIssuer() == uAccountID)
{
saFunds = saDefault;
Log(lsINFO) << "accountFunds: offer funds: ripple self-funded: " << saFunds.getText();
Log(lsINFO) << boost::str(boost::format("accountFunds: uAccountID=%s saDefault=%s SELF-FUNDED")
% NewcoinAddress::createHumanAccountID(uAccountID)
% saDefault.getFullText());
}
else
{
saFunds = accountHolds(uAccountID, saDefault.getCurrency(), saDefault.getIssuer());
Log(lsINFO) << "accountFunds: offer funds: uAccountID ="
<< NewcoinAddress::createHumanAccountID(uAccountID)
<< " : "
<< saFunds.getText()
<< "/"
<< saDefault.getHumanCurrency()
<< "/"
<< NewcoinAddress::createHumanAccountID(saDefault.getIssuer());
Log(lsINFO) << boost::str(boost::format("accountFunds: uAccountID=%s saDefault=%s saFunds=%s")
% NewcoinAddress::createHumanAccountID(uAccountID)
% saDefault.getFullText()
% saFunds.getFullText());
}
return saFunds;

View File

@@ -42,14 +42,12 @@ protected:
SLE::pointer getForMod(const uint256& node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger,
bool threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
public:

View File

@@ -20,7 +20,6 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(Domain), STI_VL, SOE_IFFLAG, 32 },
{ S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 },
{ S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Contract", ltCONTRACT, {
@@ -37,7 +36,6 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "DirectoryNode", ltDIR_NODE, {
@@ -45,20 +43,17 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 },
{ S_FIELD(IndexNext), STI_UINT64, SOE_IFFLAG, 1 },
{ S_FIELD(IndexPrevious), STI_UINT64, SOE_IFFLAG, 2 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "GeneratorMap", ltGENERATOR_MAP, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Nickname", ltNICKNAME, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Offer", ltOFFER, {
@@ -73,7 +68,6 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 },
{ S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "RippleState", ltRIPPLE_STATE, {
@@ -89,7 +83,6 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(HighQualityOut), STI_UINT32, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ NULL, ltINVALID }

View File

@@ -5,7 +5,6 @@
#include "Application.h"
#include "NewcoinAddress.h"
#include "Conversion.h"
#include "Log.h"
uint32 LedgerMaster::getCurrentLedgerIndex()

View File

@@ -66,10 +66,15 @@ public:
Ledger::pointer getLedgerByHash(const uint256& hash)
{
if (!hash)
return mCurrentLedger;
if (mCurrentLedger && (mCurrentLedger->getHash() == hash))
return mCurrentLedger;
if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash))
return mFinalizedLedger;
return mLedgerHistory.getLedgerByHash(hash);
}

View File

@@ -10,6 +10,8 @@ boost::recursive_mutex Log::sLock;
LogSeverity Log::sMinSeverity = lsINFO;
std::ofstream* Log::outStream = NULL;
boost::filesystem::path *Log::pathToLog = NULL;
uint32 Log::logRotateCounter = 0;
Log::~Log()
{
@@ -31,6 +33,48 @@ Log::~Log()
(*outStream) << logMsg << std::endl;
}
std::string Log::rotateLog(void)
{
boost::recursive_mutex::scoped_lock sl(sLock);
boost::filesystem::path abs_path;
std::string abs_path_str;
uint32 failsafe = 0;
std::string abs_new_path_str;
do {
std::string s;
std::stringstream out;
failsafe++;
if (failsafe == std::numeric_limits<uint32>::max()) {
return "unable to create new log file; too many log files!";
}
abs_path = boost::filesystem::absolute("");
abs_path /= *pathToLog;
abs_path_str = abs_path.parent_path().string();
out << logRotateCounter;
s = out.str();
abs_new_path_str = abs_path_str + "/" + s + + "_" + pathToLog->filename().string();
logRotateCounter++;
} while (boost::filesystem::exists(boost::filesystem::path(abs_new_path_str)));
outStream->close();
boost::filesystem::rename(abs_path, boost::filesystem::path(abs_new_path_str));
setLogFile(*pathToLog);
return abs_new_path_str;
}
void Log::setMinSeverity(LogSeverity s)
{
boost::recursive_mutex::scoped_lock sl(sLock);
@@ -52,4 +96,6 @@ void Log::setLogFile(boost::filesystem::path path)
outStream = newStream;
if (outStream)
Log(lsINFO) << "Starting up";
pathToLog = new boost::filesystem::path(path);
}

View File

@@ -9,6 +9,9 @@
// Ensure that we don't get value.h without writer.h
#include "../json/json.h"
#include "types.h"
#include <limits>
enum LogSeverity
{
lsTRACE = 0,
@@ -33,6 +36,9 @@ protected:
mutable std::ostringstream oss;
LogSeverity mSeverity;
static boost::filesystem::path *pathToLog;
static uint32 logRotateCounter;
public:
Log(LogSeverity s) : mSeverity(s)
{ ; }
@@ -51,6 +57,7 @@ public:
static void setMinSeverity(LogSeverity);
static void setLogFile(boost::filesystem::path);
static std::string rotateLog(void);
};
#endif

View File

@@ -67,6 +67,13 @@ void NetworkOPs::closeTimeOffset(int offset)
Log(lsINFO) << "Close time offset now " << mCloseTimeOffset;
}
uint32 NetworkOPs::getLedgerID(const uint256& hash)
{
Ledger::ref lrLedger = mLedgerMaster->getLedgerByHash(hash);
return lrLedger ? lrLedger->getLedgerSeq() : 0;
}
uint32 NetworkOPs::getCurrentLedgerID()
{
return mLedgerMaster->getCurrentLedger()->getLedgerSeq();

View File

@@ -96,6 +96,7 @@ public:
uint32 getValidationTimeNC();
void closeTimeOffset(int);
boost::posix_time::ptime getNetworkTimePT();
uint32 getLedgerID(const uint256& hash);
uint32 getCurrentLedgerID();
OperatingMode getOperatingMode() { return mMode; }
inline bool available() {
@@ -103,13 +104,14 @@ public:
return mMode >= omTRACKING;
}
Ledger::pointer getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); }
Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); }
Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); }
uint256 getClosedLedger()
{ return mLedgerMaster->getClosedLedger()->getHash(); }
// FIXME: This function is basically useless since the hash is constantly changing and the ledger
// is ephemeral and mutable.
uint256 getCurrentLedger()
{ return mLedgerMaster->getCurrentLedger()->getHash(); }
SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); }
//
// Transaction operations
@@ -150,7 +152,6 @@ public:
Json::Value getOwnerInfo(const uint256& uLedger, const NewcoinAddress& naAccount);
Json::Value getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount);
// raw object operations
bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger);
bool findRawTransaction(const uint256& transactionHash, std::vector<unsigned char>& rawTransaction);

View File

@@ -73,6 +73,9 @@ public:
bool setAccountID(const std::string& strAccountID);
void setAccountID(const uint160& hash160In);
static NewcoinAddress createAccountID(const std::string& strAccountID)
{ NewcoinAddress na; na.setAccountID(strAccountID); return na; }
static NewcoinAddress createAccountID(const uint160& uiAccountID);
static std::string createHumanAccountID(const uint160& uiAccountID)

View File

@@ -12,7 +12,6 @@
#include "Peer.h"
#include "Config.h"
#include "Application.h"
#include "Conversion.h"
#include "SerializedTransaction.h"
#include "utils.h"
#include "Log.h"

View File

@@ -6,7 +6,6 @@
#include "Application.h"
#include "RPC.h"
#include "Wallet.h"
#include "Conversion.h"
#include "NewcoinAddress.h"
#include "AccountState.h"
#include "NicknameState.h"
@@ -14,6 +13,8 @@
#include "Log.h"
#include "RippleLines.h"
#include "Pathfinder.h"
#include <iostream>
#include <boost/bind.hpp>
@@ -422,7 +423,6 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value &params)
{
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -438,7 +438,7 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
if (!obj.empty())
@@ -476,7 +476,6 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value &params)
{
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -492,7 +491,7 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
if (!obj.empty())
@@ -569,12 +568,11 @@ Json::Value RPCServer::doAccountInfo(const Json::Value &params)
ret["accepted"] = jAccepted;
uint256 uCurrent = mNetOps->getCurrentLedger();
Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex);
Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex);
if (jCurrent.empty())
{
AccountState::pointer asCurrent = mNetOps->getAccountState(uCurrent, naAccount);
AccountState::pointer asCurrent = mNetOps->getAccountState(uint256(0), naAccount);
if (asCurrent)
asCurrent->addJson(jCurrent);
@@ -598,7 +596,6 @@ Json::Value RPCServer::doAccountInfo(const Json::Value &params)
Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) {
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
NewcoinAddress naMessagePubKey;
if (!naSeed.setSeedGeneric(params[0u].asString()))
@@ -619,7 +616,7 @@ Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) {
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
std::vector<unsigned char> vucDomain;
@@ -659,7 +656,6 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value &params)
{
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -675,7 +671,7 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
if (!obj.empty())
@@ -717,7 +713,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value &params)
{
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -733,7 +728,7 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
if (!obj.empty())
@@ -773,7 +768,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value &params)
Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) {
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -789,7 +783,7 @@ Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) {
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
std::vector<unsigned char> vucDomain;
@@ -921,8 +915,6 @@ Json::Value RPCServer::doDataStore(const Json::Value& params)
// Note: Nicknames are not automatically looked up by commands as they are advisory and can be changed.
Json::Value RPCServer::doNicknameInfo(const Json::Value& params)
{
uint256 uLedger = mNetOps->getCurrentLedger();
std::string strNickname = params[0u].asString();
boost::trim(strNickname);
@@ -931,7 +923,7 @@ Json::Value RPCServer::doNicknameInfo(const Json::Value& params)
return RPCError(rpcNICKNAME_MALFORMED);
}
NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname);
NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname);
if (!nsSrc)
{
return RPCError(rpcNICKNAME_MISSING);
@@ -951,7 +943,6 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params)
{
NewcoinAddress naSrcAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -979,7 +970,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params)
}
STAmount saFee;
NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname);
NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname);
if (!nsSrc)
{
@@ -1002,7 +993,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, saFee, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -1068,7 +1059,7 @@ Json::Value RPCServer::doOfferCreate(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -1114,7 +1105,7 @@ Json::Value RPCServer::doOfferCancel(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -1154,10 +1145,9 @@ Json::Value RPCServer::doOwnerInfo(const Json::Value& params)
ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted;
uint256 uCurrent = mNetOps->getCurrentLedger();
Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex);
Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex);
ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uCurrent, naAccount) : jCurrent;
ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uint256(0), naAccount) : jCurrent;
return ret;
}
@@ -1168,7 +1158,6 @@ Json::Value RPCServer::doPasswordFund(const Json::Value &params)
NewcoinAddress naSrcAccountID;
NewcoinAddress naDstAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -1188,7 +1177,7 @@ Json::Value RPCServer::doPasswordFund(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -1462,7 +1451,7 @@ Json::Value RPCServer::doRipple(const Json::Value &params)
bLimit = params.size() != iArg ? params[iArg].asString() == "limit" : false;
bAverage = params.size() != iArg ? params[iArg].asString() == "average" : false;
if (!bPartial && !bFull)
if (!bLimit && !bAverage)
{
return RPCError(rpcINVALID_PARAMS);
}
@@ -1494,8 +1483,7 @@ Json::Value RPCServer::doRipple(const Json::Value &params)
return RPCError(rpcDST_AMT_MALFORMED);
}
uint256 uLedger = mNetOps->getCurrentLedger();
AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID);
AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID);
STAmount saFee = theConfig.FEE_DEFAULT;
NewcoinAddress naVerifyGenerator;
@@ -1503,7 +1491,7 @@ Json::Value RPCServer::doRipple(const Json::Value &params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, saFee, asSrc, naVerifyGenerator);
if (!obj.empty())
@@ -1556,7 +1544,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
NewcoinAddress naSrcAccountID;
NewcoinAddress naDstAccountID;
STAmount saLimitAmount;
uint256 uLedger = mNetOps->getCurrentLedger();
bool bLimitAmount = true;
bool bQualityIn = params.size() >= 6;
bool bQualityOut = params.size() >= 7;
@@ -1594,7 +1581,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -1627,7 +1614,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
Json::Value RPCServer::doRippleLinesGet(const Json::Value &params)
{
// uint256 uAccepted = mNetOps->getClosedLedger();
uint256 uCurrent = mNetOps->getCurrentLedger();
std::string strIdent = params[0u].asString();
bool bIndex;
@@ -1637,7 +1623,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value &params)
Json::Value ret;
ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex);
ret = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex);
if (!ret.empty())
return ret;
@@ -1649,7 +1635,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value &params)
if (bIndex)
ret["index"] = iIndex;
AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount);
AccountState::pointer as = mNetOps->getAccountState(uint256(0), naAccount);
if (as)
{
Json::Value jsonLines(Json::arrayValue);
@@ -1739,8 +1725,7 @@ Json::Value RPCServer::doSend(const Json::Value& params)
}
else
{
uint256 uLedger = mNetOps->getCurrentLedger();
AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID);
AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID);
bool bCreate = !asDst;
STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT;
@@ -1749,7 +1734,7 @@ Json::Value RPCServer::doSend(const Json::Value& params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, saFee, asSrc, naVerifyGenerator);
// Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s")
@@ -1794,7 +1779,17 @@ Json::Value RPCServer::doSend(const Json::Value& params)
// Destination exists, ordinary send.
STPathSet spsPaths;
/*
uint160 srcCurrencyID;
bool ret_b;
ret_b = false;
STAmount::currencyFromString(srcCurrencyID, sSrcCurrency);
Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount);
ret_b = pf.findPaths(5, 1, spsPaths);
// TODO: Nope; the above can't be right
*/
trans = Transaction::sharedPayment(
naAccountPublic, naAccountPrivate,
naSrcAccountID,
@@ -2081,7 +2076,6 @@ Json::Value RPCServer::accounts(const uint256& uLedger, const NewcoinAddress& na
Json::Value RPCServer::doWalletAccounts(const Json::Value& params)
{
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -2091,17 +2085,17 @@ Json::Value RPCServer::doWalletAccounts(const Json::Value& params)
// Try the seed as a master seed.
NewcoinAddress naMasterGenerator = NewcoinAddress::createGeneratorPublic(naSeed);
Json::Value jsonAccounts = accounts(uLedger, naMasterGenerator);
Json::Value jsonAccounts = accounts(uint256(0), naMasterGenerator);
if (jsonAccounts.empty())
{
// No account via seed as master, try seed a regular.
Json::Value ret = getMasterGenerator(uLedger, naSeed, naMasterGenerator);
Json::Value ret = getMasterGenerator(uint256(0), naSeed, naMasterGenerator);
if (!ret.empty())
return ret;
ret["accounts"] = accounts(uLedger, naMasterGenerator);
ret["accounts"] = accounts(uint256(0), naMasterGenerator);
return ret;
}
@@ -2124,7 +2118,6 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params)
NewcoinAddress naSrcAccountID;
STAmount saAmount;
std::string sDstCurrency;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naRegularSeed.setSeedGeneric(params[0u].asString()))
{
@@ -2151,7 +2144,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -2177,7 +2170,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params)
++iIndex;
naNewAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
asNew = mNetOps->getAccountState(uLedger, naNewAccountPublic);
asNew = mNetOps->getAccountState(uint256(0), naNewAccountPublic);
if (!asNew)
bAgain = false;
} while (bAgain);
@@ -2312,7 +2305,6 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params)
NewcoinAddress naSrcAccountID;
NewcoinAddress naDstAccountID;
NewcoinAddress naSeed;
uint256 uLedger = mNetOps->getCurrentLedger();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
@@ -2326,7 +2318,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params)
{
return RPCError(rpcDST_ACT_MALFORMED);
}
else if (mNetOps->getAccountState(uLedger, naDstAccountID))
else if (mNetOps->getAccountState(uint256(0), naDstAccountID))
{
return RPCError(rpcACT_EXISTS);
}
@@ -2339,7 +2331,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params)
NewcoinAddress naAccountPrivate;
AccountState::pointer asSrc;
STAmount saSrcBalance;
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator);
if (!obj.empty())
@@ -2518,6 +2510,11 @@ Json::Value RPCServer::doLogin(const Json::Value& params)
}
}
Json::Value RPCServer::doLogRotate(const Json::Value& params)
{
return Log::rotateLog();
}
Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params)
{
Log(lsTRACE) << "RPC:" << command;
@@ -2543,6 +2540,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
{ "data_fetch", &RPCServer::doDataFetch, 1, 1, true },
{ "data_store", &RPCServer::doDataStore, 2, 2, true },
{ "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork },
{ "logrotate", &RPCServer::doLogRotate, 0, 0, false, optCurrent },
{ "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent },
{ "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent },
{ "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent },
@@ -2602,7 +2600,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
{
return RPCError(rpcNO_NETWORK);
}
else if ((commandsA[i].iOptions & optCurrent) && mNetOps->getCurrentLedger().isZero())
// XXX Should verify we have a current ledger.
else if ((commandsA[i].iOptions & optCurrent) && false)
{
return RPCError(rpcNO_CURRENT);
}

View File

@@ -141,6 +141,7 @@ private:
Json::Value doDataFetch(const Json::Value& params);
Json::Value doDataStore(const Json::Value& params);
Json::Value doLedger(const Json::Value& params);
Json::Value doLogRotate(const Json::Value& params);
Json::Value doNicknameInfo(const Json::Value& params);
Json::Value doNicknameSet(const Json::Value& params);
Json::Value doOfferCreate(const Json::Value& params);
@@ -184,6 +185,7 @@ private:
Json::Value doLogin(const Json::Value& params);
public:
static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps)
{

View File

@@ -46,8 +46,6 @@ static uint8_t SNTPQueryData[48] =
SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service),
mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256)
{
if (!theConfig.RUN_STANDALONE)
{
mSocket.open(boost::asio::ip::udp::v4());
mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint,
@@ -57,7 +55,6 @@ SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTi
mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY));
mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error));
}
}
void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it)
{

127
src/SerializeProto.h Normal file
View File

@@ -0,0 +1,127 @@
// This is not really a header file, but it can be used as one with
// appropriate #define statements.
// types (common)
TYPE("Int32", UINT32, 1)
TYPE("Int64", UINT64, 2)
TYPE("Hash128", HASH128, 3)
TYPE("Hash256", HASH256, 4)
// 5 is reserved
TYPE("Amount", AMOUNT, 6)
TYPE("VariableLength", VL, 7)
TYPE("Account", ACCOUNT, 8)
// 9-13 are reserved
TYPE("Object", OBJECT, 14)
TYPE("Array", ARRAY, 15)
// types (uncommon)
TYPE("Int8", UINT8, 16)
TYPE("Int16", UINT16, 17)
TYPE("Hash160", HASH160, 18)
TYPE("PathSet", PATHSET, 19)
TYPE("Vector256", VECTOR256, 20)
// 8-bit integers
FIELD(CloseResolution, UINT8, 1)
// 32-bit integers (common)
FIELD(Flags, UINT32, 1)
FIELD(SourceTag, UINT32, 2)
FIELD(Sequence, UINT32, 3)
FIELD(LastTxnSeq, UINT32, 4)
FIELD(LedgerSequence, UINT32, 5)
FIELD(CloseTime, UINT32, 6)
FIELD(ParentCloseTime, UINT32, 7)
FIELD(SigningTime, UINT32, 8)
FIELD(Expiration, UINT32, 9)
FIELD(TransferRate, UINT32, 10)
FIELD(PublishSize, UINT32, 11)
// 32-bit integers (uncommon)
FIELD(HighQualityIn, UINT32, 16)
FIELD(HighQualityOut, UINT32, 17)
FIELD(LowQualityIn, UINT32, 18)
FIELD(LowQualityOut, UINT32, 19)
FIELD(QualityIn, UINT32, 20)
FIELD(QualityOut, UINT32, 21)
FIELD(StampEscrow, UINT32, 22)
FIELD(BondAmount, UINT32, 23)
FIELD(LoadFee, UINT32, 24)
FIELD(OfferSequence, UINT32, 25)
// 64-bit integers
FIELD(IndexNext, UINT64, 1)
FIELD(IndexPrevious, UINT64, 2)
FIELD(BookNode, UINT64, 3)
FIELD(OwnerNode, UINT64, 4)
FIELD(BaseFee, UINT64, 5)
// 128-bit
FIELD(EmailHash, HASH128, 2)
// 256-bit (common)
FIELD(LedgerHash, HASH256, 1)
FIELD(ParentHash, HASH256, 2)
FIELD(TransactionHash, HASH256, 3)
FIELD(AccountHash, HASH256, 4)
FIELD(LastTxnID, HASH256, 5)
FIELD(WalletLocator, HASH256, 6)
FIELD(PublishHash, HASH256, 7)
// 256-bit (uncommon)
FIELD(BookDirectory, HASH256, 16)
FIELD(InvoiceID, HASH256, 17)
FIELD(Nickname, HASH256, 18)
// currency amount (common)
FIELD(Amount, AMOUNT, 1)
FIELD(Balance, AMOUNT, 2)
FIELD(LimitAmount, AMOUNT, 3)
FIELD(TakerPays, AMOUNT, 4)
FIELD(TakerGets, AMOUNT, 5)
FIELD(LowLimit, AMOUNT, 6)
FIELD(HighLimit, AMOUNT, 7)
FIELD(SendMax, AMOUNT, 9)
// current amount (uncommon)
FIELD(MinimumOffer, AMOUNT, 16)
FIELD(RippleEscrow, AMOUNT, 17)
// variable length
FIELD(PublicKey, VL, 1)
FIELD(MessageKey, VL, 2)
FIELD(SigningKey, VL, 3)
FIELD(Signature, VL, 4)
FIELD(Generator, VL, 5)
FIELD(Domain, VL, 6)
FIELD(FundCode, VL, 7)
FIELD(RemoveCode, VL, 8)
FIELD(ExpireCode, VL, 9)
FIELD(CreateCode, VL, 10)
// account
FIELD(Account, ACCOUNT, 1)
FIELD(Owner, ACCOUNT, 2)
FIELD(Destination, ACCOUNT, 3)
FIELD(Issuer, ACCOUNT, 4)
FIELD(HighID, ACCOUNT, 5)
FIELD(LowID, ACCOUNT, 6)
FIELD(Target, ACCOUNT, 7)
FIELD(AuthorizedKey, ACCOUNT, 8)
// path set
FIELD(Paths, PATHSET, 1)
// vector of 256-bit
FIELD(Indexes, VECTOR256, 1)
// inner object
// OBJECT/1 is reserved for end of object
FIELD(MiddleTransaction, OBJECT, 2)
FIELD(InnerTransaction, OBJECT, 3)
// array of objects
// ARRAY/1 is reserved for end of array
FIELD(SigningAccounts, ARRAY, 2)

View File

@@ -3,6 +3,7 @@
#include <boost/format.hpp>
#include "Ledger.h"
#include "Log.h"
SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index)
: SerializedType("LedgerEntry"), mIndex(index)
@@ -99,6 +100,7 @@ uint32 SerializedLedgerEntry::getThreadedLedger()
bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID)
{
uint256 oldPrevTxID = getIFieldH256(sfLastTxnID);
Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID;
if (oldPrevTxID == txID)
return false;
prevTxID = oldPrevTxID;

View File

@@ -42,9 +42,6 @@ std::auto_ptr<SerializedType> STObject::makeDefaultObject(SerializedTypeID id, c
case STI_VL:
return std::auto_ptr<SerializedType>(new STVariableLength(name));
case STI_TL:
return std::auto_ptr<SerializedType>(new STTaggedList(name));
case STI_ACCOUNT:
return std::auto_ptr<SerializedType>(new STAccount(name));
@@ -91,9 +88,6 @@ std::auto_ptr<SerializedType> STObject::makeDeserializedObject(SerializedTypeID
case STI_VL:
return STVariableLength::deserialize(sit, name);
case STI_TL:
return STTaggedList::deserialize(sit, name);
case STI_ACCOUNT:
return STAccount::deserialize(sit, name);
@@ -476,17 +470,6 @@ std::vector<unsigned char> STObject::getValueFieldVL(SOE_Field field) const
return cf->getValue();
}
std::vector<TaggedListItem> STObject::getValueFieldTL(SOE_Field field) const
{
const SerializedType* rf = peekAtPField(field);
if (!rf) throw std::runtime_error("Field not found");
SerializedTypeID id = rf->getSType();
if (id == STI_NOTPRESENT) return std::vector<TaggedListItem>(); // optional field not present
const STTaggedList *cf = dynamic_cast<const STTaggedList *>(rf);
if (!cf) throw std::runtime_error("Wrong field type");
return cf->getValue();
}
STAmount STObject::getValueFieldAmount(SOE_Field field) const
{
const SerializedType* rf = peekAtPField(field);
@@ -620,16 +603,6 @@ void STObject::setValueFieldVL(SOE_Field field, const std::vector<unsigned char>
cf->setValue(v);
}
void STObject::setValueFieldTL(SOE_Field field, const std::vector<TaggedListItem>& v)
{
SerializedType* rf = getPField(field);
if (!rf) throw std::runtime_error("Field not found");
if (rf->getSType() == STI_NOTPRESENT) rf = makeFieldPresent(field);
STTaggedList* cf = dynamic_cast<STTaggedList*>(rf);
if (!cf) throw std::runtime_error("Wrong field type");
cf->setValue(v);
}
void STObject::setValueFieldAmount(SOE_Field field, const STAmount &v)
{
SerializedType* rf = getPField(field);

View File

@@ -18,97 +18,16 @@ enum SOE_Type
SOE_IFNFLAG = 3 // present if flag not set
};
// JED: seems like there would be a better way to do this
// maybe something that inherits from SerializedTransaction
enum SOE_Field
{
sfInvalid = -1,
sfGeneric = 0,
// common fields
sfAcceptExpire,
sfAcceptRate,
sfAcceptStart,
sfAccount,
sfAmount,
sfAuthorizedKey,
sfBalance,
sfBondAmount,
sfBookDirectory,
sfBookNode,
sfBorrowExpire,
sfBorrowRate,
sfBorrowStart,
sfBorrower,
sfCreateCode,
sfCloseTime,
sfCurrency,
sfCurrencyIn,
sfCurrencyOut,
sfDestination,
sfDomain,
sfEmailHash,
sfExpiration,
sfExpireCode,
sfExtensions,
sfFirstNode,
sfFlags,
sfFundCode,
sfGenerator,
sfGeneratorID,
sfHash,
sfHighID,
sfHighLimit,
sfHighQualityIn,
sfHighQualityOut,
sfIdentifier,
sfIndexes,
sfIndexNext,
sfIndexPrevious,
sfInvoiceID,
sfIssuer,
sfLastNode,
sfLastTxnID,
sfLastTxnSeq,
sfLedgerHash,
sfLimitAmount,
sfLowID,
sfLowLimit,
sfLowQualityIn,
sfLowQualityOut,
sfMessageKey,
sfMinimumOffer,
sfNextAcceptExpire,
sfNextAcceptRate,
sfNextAcceptStart,
sfNextTransitExpire,
sfNextTransitRate,
sfNextTransitStart,
sfNickname,
sfOfferSequence,
sfOwner,
sfOwnerNode,
sfPaths,
sfPubKey,
sfPublishHash,
sfPublishSize,
sfQualityIn,
sfQualityOut,
sfRemoveCode,
sfRippleEscrow,
sfSendMax,
sfSequence,
sfSignature,
sfSigningKey,
sfSigningTime,
sfSourceTag,
sfStampEscrow,
sfTakerGets,
sfTakerPays,
sfTarget,
sfTransferRate,
sfVersion,
sfWalletLocator,
#define FIELD(name, type, index) sf##name,
#define TYPE(name, type, index)
#include "SerializeProto.h"
#undef FIELD
#undef TYPE
// test fields
sfTest1, sfTest2, sfTest3, sfTest4

View File

@@ -255,51 +255,6 @@ void STAccount::setValueNCA(const NewcoinAddress& nca)
setValueH160(nca.getAccountID());
}
std::string STTaggedList::getText() const
{
std::string ret;
for (std::vector<TaggedListItem>::const_iterator it=value.begin(); it!=value.end(); ++it)
{
ret += boost::lexical_cast<std::string>(it->first);
ret += ",";
ret += strHex(it->second);
}
return ret;
}
Json::Value STTaggedList::getJson(int) const
{
Json::Value ret(Json::arrayValue);
for (std::vector<TaggedListItem>::const_iterator it=value.begin(); it!=value.end(); ++it)
{
Json::Value elem(Json::arrayValue);
elem.append(it->first);
elem.append(strHex(it->second));
ret.append(elem);
}
return ret;
}
STTaggedList* STTaggedList::construct(SerializerIterator& u, const char *name)
{
return new STTaggedList(name, u.getTaggedList());
}
int STTaggedList::getLength() const
{
int ret = Serializer::getTaggedListLength(value);
if (ret<0) throw std::overflow_error("bad TL length");
return ret;
}
bool STTaggedList::isEquivalent(const SerializedType& t) const
{
const STTaggedList* v = dynamic_cast<const STTaggedList*>(&t);
return v && (value == v->value);
}
STPathSet* STPathSet::construct(SerializerIterator& s, const char *name)
{
std::vector<STPath> paths;

View File

@@ -15,25 +15,15 @@ enum SerializedTypeID
STI_DONE = -1,
STI_NOTPRESENT = 0,
// standard types
STI_OBJECT = 1,
STI_UINT8 = 2,
STI_UINT16 = 3,
STI_UINT32 = 4,
STI_UINT64 = 5,
STI_HASH128 = 6,
STI_HASH160 = 7,
STI_HASH256 = 8,
STI_VL = 9,
STI_TL = 10,
STI_AMOUNT = 11,
STI_PATHSET = 12,
STI_VECTOR256 = 13,
#define TYPE(name, field, value) STI_##field = value,
#define FIELD(name, field, value)
#include "SerializeProto.h"
#undef TYPE
#undef FIELD
// high level types
STI_ACCOUNT = 100,
STI_TRANSACTION = 101,
STI_LEDGERENTRY = 102
STI_TRANSACTION = 100001,
STI_LEDGERENTRY = 100002
};
enum PathFlags
@@ -247,9 +237,9 @@ protected:
STAmount(const char *name, uint64 value, bool isNegative)
: SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative)
{ ; }
STAmount(const char *n, const uint160& cur, uint64 val, int off, bool isNative, bool isNegative)
: SerializedType(n), mCurrency(cur), mValue(val), mOffset(off), mIsNative(isNative), mIsNegative(isNegative)
{ ; }
STAmount(const char *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg)
: SerializedType(n), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off),
mIsNative(isNat), mIsNegative(isNeg) { ; }
uint64 toUInt64() const;
static uint64 muldiv(uint64, uint64, uint64);
@@ -269,8 +259,9 @@ public:
{ canonicalize(); }
// YYY This should probably require issuer too.
STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) :
SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg)
STAmount(const char* n, const uint160& currency, const uint160& issuer,
uint64 v = 0, int off = 0, bool isNeg = false) :
SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg)
{ canonicalize(); }
STAmount(const char* n, int64 v);
@@ -726,45 +717,6 @@ namespace boost
};
}
class STTaggedList : public SerializedType
{
protected:
std::vector<TaggedListItem> value;
STTaggedList* duplicate() const { return new STTaggedList(name, value); }
static STTaggedList* construct(SerializerIterator&, const char* name = NULL);
public:
STTaggedList() { ; }
STTaggedList(const char* n) : SerializedType(n) { ; }
STTaggedList(const std::vector<TaggedListItem>& v) : value(v) { ; }
STTaggedList(const char* n, const std::vector<TaggedListItem>& v) : SerializedType(n), value(v) { ; }
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const;
SerializedTypeID getSType() const { return STI_TL; }
std::string getText() const;
void add(Serializer& s) const { if (s.addTaggedList(value) < 0) throw(0); }
const std::vector<TaggedListItem>& peekValue() const { return value; }
std::vector<TaggedListItem>& peekValue() { return value; }
std::vector<TaggedListItem> getValue() const { return value; }
virtual Json::Value getJson(int) const;
void setValue(const std::vector<TaggedListItem>& v) { value=v; }
int getItemCount() const { return value.size(); }
bool isEmpty() const { return value.empty(); }
void clear() { value.erase(value.begin(), value.end()); }
void addItem(const TaggedListItem& v) { value.push_back(v); }
operator std::vector<TaggedListItem>() const { return value; }
virtual bool isEquivalent(const SerializedType& t) const;
};
class STVector256 : public SerializedType
{
protected:

View File

@@ -154,6 +154,57 @@ uint256 Serializer::get256(int offset) const
return ret;
}
int Serializer::addFieldID(int type, int name)
{
int ret = mData.size();
assert((type > 0) && (type < 256) && (name > 0) && (name < 256));
if (type < 16)
{
if (name < 16) // common type, common name
mData.push_back(static_cast<unsigned char>((type << 4) | name));
else
{ // common type, uncommon name
mData.push_back(static_cast<unsigned char>(type << 4));
mData.push_back(static_cast<unsigned char>(name));
}
}
else if (name < 16)
{ // uncommon type, common name
mData.push_back(static_cast<unsigned char>(name));
mData.push_back(static_cast<unsigned char>(type));
}
else
{ // uncommon type, uncommon name
mData.push_back(static_cast<unsigned char>(0));
mData.push_back(static_cast<unsigned char>(type));
mData.push_back(static_cast<unsigned char>(name));
}
return ret;
}
bool Serializer::getFieldID(int& type, int & name, int offset) const
{
if (!get8(type, offset))
return false;
name = type & 15;
type >>= 4;
if (type == 0)
{ // uncommon type
if (!get8(type, ++offset))
return false;
if ((type == 0) || (type < 16))
return false;
}
if (name == 0)
{ // uncommon name
if (!get8(name, ++offset))
return false;
if ((name == 0) || (name < 16))
return false;
}
return true;
}
int Serializer::add8(unsigned char byte)
{
int ret = mData.size();
@@ -535,6 +586,17 @@ int SerializerIterator::getBytesLeft()
return mSerializer.size() - mPos;
}
void SerializerIterator::getFieldID(int& type, int& field)
{
if (!mSerializer.getFieldID(type, field, mPos))
throw std::runtime_error("invalid serializer getFieldID");
++mPos;
if (type >= 16)
++mPos;
if (field >= 16)
++mPos;
}
unsigned char SerializerIterator::get8()
{
int val;

View File

@@ -67,6 +67,9 @@ public:
bool getTaggedList(std::list<TaggedListItem>&, int offset, int& length) const;
bool getTaggedList(std::vector<TaggedListItem>&, int offset, int& length) const;
bool getFieldID(int& type, int& name, int offset) const;
int addFieldID(int type, int name);
// normal hash functions
uint160 getRIPEMD160(int size=-1) const;
uint256 getSHA256(int size=-1) const;
@@ -156,6 +159,8 @@ public:
uint160 get160();
uint256 get256();
void getFieldID(int& type, int& field);
std::vector<unsigned char> getRaw(int iLength);
std::vector<unsigned char> getVL();

View File

@@ -194,7 +194,7 @@ Transaction::pointer Transaction::setClaim(
const std::vector<unsigned char>& vucSignature)
{
mTransaction->setITFieldVL(sfGenerator, vucGenerator);
mTransaction->setITFieldVL(sfPubKey, vucPubKey);
mTransaction->setITFieldVL(sfPublicKey, vucPubKey);
mTransaction->setITFieldVL(sfSignature, vucSignature);
sign(naPrivateKey);
@@ -455,7 +455,7 @@ Transaction::pointer Transaction::setPasswordSet(
{
mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID);
mTransaction->setITFieldVL(sfGenerator, vucGenerator);
mTransaction->setITFieldVL(sfPubKey, vucPubKey);
mTransaction->setITFieldVL(sfPublicKey, vucPubKey);
mTransaction->setITFieldVL(sfSignature, vucSignature);
sign(naPrivateKey);
@@ -542,7 +542,7 @@ Transaction::pointer Transaction::setWalletAdd(
{
mTransaction->setITFieldAmount(sfAmount, saAmount);
mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID);
mTransaction->setITFieldVL(sfPubKey, naNewPubKey.getAccountPublic());
mTransaction->setITFieldVL(sfPublicKey, naNewPubKey.getAccountPublic());
mTransaction->setITFieldVL(sfSignature, vucSignature);
sign(naPrivateKey);

View File

@@ -30,7 +30,7 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus
//
std::vector<unsigned char> vucCipher = txn.getITFieldVL(sfGenerator);
std::vector<unsigned char> vucPubKey = txn.getITFieldVL(sfPubKey);
std::vector<unsigned char> vucPubKey = txn.getITFieldVL(sfPublicKey);
std::vector<unsigned char> vucSignature = txn.getITFieldVL(sfSignature);
NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey);
@@ -166,18 +166,24 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn)
{
uint32 uRate = txn.getITFieldU32(sfTransferRate);
if (!uRate)
if (!uRate || uRate == QUALITY_ONE)
{
Log(lsINFO) << "doAccountSet: unset transfer rate";
mTxnAccount->makeIFieldAbsent(sfTransferRate);
}
else
else if (uRate > QUALITY_ONE)
{
Log(lsINFO) << "doAccountSet: set transfer rate";
mTxnAccount->setIFieldU32(sfTransferRate, uRate);
}
else
{
Log(lsINFO) << "doAccountSet: bad transfer rate";
return temBAD_TRANSFER_RATE;
}
}
//
@@ -620,7 +626,7 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn)
{
std::cerr << "WalletAdd>" << std::endl;
const std::vector<unsigned char> vucPubKey = txn.getITFieldVL(sfPubKey);
const std::vector<unsigned char> vucPubKey = txn.getITFieldVL(sfPublicKey);
const std::vector<unsigned char> vucSignature = txn.getITFieldVL(sfSignature);
const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey);
const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey);
@@ -710,8 +716,8 @@ TER TransactionEngine::takeOffers(
boost::unordered_set<uint256> usOfferUnfundedBecame; // Offers that became unfunded.
boost::unordered_set<uint160> usAccountTouched; // Accounts touched.
saTakerPaid = 0;
saTakerGot = 0;
saTakerPaid = STAmount(saTakerPays.getCurrency(), saTakerPays.getIssuer());
saTakerGot = STAmount(saTakerGets.getCurrency(), saTakerGets.getIssuer());
while (temUNCERTAIN == terResult)
{
@@ -915,8 +921,11 @@ Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0);
const bool bPassive = isSetBit(txFlags, tfPassive);
STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays);
STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets);
Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText();
Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGets=%s")
% saTakerPays.getFullText()
% saTakerGets.getFullText());
const uint160 uPaysIssuerID = saTakerPays.getIssuer();
const uint160 uGetsIssuerID = saTakerGets.getIssuer();
const uint32 uExpiration = txn.getITFieldU32(sfExpiration);
@@ -999,14 +1008,14 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
STAmount saOfferGot;
const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID);
Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s")
Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s for %s -> %s")
% uTakeBookBase.ToString()
% saTakerGets.getHumanCurrency()
% NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer())
% saTakerPays.getHumanCurrency()
% NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer()));
% saTakerGets.getFullText()
% saTakerPays.getFullText());
// Take using the parameters of the offer.
#if 1
Log(lsWARNING) << "doOfferCreate: takeOffers: BEFORE saTakerGets=" << saTakerGets.getFullText();
terResult = takeOffers(
bPassive,
uTakeBookBase,
@@ -1017,12 +1026,14 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
saOfferPaid, // How much was spent.
saOfferGot // How much was got.
);
#else
terResult = tesSUCCESS;
#endif
Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult;
Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: AFTER saTakerGets=" << saTakerGets.getFullText();
if (tesSUCCESS == terResult)
{
@@ -1033,9 +1044,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer());
Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID);
Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: FUNDS=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText();
// Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID);
// Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID);
@@ -1046,6 +1056,9 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
&& mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded.
{
// We need to place the remainder of the offer into its order book.
Log(lsINFO) << boost::str(boost::format("doOfferCreate: offer not fully consumed: saTakerPays=%s saTakerGets=%s")
% saTakerPays.getFullText()
% saTakerGets.getFullText());
// Add offer to owner's directory.
terResult = mNodes.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex);
@@ -1069,12 +1082,13 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
if (tesSUCCESS == terResult)
{
// Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID);
// Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID);
// Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative();
// Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative();
// Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency();
// Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency();
Log(lsWARNING) << "doOfferCreate: sfAccount=" << NewcoinAddress::createHumanAccountID(mTxnAccountID);
Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID);
Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID);
Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative();
Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative();
Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency();
Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency();
sleOffer->setIFieldAccount(sfAccount, mTxnAccountID);
sleOffer->setIFieldU32(sfSequence, uSequence);
@@ -1092,6 +1106,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText();
}
}
Log(lsINFO) << "doOfferCreate: final sleOffer=" << sleOffer->getJson(0);
return terResult;
}

View File

@@ -31,6 +31,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
{ temBAD_PATH, "temBAD_PATH", "Malformed." },
{ temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed." },
{ temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." },
{ temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: transfer rate must be >= 1.0" },
{ temBAD_SET_ID, "temBAD_SET_ID", "Malformed." },
{ temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." },
{ temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." },
@@ -89,3 +90,4 @@ std::string transHuman(TER terCode)
return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-";
}
// vim:ts=4

View File

@@ -33,6 +33,7 @@ enum TER // aka TransactionEngineResult
temBAD_PATH,
temBAD_PATH_LOOP,
temBAD_PUBLISH,
temBAD_TRANSFER_RATE,
temBAD_SET_ID,
temCREATEXNS,
temDST_IS_SRC,

View File

@@ -15,16 +15,14 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 32 },
{ S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 },
{ S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Claim", ttCLAIM, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "CreditSet", ttCREDIT_SET, {
@@ -34,7 +32,6 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(LimitAmount), STI_AMOUNT, SOE_IFFLAG, 2 },
{ S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
/*
@@ -45,7 +42,6 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 },
{ S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 4 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
*/
@@ -55,7 +51,6 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 },
{ S_FIELD(Signature), STI_VL, SOE_IFFLAG, 2 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "OfferCreate", ttOFFER_CREATE, {
@@ -64,31 +59,27 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "OfferCancel", ttOFFER_CANCEL, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(OfferSequence), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "PasswordFund", ttPASSWORD_FUND, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "PasswordSet", ttPASSWORD_SET, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Payment", ttPAYMENT, {
@@ -99,17 +90,15 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(Paths), STI_PATHSET, SOE_IFFLAG, 2 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "WalletAdd", ttWALLET_ADD, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Contract", ttCONTRACT, {
@@ -122,13 +111,11 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Contract", ttCONTRACT_REMOVE, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ NULL, ttINVALID }

View File

@@ -294,11 +294,15 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const
return mNodes.find(node) != mNodes.end();
}
TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type)
TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type, bool overrideType)
{
std::map<uint256, TransactionMetaNode>::iterator it = mNodes.find(node);
if (it != mNodes.end())
{
if (overrideType)
it->second.setType(type);
return it->second;
}
return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second;
}

View File

@@ -158,6 +158,7 @@ public:
TransactionMetaNode(int type, const uint256& node, SerializerIterator&);
void addRaw(Serializer&);
void setType(int t) { mType = t; }
Json::Value getJson(int) const;
bool addAmount(int nodeType, const STAmount& amount);
@@ -189,7 +190,7 @@ public:
uint32 getLgrSeq() { return mLedger; }
bool isNodeAffected(const uint256&) const;
TransactionMetaNode& getAffectedNode(const uint256&, int type);
TransactionMetaNode& getAffectedNode(const uint256&, int type, bool overrideType);
const TransactionMetaNode& peekAffectedNode(const uint256&) const;
Json::Value getJson(int) const;

View File

@@ -2,7 +2,6 @@
// XXX Want a limit of 2000 validators.
#include "Application.h"
#include "Conversion.h"
#include "HttpsClient.h"
#include "Log.h"
#include "ParseSection.h"

View File

@@ -75,7 +75,12 @@ public:
Json::Value invokeCommand(const Json::Value& jvRequest);
boost::unordered_set<NewcoinAddress> parseAccountIds(const Json::Value& jvArray);
// Commands
// Request-Response Commands
void doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest);
void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest);
void doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest);
// Streaming Commands
void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest);
void doAccountInfoUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest);
void doAccountTransactionSubscribe(Json::Value& jvResult, const Json::Value& jvRequest);
@@ -293,6 +298,12 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest)
const char* pCommand;
doFuncPtr dfpFunc;
} commandsA[] = {
// Request-Response Commands:
{ "ledger_closed", &WSConnection::doLedgerClosed },
{ "ledger_current", &WSConnection::doLedgerCurrent },
{ "ledger_entry", &WSConnection::doLedgerEntry },
// Streaming commands:
{ "account_info_subscribe", &WSConnection::doAccountInfoSubscribe },
{ "account_info_unsubscribe", &WSConnection::doAccountInfoUnsubscribe },
{ "account_transaction_subscribe", &WSConnection::doAccountTransactionSubscribe },
@@ -541,6 +552,239 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json
}
}
void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest)
{
uint256 uLedger = theApp->getOPs().getClosedLedger();
jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger);
jvResult["ledger"] = uLedger.ToString();
}
void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest)
{
jvResult["ledger_index"] = theApp->getOPs().getCurrentLedgerID();
}
void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest)
{
NetworkOPs& noNetwork = theApp->getOPs();
uint256 uLedger = jvRequest.isMember("ledger") ? uint256(jvRequest["ledger"].asString()) : 0;
uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0;
Ledger::pointer lpLedger;
if (!!uLedger)
{
// Ledger directly specified.
lpLedger = noNetwork.getLedgerByHash(uLedger);
if (!lpLedger)
{
jvResult["error"] = "ledgerNotFound";
return;
}
uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index, override if needed.
}
else if (!!uLedgerIndex)
{
lpLedger = noNetwork.getLedgerBySeq(uLedgerIndex);
if (!lpLedger)
{
jvResult["error"] = "ledgerNotFound"; // ledger_index from future?
return;
}
}
else
{
// Default to current ledger.
lpLedger = noNetwork.getCurrentLedger();
uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index.
}
if (!!uLedger)
jvResult["ledger"] = uLedger.ToString();
jvResult["ledger_index"] = uLedgerIndex;
uint256 uNodeIndex;
bool bNodeBinary = false;
if (jvRequest.isMember("index"))
{
// XXX Needs to provide proof.
uNodeIndex.SetHex(jvRequest["index"].asString());
bNodeBinary = true;
}
else if (jvRequest.isMember("account_root"))
{
NewcoinAddress naAccount;
if (!naAccount.setAccountID(jvRequest["account_root"].asString()))
{
jvResult["error"] = "malformedAddress";
}
else
{
uNodeIndex = Ledger::getAccountRootIndex(naAccount.getAccountID());
}
}
else if (jvRequest.isMember("directory"))
{
if (!jvRequest.isObject())
{
uNodeIndex.SetHex(jvRequest["directory"].asString());
}
else if (jvRequest["directory"].isMember("sub_index")
&& !jvRequest["directory"]["sub_index"].isIntegral())
{
jvResult["error"] = "malformedRequest";
}
else
{
uint64 uSubIndex = jvRequest["directory"].isMember("sub_index")
? jvRequest["directory"]["sub_index"].asUInt()
: 0;
if (jvRequest["directory"].isMember("dir_root"))
{
uint256 uDirRoot;
uDirRoot.SetHex(jvRequest["dir_root"].asString());
uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex);
}
else if (jvRequest["directory"].isMember("owner"))
{
NewcoinAddress naOwnerID;
if (!naOwnerID.setAccountID(jvRequest["directory"]["owner"].asString()))
{
jvResult["error"] = "malformedAddress";
}
else
{
uint256 uDirRoot = Ledger::getOwnerDirIndex(naOwnerID.getAccountID());
uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex);
}
}
else
{
jvResult["error"] = "malformedRequest";
}
}
}
else if (jvRequest.isMember("generator"))
{
NewcoinAddress naGeneratorID;
if (!jvRequest.isObject())
{
uNodeIndex.SetHex(jvRequest["generator"].asString());
}
else if (!jvRequest["generator"].isMember("regular_seed"))
{
jvResult["error"] = "malformedRequest";
}
else if (!naGeneratorID.setSeedGeneric(jvRequest["generator"]["regular_seed"].asString()))
{
jvResult["error"] = "malformedAddress";
}
else
{
NewcoinAddress na0Public; // To find the generator's index.
NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naGeneratorID);
na0Public.setAccountPublic(naGenerator, 0);
uNodeIndex = Ledger::getGeneratorIndex(na0Public.getAccountID());
}
}
else if (jvRequest.isMember("offer"))
{
NewcoinAddress naAccountID;
if (!jvRequest.isObject())
{
uNodeIndex.SetHex(jvRequest["offer"].asString());
}
else if (!jvRequest["offer"].isMember("account")
|| !jvRequest["offer"].isMember("seq")
|| !jvRequest["offer"]["seq"].isIntegral())
{
jvResult["error"] = "malformedRequest";
}
else if (!naAccountID.setAccountID(jvRequest["offer"]["account"].asString()))
{
jvResult["error"] = "malformedAddress";
}
else
{
uint32 uSequence = jvRequest["offer"]["seq"].asUInt();
uNodeIndex = Ledger::getOfferIndex(naAccountID.getAccountID(), uSequence);
}
}
else if (jvRequest.isMember("ripple_state"))
{
NewcoinAddress naA;
NewcoinAddress naB;
uint160 uCurrency;
if (!jvRequest.isMember("accounts")
|| !jvRequest.isMember("currency")
|| !jvRequest["accounts"].isArray()
|| 2 != jvRequest["accounts"].size()) {
jvResult["error"] = "malformedRequest";
}
else if (!naA.setAccountID(jvRequest["accounts"][0u].asString())
|| !naB.setAccountID(jvRequest["accounts"][1u].asString())) {
jvResult["error"] = "malformedAddress";
}
else if (!STAmount::currencyFromString(uCurrency, jvRequest["currency"].asString())) {
jvResult["error"] = "malformedCurrency";
}
else
{
uNodeIndex = Ledger::getRippleStateIndex(naA, naB, uCurrency);
}
}
else
{
jvResult["error"] = "unknownOption";
}
if (!!uNodeIndex)
{
SLE::pointer sleNode = noNetwork.getSLE(lpLedger, uNodeIndex);
if (!sleNode)
{
// Not found.
// XXX Should also provide proof.
jvResult["error"] = "entryNotFound";
}
else if (bNodeBinary)
{
// XXX Should also provide proof.
Serializer s;
sleNode->add(s);
jvResult["node_binary"] = strHex(s.peekData());
jvResult["index"] = uNodeIndex.ToString();
}
else
{
jvResult["node"] = sleNode->getJson(0);
jvResult["index"] = uNodeIndex.ToString();
}
}
}
void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().subTransaction(this))

View File

@@ -51,6 +51,7 @@ void printHelp(const po::options_description& desc)
cout << " data_fetch <key>" << endl;
cout << " data_store <key> <value>" << endl;
cout << " ledger [<id>|current|lastclosed] [full]" << endl;
cout << " logrotate " << endl;
cout << " nickname_info <nickname>" << endl;
cout << " nickname_set <seed> <paying_account> <nickname> [<offer_minimum>] [<authorization>]" << endl;
cout << " offer_create <seed> <paying_account> <taker_pays_amount> <taker_pays_currency> <taker_pays_issuer> <takers_gets_amount> <takers_gets_currency> <takers_gets_issuer> <expires> [passive]" << endl;

View File

@@ -386,96 +386,6 @@ public:
};
//////////////////////////////////////////////////////////////////////////////
//
// uint160
//
class uint160 : public base_uint160
{
public:
typedef base_uint160 basetype;
uint160()
{
zero();
}
uint160(const basetype& b)
{
*this = b;
}
uint160& operator=(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
uint160(uint64 b)
{
*this = b;
}
uint160& operator=(uint64 uHost)
{
zero();
// Put in least significant bits.
((uint64_t *) end())[-1] = htobe64(uHost);
return *this;
}
explicit uint160(const std::string& str)
{
SetHex(str);
}
explicit uint160(const std::vector<unsigned char>& vch)
{
if (vch.size() == sizeof(pn))
memcpy(pn, &vch[0], sizeof(pn));
else
zero();
}
base_uint256 to256() const;
};
inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; }
inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; }
inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; }
inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; }
inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; }
inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
extern std::size_t hash_value(const uint160&);
inline const std::string strHex(const uint160& ui)
{
return strHex(ui.begin(), ui.size());
}
//////////////////////////////////////////////////////////////////////////////
//
// uint256
@@ -694,5 +604,102 @@ inline int Testuint256AdHoc(std::vector<std::string> vArg)
return (0);
}
//////////////////////////////////////////////////////////////////////////////
//
// uint160
//
class uint160 : public base_uint160
{
public:
typedef base_uint160 basetype;
uint160()
{
zero();
}
uint160(const basetype& b)
{
*this = b;
}
uint160& operator=(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
uint160(uint64 b)
{
*this = b;
}
uint160& operator=(uint64 uHost)
{
zero();
// Put in least significant bits.
((uint64_t *) end())[-1] = htobe64(uHost);
return *this;
}
explicit uint160(const std::string& str)
{
SetHex(str);
}
explicit uint160(const std::vector<unsigned char>& vch)
{
if (vch.size() == sizeof(pn))
memcpy(pn, &vch[0], sizeof(pn));
else
zero();
}
base_uint256 to256() const
{
uint256 m;
memcpy(m.begin(), begin(), size());
return m;
}
};
inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; }
inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; }
inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; }
inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; }
inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; }
inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
extern std::size_t hash_value(const uint160&);
inline const std::string strHex(const uint160& ui)
{
return strHex(ui.begin(), ui.size());
}
#endif
// vim:ts=4

View File

@@ -9,15 +9,17 @@ exports.newcoind = path.join(process.cwd(), "newcoind");
// Configuration for servers.
exports.servers = {
// A local test server.
alpha : {
'trusted' : true,
// "peer_ip" : "0.0.0.0",
// "peer_port" : 51235,
"rpc_ip" : "0.0.0.0",
"rpc_port" : 5005,
"websocket_ip" : "127.0.0.1",
"websocket_port" : 6005,
"validation_seed" : "shhDFVsmS2GSu5vUyZSPXYfj1r79h",
"validators" : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta"
'rpc_ip' : "0.0.0.0",
'rpc_port' : 5005,
'websocket_ip' : "127.0.0.1",
'websocket_port' : 6005,
'validation_seed' : "shhDFVsmS2GSu5vUyZSPXYfj1r79h",
'validators' : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta"
}
};
// vim:ts=4

View File

@@ -1,4 +1,7 @@
// Manage test servers
//
// YYY Would be nice to be able to hide server output.
//
// Provide servers
//
@@ -6,7 +9,7 @@
//
var config = require("./config.js");
var utils = require("./utils.js");
var utils = require("../js/utils.js");
var fs = require("fs");
var path = require("path");
@@ -16,57 +19,63 @@ var WebSocket = require("ws");
var servers = {};
var serverPath = function(name) {
return "tmp/server/" + name;
// Create a server object
var Server = function(name) {
this.name = name;
};
// Return a server's newcoind.cfg as string.
var configContent = function(name) {
var cfg = config.servers[name];
Server.method('configContent', function() {
var cfg = config.servers[this.name];
return Object.keys(cfg).map(function(o) {
return util.format("[%s]\n%s\n", o, cfg[o]);
}).join("");
};
});
var configPath = function(name) {
return path.join(serverPath(name), "newcoind.cfg");
};
Server.method('serverPath', function() {
return "tmp/server/" + this.name;
});
Server.method('configPath', function() {
return path.join(this.serverPath(), "newcoind.cfg");
});
// Write a server's newcoind.cfg.
var writeConfig = function(name, done) {
fs.writeFile(configPath(name), configContent(name), 'utf8', done);
};
Server.method('writeConfig', function(done) {
fs.writeFile(this.configPath(), this.configContent(), 'utf8', done);
});
var serverSpawnSync = function(name) {
// Spawn the server.
Server.method('serverSpawnSync', function() {
// Spawn in standalone mode for now.
var server = child.spawn(
this.child = child.spawn(
config.newcoind,
[
"-a",
"--conf=newcoind.cfg"
],
{
cwd: serverPath(name),
cwd: this.serverPath(),
env: process.env,
stdio: 'inherit'
});
servers[name] = server;
console.log("server: %s: %s -a --conf=%s", server.pid, config.newcoind, configPath(name));
console.log("sever: start: servers = %s", Object.keys(servers).toString());
console.log("server: start %s: %s -a --conf=%s", this.child.pid, config.newcoind, this.configPath());
server.on('exit', function (code, signal) {
// By default, just log exits.
this.child.on('exit', function(code, signal) {
// If could not exec: code=127, signal=null
// If regular exit: code=0, signal=null
console.log("sever: spawn: server exited code=%s: signal=%s", code, signal);
delete servers[name];
console.log("server: spawn: server exited code=%s: signal=%s", code, signal);
});
};
});
var makeBase = function(name, done) {
var path = serverPath(name);
// Prepare server's working directory.
Server.method('makeBase', function(done) {
var path = this.serverPath();
var self = this;
// Reset the server directory, build it if needed.
utils.resetPath(path, '0777', function(e) {
@@ -74,49 +83,73 @@ var makeBase = function(name, done) {
throw e;
}
else {
writeConfig(name, done);
self.writeConfig(done);
}
});
};
var wsOpen = function(done) {
var socket = new WebSocket(util.format("ws:://%s:%s", server.websocket_ip, server.websocket_port));
socket.on('open') {
done();
});
};
// Create a standalone server.
// Prepare the working directory and spawn the server.
exports.start = function(name, done) {
makeBase(name, function (e) {
Server.method('start', function(done) {
var self = this;
this.makeBase(function(e) {
if (e) {
throw e;
}
else {
serverSpawnSync(name);
wsOpen(done);
self.serverSpawnSync();
done();
}
});
};
});
exports.stop = function(name, done) {
console.log("sever: stop: servers = %s", Object.keys(servers).toString());
var server = servers[name];
if (server) {
server.on('exit', function (code, signal) {
console.log("sever: stop: server exited");
delete servers[name];
// Stop a standalone server.
Server.method('stop', function(done) {
if (this.child) {
// Update the on exit to invoke done.
this.child.on('exit', function(code, signal) {
console.log("server: stop: server exited");
done();
});
server.kill();
this.child.kill();
}
else
{
console.log("sever: stop: no such server");
console.log("server: stop: no such server");
done();
}
});
// Start the named server.
exports.start = function(name, done) {
if (servers[name])
{
console.log("server: start: server already started.");
}
else
{
var server = new Server(name);
servers[name] = server;
console.log("server: start: %s", JSON.stringify(server));
server.start(done);
}
};
// Delete the named server.
exports.stop = function(name, done) {
console.log("server: stop: %s of %s", name, Object.keys(servers).toString());
var server = servers[name];
if (server) {
server.stop(done);
delete servers[name];
}
};
exports.Server = Server;
// vim:ts=4

View File

@@ -1,11 +1,16 @@
// console.log("standalone-test.js>");
var fs = require("fs");
var buster = require("buster");
var server = require("./server.js");
var remote = require("../js/remote.js");
var config = require("./config.js");
buster.testCase("Check standalone server startup", {
// How long to wait for server to start.
var serverDelay = 1500;
buster.testRunner.timeout = 5000;
buster.testCase("Standalone server startup", {
"server start and stop": function(done) {
server.start("alpha",
function(e) {
@@ -18,5 +23,166 @@ buster.testCase("Check standalone server startup", {
}
});
// console.log("standalone-test.js<");
buster.testCase("WebSocket connection", {
'setUp' :
function(done) {
server.start("alpha",
function(e) {
buster.refute(e);
done();
}
);
},
'tearDown' :
function(done) {
server.stop("alpha", function(e) {
buster.refute(e);
done();
});
},
"websocket connect and disconnect" :
function(done) {
var alpha = remote.remoteConfig(config, "alpha");
alpha.connect(function(stat) {
buster.assert(1 == stat); // OPEN
alpha.disconnect(function(stat) {
buster.assert(3 == stat); // CLOSED
done();
});
}, serverDelay);
},
});
buster.testCase("Websocket commands", {
'setUp' :
function(done) {
server.start("alpha",
function(e) {
buster.refute(e);
alpha = remote.remoteConfig(config, "alpha");
alpha.connect(function(stat) {
buster.assert(1 == stat); // OPEN
done();
}, serverDelay);
});
},
'tearDown' :
function(done) {
alpha.disconnect(function(stat) {
buster.assert(3 == stat); // CLOSED
server.stop("alpha", function(e) {
buster.refute(e);
done();
});
});
},
'ledger_current' :
function(done) {
alpha.ledger_current(function (r) {
console.log(r);
buster.assert.equals(r.ledger_index, 3);
done();
});
},
'// ledger_closed' :
function(done) {
alpha.ledger_closed(function (r) {
console.log("result: %s", JSON.stringify(r));
buster.assert.equals(r.ledger_index, 2);
done();
});
},
'account_root success' :
function(done) {
alpha.ledger_closed(function (r) {
// console.log("result: %s", JSON.stringify(r));
buster.refute('error' in r);
alpha.ledger_entry({
'ledger_index' : r.ledger_index,
'account_root' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh'
} , function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert('node' in r);
done();
});
});
},
'account_root malformedAddress' :
function(done) {
alpha.ledger_closed(function (r) {
// console.log("result: %s", JSON.stringify(r));
buster.refute('error' in r);
alpha.ledger_entry({
'ledger_index' : r.ledger_index,
'account_root' : 'foobar'
} , function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert.equals(r.error, 'malformedAddress');
done();
});
});
},
'account_root entryNotFound' :
function(done) {
alpha.ledger_closed(function (r) {
// console.log("result: %s", JSON.stringify(r));
buster.refute('error' in r);
alpha.ledger_entry({
'ledger_index' : r.ledger_index,
'account_root' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn'
} , function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert.equals(r.error, 'entryNotFound');
done();
});
});
},
'ledger_entry index' :
function(done) {
alpha.ledger_closed(function (r) {
// console.log("result: %s", JSON.stringify(r));
buster.refute('error' in r);
alpha.ledger_entry({
'ledger_index' : r.ledger_index,
'index' : "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
} , function (r) {
console.log("node: %s", JSON.stringify(r));
buster.assert('node_binary' in r);
done();
});
});
},
});
// vim:ts=4