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

Conflicts:
	src/Application.cpp
This commit is contained in:
JoelKatz
2012-11-05 16:19:34 -08:00
15 changed files with 303 additions and 204 deletions

3
.gitignore vendored
View File

@@ -23,3 +23,6 @@ node_modules
# Ignore tmp directory.
tmp
# Ignore database directory.
db/*.db

View File

@@ -68,7 +68,7 @@ Request.prototype.ledger_choose = function (current) {
this.message.ledger_index = this.remote.ledger_current_index;
}
else {
this.message.ledger = this.remote.ledger_closed;
this.message.ledger_hash = this.remote.ledger_hash;
}
return this;
@@ -77,8 +77,8 @@ Request.prototype.ledger_choose = function (current) {
// Set the ledger for a request.
// - ledger_entry
// - transaction_entry
Request.prototype.ledger_closed = function (ledger) {
this.message.ledger_closed = ledger;
Request.prototype.ledger_hash = function (h) {
this.message.ledger_hash = n;
return this;
};
@@ -110,8 +110,14 @@ Request.prototype.secret = function (s) {
return this;
};
Request.prototype.transaction = function (t) {
this.message.transaction = t;
Request.prototype.tx_hash = function (h) {
this.message.tx_hash = h;
return this;
};
Request.prototype.tx_json = function (j) {
this.message.tx_json = j;
return this;
};
@@ -148,7 +154,7 @@ var Remote = function (trusted, websocket_ip, websocket_port, trace) {
this.websocket_port = websocket_port;
this.id = 0;
this.trace = trace;
this.ledger_closed = undefined;
this.ledger_hash = undefined;
this.ledger_current_index = undefined;
this.stand_alone = undefined;
this.online_target = false;
@@ -413,10 +419,11 @@ Remote.prototype._connect_message = function (ws, json, flags) {
// XXX Be more defensive fields could be missing or of wrong type.
// YYY Might want to do some cache management.
this.ledger_closed = message.ledger_closed;
this.ledger_current_index = message.ledger_closed_index + 1;
this.ledger_time = message.ledger_time;
this.ledger_hash = message.ledger_hash;
this.ledger_current_index = message.ledger_index + 1;
this.emit('ledger_closed', message.ledger_closed, message.ledger_closed_index);
this.emit('ledger_closed', message.ledger_hash, message.ledger_index);
break;
default:
@@ -469,16 +476,25 @@ Remote.prototype.request = function (request) {
}
};
Remote.prototype.request_ledger_closed = function () {
// Only for unit testing.
Remote.prototype.request_ledger_hash = function () {
assert(this.trusted); // If not trusted, need to check proof.
return new Request(this, 'ledger_closed');
var request = new Request(this, 'rpc');
request.rpc_command = 'ledger_closed';
return request;
};
// Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning).
// Only for use by unit tests.
// Only for unit testing.
Remote.prototype.request_ledger_current = function () {
return new Request(this, 'ledger_current');
var request = new Request(this, 'rpc');
request.rpc_command = 'ledger_current';
return request;
};
// --> ledger : optional
@@ -494,7 +510,7 @@ Remote.prototype.request_ledger_entry = function (type) {
// Transparent caching:
request.on('request', function (remote) { // Intercept default request.
if (this.ledger_closed) {
if (this.ledger_hash) {
// XXX Add caching.
}
// else if (req.ledger_index)
@@ -540,18 +556,26 @@ Remote.prototype.request_ledger_entry = function (type) {
return request;
};
Remote.prototype.request_subscribe = function () {
var request = new Request(this, 'subscribe');
request.message.streams = [ 'ledger' ];
return request;
};
Remote.prototype.request_transaction_entry = function (hash) {
assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol.
return (new Request(this, 'transaction_entry'))
.transaction(hash);
.tx_hash(hash);
};
// Submit a transaction.
Remote.prototype.submit = function (transaction) {
var self = this;
if (this.trace) console.log("remote: submit: %s", JSON.stringify(transaction.transaction));
if (this.trace) console.log("remote: submit: %s", JSON.stringify(transaction.tx_json));
if (transaction.secret && !this.trusted)
{
@@ -561,14 +585,14 @@ Remote.prototype.submit = function (transaction) {
});
}
else {
if (!transaction.transaction.Sequence) {
transaction.transaction.Sequence = this.account_seq(transaction.transaction.Account, 'ADVANCE');
// console.log("Sequence: %s", transaction.transaction.Sequence);
if (!transaction.tx_json.Sequence) {
transaction.tx_json.Sequence = this.account_seq(transaction.tx_json.Account, 'ADVANCE');
// console.log("Sequence: %s", transaction.tx_json.Sequence);
}
if (!transaction.transaction.Sequence) {
if (!transaction.tx_json.Sequence) {
// Look in the last closed ledger.
this.account_seq_cache(transaction.transaction.Account, false)
this.account_seq_cache(transaction.tx_json.Account, false)
.on('success_account_seq_cache', function () {
// Try again.
self.submit(transaction);
@@ -577,7 +601,7 @@ Remote.prototype.submit = function (transaction) {
// XXX Maybe be smarter about this. Don't want to trust an untrusted server for this seq number.
// Look in the current ledger.
self.account_seq_cache(transaction.transaction.Account, 'CURRENT')
self.account_seq_cache(transaction.tx_json.Account, 'CURRENT')
.on('success_account_seq_cache', function () {
// Try again.
self.submit(transaction);
@@ -593,9 +617,12 @@ Remote.prototype.submit = function (transaction) {
else {
var submit_request = new Request(this, 'submit');
submit_request.transaction(transaction.transaction);
submit_request.tx_json(transaction.tx_json);
submit_request.secret(transaction.secret);
if (transaction.build_path)
submit_request.build_path = true;
// Forward successes and errors.
submit_request.on('success', function (message) { transaction.emit('success', message); });
submit_request.on('error', function (message) { transaction.emit('error', message); });
@@ -615,15 +642,16 @@ Remote.prototype.submit = function (transaction) {
Remote.prototype._server_subscribe = function () {
var self = this;
(new Request(this, 'server_subscribe'))
this.request_subscribe()
.on('success', function (message) {
self.stand_alone = !!message.stand_alone;
if (message.ledger_closed && message.ledger_current_index) {
self.ledger_closed = message.ledger_closed;
self.ledger_current_index = message.ledger_current_index;
if (message.ledger_hash && message.ledger_index) {
self.ledger_time = message.ledger_time;
self.ledger_hash = message.ledger_hash;
self.ledger_current_index = message.ledger_index+1;
self.emit('ledger_closed', self.ledger_closed, self.ledger_current_index-1);
self.emit('ledger_closed', self.ledger_hash, self.ledger_current_index-1);
}
self.emit('subscribed');
@@ -636,9 +664,9 @@ Remote.prototype._server_subscribe = function () {
};
// Ask the remote to accept the current ledger.
// - To be notified when the ledger is accepted, server_subscribe() then listen to 'ledger_closed' events.
// - To be notified when the ledger is accepted, server_subscribe() then listen to 'ledger_hash' events.
// A good way to be notified of the result of this is:
// remote.once('ledger_closed', function (ledger_closed, ledger_closed_index) { ... } );
// remote.once('ledger_closed', function (ledger_closed, ledger_index) { ... } );
Remote.prototype.ledger_accept = function () {
if (this.stand_alone || undefined === this.stand_alone)
{
@@ -840,7 +868,8 @@ var Transaction = function (remote) {
this.remote = remote;
this.secret = undefined;
this.transaction = { // Transaction data.
this.build_path = true;
this.tx_json = { // Transaction data.
'Flags' : 0, // XXX Would be nice if server did not require this.
};
this.hash = undefined;
@@ -849,12 +878,12 @@ var Transaction = function (remote) {
this.on('success', function (message) {
if (message.engine_result) {
self.hash = message.transaction.hash;
self.hash = message.tx_json.hash;
self.set_state('client_proposed');
self.emit('proposed', {
'transaction' : message.transaction,
'tx_json' : message.tx_json,
'result' : message.engine_result,
'result_code' : message.engine_result_code,
'result_message' : message.engine_result_message,
@@ -916,14 +945,14 @@ Transaction.prototype.set_state = function (state) {
};
// Submit a transaction to the network.
// XXX Don't allow a submit without knowing ledger_closed_index.
// XXX Don't allow a submit without knowing ledger_index.
// XXX Have a network canSubmit(), post events for following.
// XXX Also give broader status for tracking through network disconnects.
Transaction.prototype.submit = function () {
var self = this;
var transaction = this.transaction;
var self = this;
var tx_json = this.tx_json;
if ('string' !== typeof transaction.Account)
if ('string' !== typeof tx_json.Account)
{
this.emit('error', {
'error' : 'invalidAccount',
@@ -934,14 +963,14 @@ Transaction.prototype.submit = function () {
// YYY Might check paths for invalid accounts.
if (undefined === transaction.Fee) {
if ('Payment' === transaction.TransactionType
&& transaction.Flags & Remote.flags.Payment.CreateAccount) {
if (undefined === tx_json.Fee) {
if ('Payment' === tx_json.TransactionType
&& tx_json.Flags & Remote.flags.Payment.CreateAccount) {
transaction.Fee = Remote.fees.account_create.to_json();
tx_json.Fee = Remote.fees.account_create.to_json();
}
else {
transaction.Fee = Remote.fees['default'].to_json();
tx_json.Fee = Remote.fees['default'].to_json();
}
}
@@ -950,12 +979,12 @@ Transaction.prototype.submit = function () {
this.submit_index = this.remote.ledger_current_index;
var on_ledger_closed = function (ledger_closed, ledger_closed_index) {
var on_ledger_closed = function (ledger_hash, ledger_index) {
var stop = false;
// XXX make sure self.hash is available.
self.remote.request_transaction_entry(self.hash)
.ledger_closed(ledger_closed)
.ledger_closed(ledger_hash)
.on('success', function (message) {
self.set_state(message.metadata.TransactionResult);
self.emit('final', message);
@@ -963,12 +992,12 @@ Transaction.prototype.submit = function () {
.on('error', function (message) {
if ('remoteError' === message.error
&& 'transactionNotFound' === message.remote.error) {
if (self.submit_index + SUBMIT_LOST < ledger_closed_index) {
if (self.submit_index + SUBMIT_LOST < ledger_index) {
self.set_state('client_lost'); // Gave up.
self.emit('lost');
stop = true;
}
else if (self.submit_index + SUBMIT_MISSING < ledger_closed_index) {
else if (self.submit_index + SUBMIT_MISSING < ledger_index) {
self.set_state('client_missing'); // We don't know what happened to transaction, still might find.
self.emit('pending');
}
@@ -1000,6 +1029,12 @@ Transaction.prototype.submit = function () {
// Set options for Transactions
//
Transaction.prototype.build_path = function (build) {
this.build_path = build;
return this;
}
Transaction._path_rewrite = function (path) {
var path_new = [];
@@ -1023,8 +1058,8 @@ Transaction._path_rewrite = function (path) {
}
Transaction.prototype.path_add = function (path) {
this.transaction.Paths = this.transaction.Paths || []
this.transaction.Paths.push(Transaction._path_rewrite(path));
this.tx_json.Paths = this.tx_json.Paths || []
this.tx_json.Paths.push(Transaction._path_rewrite(path));
return this;
}
@@ -1046,16 +1081,16 @@ Transaction.prototype.secret = function (secret) {
Transaction.prototype.send_max = function (send_max) {
if (send_max)
this.transaction.SendMax = Amount.json_rewrite(send_max);
this.tx_json.SendMax = Amount.json_rewrite(send_max);
return this;
}
// --> rate: In billionths.
Transaction.prototype.transfer_rate = function (rate) {
this.transaction.TransferRate = Number(rate);
this.tx_json.TransferRate = Number(rate);
if (this.transaction.TransferRate < 1e9)
if (this.tx_json.TransferRate < 1e9)
throw 'invalidTransferRate';
return this;
@@ -1065,10 +1100,10 @@ Transaction.prototype.transfer_rate = function (rate) {
// --> flags: undefined, _flag_, or [ _flags_ ]
Transaction.prototype.set_flags = function (flags) {
if (flags) {
var transaction_flags = Remote.flags[this.transaction.TransactionType];
var transaction_flags = Remote.flags[this.tx_json.TransactionType];
if (undefined == this.transaction.Flags) // We plan to not define this field on new Transaction.
this.transaction.Flags = 0;
if (undefined == this.tx_json.Flags) // We plan to not define this field on new Transaction.
this.tx_json.Flags = 0;
var flag_set = 'object' === typeof flags ? flags : [ flags ];
@@ -1077,15 +1112,15 @@ Transaction.prototype.set_flags = function (flags) {
if (flag in transaction_flags)
{
this.transaction.Flags += transaction_flags[flag];
this.tx_json.Flags += transaction_flags[flag];
}
else {
// XXX Immediately report an error or mark it.
}
}
if (this.transaction.Flags & Remote.flags.Payment.CreateAccount)
this.transaction.Fee = Remote.fees.account_create.to_json();
if (this.tx_json.Flags & Remote.flags.Payment.CreateAccount)
this.tx_json.Fee = Remote.fees.account_create.to_json();
}
return this;
@@ -1106,43 +1141,43 @@ Transaction.prototype._account_secret = function (account) {
// .transfer_rate()
// .wallet_locator() NYI
Transaction.prototype.account_set = function (src) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'AccountSet';
this.transaction.Account = UInt160.json_rewrite(src);
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'AccountSet';
this.tx_json.Account = UInt160.json_rewrite(src);
return this;
};
Transaction.prototype.claim = function (src, generator, public_key, signature) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'Claim';
this.transaction.Generator = generator;
this.transaction.PublicKey = public_key;
this.transaction.Signature = signature;
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'Claim';
this.tx_json.Generator = generator;
this.tx_json.PublicKey = public_key;
this.tx_json.Signature = signature;
return this;
};
Transaction.prototype.offer_cancel = function (src, sequence) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'OfferCancel';
this.transaction.Account = UInt160.json_rewrite(src);
this.transaction.OfferSequence = Number(sequence);
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'OfferCancel';
this.tx_json.Account = UInt160.json_rewrite(src);
this.tx_json.OfferSequence = Number(sequence);
return this;
};
// --> expiration : Date or Number
Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expiration) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'OfferCreate';
this.transaction.Account = UInt160.json_rewrite(src);
this.transaction.Fee = Remote.fees.offer.to_json();
this.transaction.TakerPays = Amount.json_rewrite(taker_pays);
this.transaction.TakerGets = Amount.json_rewrite(taker_gets);
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'OfferCreate';
this.tx_json.Account = UInt160.json_rewrite(src);
this.tx_json.Fee = Remote.fees.offer.to_json();
this.tx_json.TakerPays = Amount.json_rewrite(taker_pays);
this.tx_json.TakerGets = Amount.json_rewrite(taker_gets);
if (expiration)
this.transaction.Expiration = Date === expiration.constructor
this.tx_json.Expiration = Date === expiration.constructor
? expiration.getTime()
: Number(expiration);
@@ -1150,20 +1185,20 @@ Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expi
};
Transaction.prototype.password_fund = function (src, dst) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'PasswordFund';
this.transaction.Destination = UInt160.json_rewrite(dst);
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'PasswordFund';
this.tx_json.Destination = UInt160.json_rewrite(dst);
return this;
}
Transaction.prototype.password_set = function (src, authorized_key, generator, public_key, signature) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'PasswordSet';
this.transaction.AuthorizedKey = authorized_key;
this.transaction.Generator = generator;
this.transaction.PublicKey = public_key;
this.transaction.Signature = signature;
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'PasswordSet';
this.tx_json.AuthorizedKey = authorized_key;
this.tx_json.Generator = generator;
this.tx_json.PublicKey = public_key;
this.tx_json.Signature = signature;
return this;
}
@@ -1178,34 +1213,35 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p
//
// Options:
// .paths()
// .build_path()
// .path_add()
// .secret()
// .send_max()
// .set_flags()
Transaction.prototype.payment = function (src, dst, deliver_amount) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'Payment';
this.transaction.Account = UInt160.json_rewrite(src);
this.transaction.Amount = Amount.json_rewrite(deliver_amount);
this.transaction.Destination = UInt160.json_rewrite(dst);
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'Payment';
this.tx_json.Account = UInt160.json_rewrite(src);
this.tx_json.Amount = Amount.json_rewrite(deliver_amount);
this.tx_json.Destination = UInt160.json_rewrite(dst);
return this;
}
Transaction.prototype.ripple_line_set = function (src, limit, quality_in, quality_out) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'CreditSet';
this.transaction.Account = UInt160.json_rewrite(src);
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'CreditSet';
this.tx_json.Account = UInt160.json_rewrite(src);
// Allow limit of 0 through.
if (undefined !== limit)
this.transaction.LimitAmount = Amount.json_rewrite(limit);
this.tx_json.LimitAmount = Amount.json_rewrite(limit);
if (quality_in)
this.transaction.QualityIn = quality_in;
this.tx_json.QualityIn = quality_in;
if (quality_out)
this.transaction.QualityOut = quality_out;
this.tx_json.QualityOut = quality_out;
// XXX Throw an error if nothing is set.
@@ -1213,12 +1249,12 @@ Transaction.prototype.ripple_line_set = function (src, limit, quality_in, qualit
};
Transaction.prototype.wallet_add = function (src, amount, authorized_key, public_key, signature) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'WalletAdd';
this.transaction.Amount = Amount.json_rewrite(amount);
this.transaction.AuthorizedKey = authorized_key;
this.transaction.PublicKey = public_key;
this.transaction.Signature = signature;
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'WalletAdd';
this.tx_json.Amount = Amount.json_rewrite(amount);
this.tx_json.AuthorizedKey = authorized_key;
this.tx_json.PublicKey = public_key;
this.tx_json.Signature = signature;
return this;
};

View File

@@ -42,7 +42,7 @@ Application::Application() :
mTempNodeCache("NodeCache", 16384, 90), mHashedObjectStore(16384, 300),
mSNTPClient(mAuxService), mRPCHandler(&mNetOps),
mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSDoor(NULL),
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL),
mSweepTimer(mAuxService)
{
RAND_bytes(mNonce256.begin(), mNonce256.size());
@@ -147,7 +147,7 @@ void Application::run()
}
else
{
std::cerr << "Peer interface: disabled" << std::endl;
cLog(lsINFO) << "Peer interface: disabled";
}
//
@@ -159,10 +159,32 @@ void Application::run()
}
else
{
std::cerr << "RPC interface: disabled" << std::endl;
cLog(lsINFO) << "RPC interface: disabled";
}
mWSDoor = WSDoor::createWSDoor();
//
// Allow private WS connections.
//
if (!theConfig.WEBSOCKET_IP.empty() && theConfig.WEBSOCKET_PORT)
{
mWSPrivateDoor = WSDoor::createWSDoor(theConfig.WEBSOCKET_IP, theConfig.WEBSOCKET_PORT, false);
}
else
{
cLog(lsINFO) << "WS private interface: disabled";
}
//
// Allow public WS connections.
//
if (!theConfig.WEBSOCKET_PUBLIC_IP.empty() && theConfig.WEBSOCKET_PUBLIC_PORT)
{
mWSPublicDoor = WSDoor::createWSDoor(theConfig.WEBSOCKET_PUBLIC_IP, theConfig.WEBSOCKET_PUBLIC_PORT, true);
}
else
{
cLog(lsINFO) << "WS public interface: disabled";
}
//
// Begin connecting to network.
@@ -181,9 +203,13 @@ void Application::run()
mIOService.run(); // This blocks
mWSDoor->stop();
if (mWSPublicDoor)
mWSPublicDoor->stop();
std::cout << "Done." << std::endl;
if (mWSPrivateDoor)
mWSPrivateDoor->stop();
cLog(lsINFO) << "Done.";
}
void Application::sweep()

View File

@@ -62,7 +62,8 @@ class Application
ConnectionPool mConnectionPool;
PeerDoor* mPeerDoor;
RPCDoor* mRPCDoor;
WSDoor* mWSDoor;
WSDoor* mWSPublicDoor;
WSDoor* mWSPrivateDoor;
uint256 mNonce256;
std::size_t mNonceST;

View File

@@ -30,6 +30,8 @@
#define SECTION_UNL_DEFAULT "unl_default"
#define SECTION_VALIDATION_QUORUM "validation_quorum"
#define SECTION_VALIDATION_SEED "validation_seed"
#define SECTION_WEBSOCKET_PUBLIC_IP "websocket_public_ip"
#define SECTION_WEBSOCKET_PUBLIC_PORT "websocket_public_port"
#define SECTION_WEBSOCKET_IP "websocket_ip"
#define SECTION_WEBSOCKET_PORT "websocket_port"
#define SECTION_VALIDATORS "validators"
@@ -124,6 +126,7 @@ void Config::setup(const std::string& strConf)
PEER_PORT = SYSTEM_PEER_PORT;
RPC_PORT = 5001;
WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT;
WEBSOCKET_PUBLIC_PORT = SYSTEM_WEBSOCKET_PUBLIC_PORT;
NUMBER_CONNECTIONS = 30;
// a new ledger every minute
@@ -235,6 +238,11 @@ void Config::load()
if (sectionSingleB(secConfig, SECTION_WEBSOCKET_PORT, strTemp))
WEBSOCKET_PORT = boost::lexical_cast<int>(strTemp);
(void) sectionSingleB(secConfig, SECTION_WEBSOCKET_PUBLIC_IP, WEBSOCKET_PUBLIC_IP);
if (sectionSingleB(secConfig, SECTION_WEBSOCKET_PUBLIC_PORT, strTemp))
WEBSOCKET_PUBLIC_PORT = boost::lexical_cast<int>(strTemp);
if (sectionSingleB(secConfig, SECTION_VALIDATION_SEED, strTemp))
{
VALIDATION_SEED.setSeedGeneric(strTemp);

View File

@@ -24,8 +24,9 @@
#define DEFAULT_VALIDATORS_SITE "redstem.com"
#define VALIDATORS_FILE_NAME "validators.txt"
const int SYSTEM_PEER_PORT = 6561;
const int SYSTEM_WEBSOCKET_PORT = 6562;
const int SYSTEM_PEER_PORT = 6561;
const int SYSTEM_WEBSOCKET_PORT = 6562;
const int SYSTEM_WEBSOCKET_PUBLIC_PORT = 6563; // XXX Going away.
// Allow anonymous DH.
#define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH"
@@ -82,6 +83,9 @@ public:
unsigned int PEER_CONNECT_LOW_WATER;
// Websocket networking parameters
std::string WEBSOCKET_PUBLIC_IP; // XXX Going away. Merge with the inbound peer connction.
int WEBSOCKET_PUBLIC_PORT;
std::string WEBSOCKET_IP;
int WEBSOCKET_PORT;

View File

@@ -917,12 +917,12 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri
{
Json::Value jvObj(Json::objectValue);
jvObj["type"] = "accountInfoBootstrap";
jvObj["account"] = naAccountID.humanAccountID();
jvObj["owner"] = getOwnerInfo(lpAccepted, naAccountID);
jvObj["ledger_closed_index"] = lpAccepted->getLedgerSeq();
jvObj["ledger_closed"] = lpAccepted->getHash().ToString();
jvObj["ledger_closed_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
jvObj["type"] = "accountInfoBootstrap";
jvObj["account"] = naAccountID.humanAccountID();
jvObj["owner"] = getOwnerInfo(lpAccepted, naAccountID);
jvObj["ledger_index"] = lpAccepted->getLedgerSeq();
jvObj["ledger_hash"] = lpAccepted->getHash().ToString();
jvObj["ledger_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
return jvObj;
}
@@ -930,7 +930,7 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri
void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
{
Json::Value jvObj = transJson(stTxn, terResult, false, lpCurrent, "transaction");
{
boost::interprocess::sharable_lock<boost::interprocess::interprocess_upgradable_mutex> sl(mMonitorLock);
BOOST_FOREACH(InfoSub* ispListener, mSubRTTransactions)
@@ -956,10 +956,10 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
{
Json::Value jvObj(Json::objectValue);
jvObj["type"] = "ledgerClosed";
jvObj["ledger_closed_index"] = lpAccepted->getLedgerSeq();
jvObj["ledger_closed"] = lpAccepted->getHash().ToString();
jvObj["ledger_closed_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
jvObj["type"] = "ledgerClosed";
jvObj["ledger_index"] = lpAccepted->getLedgerSeq();
jvObj["ledger_hash"] = lpAccepted->getHash().ToString();
jvObj["ledger_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
BOOST_FOREACH(InfoSub* ispListener, mSubLedger)
{
@@ -967,7 +967,7 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
}
}
}
{
// we don't lock since pubAcceptedTransaction is locking
if (!mSubTransactions.empty() || !mSubRTTransactions.empty() || !mSubAccount.empty() || !mSubRTAccount.empty() || !mSubmitMap.empty() )
@@ -986,8 +986,6 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
// TODO: remove old entries from the submit map
}
}
}
Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terResult, bool bAccepted, Ledger::ref lpCurrent, const std::string& strType)
@@ -1001,8 +999,8 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes
jvObj["type"] = strType;
jvObj["transaction"] = stTxn.getJson(0);
if (bAccepted) {
jvObj["ledger_closed_index"] = lpCurrent->getLedgerSeq();
jvObj["ledger_closed"] = lpCurrent->getHash().ToString();
jvObj["ledger_index"] = lpCurrent->getLedgerSeq();
jvObj["ledger_hash"] = lpCurrent->getHash().ToString();
}
else
{
@@ -1032,7 +1030,7 @@ void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedT
ispListener->send(jvObj);
}
}
pubAccountTransaction(lpCurrent,stTxn,terResult,true);
}
@@ -1181,8 +1179,12 @@ void NetworkOPs::unsubAccountChanges(InfoSub* ispListener)
#endif
// <-- bool: true=added, false=already there
bool NetworkOPs::subLedger(InfoSub* ispListener)
bool NetworkOPs::subLedger(InfoSub* ispListener, Json::Value& jvResult)
{
jvResult["ledger_index"] = getClosedLedger()->getLedgerSeq();
jvResult["ledger_hash"] = getClosedLedger()->getHash().ToString();
jvResult["ledger_time"] = Json::Value::UInt(utFromSeconds(getClosedLedger()->getCloseTimeNC()));
return mSubLedger.insert(ispListener).second;
}

View File

@@ -74,8 +74,8 @@ protected:
// XXX Split into more locks.
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
subInfoMapType mSubAccount;
subInfoMapType mSubRTAccount;
subInfoMapType mSubAccount;
subInfoMapType mSubRTAccount;
subSubmitMapType mSubmitMap;
boost::unordered_set<InfoSub*> mSubLedger; // accepted ledgers
@@ -111,11 +111,12 @@ public:
return mMode >= omTRACKING;
}
Ledger::pointer getClosedLedger() { return mLedgerMaster->getClosedLedger(); }
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()
uint256 getClosedLedgerHash()
{ return mLedgerMaster->getClosedLedger()->getHash(); }
SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); }
@@ -224,7 +225,7 @@ public:
void subAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt);
void unsubAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt);
bool subLedger(InfoSub* ispListener);
bool subLedger(InfoSub* ispListener, Json::Value& jvResult);
bool unsubLedger(InfoSub* ispListener);
bool subServer(InfoSub* ispListener);

View File

@@ -13,7 +13,7 @@
#include <boost/foreach.hpp>
#include <openssl/md5.h>
/*
carries out the RPC
carries out the RPC
*/
@@ -341,7 +341,7 @@ Json::Value RPCHandler::doAccountInfo(const Json::Value &params)
// Get info on account.
uint256 uAccepted = mNetOps->getClosedLedger();
uint256 uAccepted = mNetOps->getClosedLedgerHash();
Json::Value jAccepted = accountFromString(uAccepted, naAccount, bIndex, strIdent, iIndex);
if (jAccepted.empty())
@@ -507,7 +507,7 @@ Json::Value RPCHandler::doOwnerInfo(const Json::Value& params)
// Get info on account.
uint256 uAccepted = mNetOps->getClosedLedger();
uint256 uAccepted = mNetOps->getClosedLedgerHash();
Json::Value jAccepted = accountFromString(uAccepted, naAccount, bIndex, strIdent, iIndex);
ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted;
@@ -621,7 +621,7 @@ Json::Value RPCHandler::doProfile(const Json::Value &params)
// ripple_lines_get <account>|<nickname>|<account_public_key> [<index>]
Json::Value RPCHandler::doRippleLinesGet(const Json::Value &params)
{
// uint256 uAccepted = mNetOps->getClosedLedger();
// uint256 uAccepted = mNetOps->getClosedLedgerHash();
std::string strIdent = params[0u].asString();
bool bIndex;
@@ -694,20 +694,26 @@ Json::Value RPCHandler::doSubmit(const Json::Value& params)
Json::Reader reader;
if(reader.parse(params[1u].asString(),txJSON))
{
return handleJSONSubmit(params[0u].asString(), txJSON);
Json::Value jvRequest;
jvRequest["secret"] = params[0u].asString();
jvRequest["tx_json"] = txJSON;
return handleJSONSubmit(jvRequest);
}
return rpcError(rpcSRC_ACT_MALFORMED);
}
Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& txJSON)
Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest)
{
Json::Value jvResult;
Json::Value jvResult;
RippleAddress naSeed;
RippleAddress srcAddress;
Json::Value txJSON = jvResult["tx_json"];
if (!naSeed.setSeedGeneric(key))
if (!naSeed.setSeedGeneric(jvResult["secret"].asString()))
{
return rpcError(rpcBAD_SEED);
}
@@ -727,6 +733,11 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
txJSON["TransactionType"]=0;
RippleAddress dstAccountID;
if (!txJSON.isMember("Destination"))
{
return rpcError(rpcDST_ACT_MISSING);
}
if (!dstAccountID.setAccountID(txJSON["Destination"].asString()))
{
return rpcError(rpcDST_ACT_MALFORMED);
@@ -738,7 +749,8 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
txJSON["Fee"]=(int)theConfig.FEE_DEFAULT;
else txJSON["Fee"]=(int)theConfig.FEE_ACCOUNT_CREATE;
}
if(!txJSON.isMember("Paths"))
if(!txJSON.isMember("Paths") && (!jvRequest.isMember("build_path") || jvRequest["build_path"].asBool()))
{
if(txJSON["Amount"].isObject() || txJSON.isMember("SendMax") )
{ // we need a ripple path
@@ -746,8 +758,12 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
uint160 srcCurrencyID;
if(txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency"))
{
STAmount::currencyFromString(srcCurrencyID, "XRP");
}else STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString());
STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString());
}
else
{
srcCurrencyID = CURRENCY_XRP;
}
STAmount dstAmount;
if(txJSON["Amount"].isObject())
@@ -804,7 +820,7 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
RippleAddress naAuthorizedPublic;
RippleAddress naSecret = RippleAddress::createSeedGeneric(key);
RippleAddress naSecret = RippleAddress::createSeedGeneric(jvResult["secret"].asString());
RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic(naSecret);
// Find the index of Account from the master generator, so we can generate the public and private keys.
@@ -858,7 +874,7 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
{
jvResult["error"] = "malformedTransaction";
jvResult["error_exception"] = e.what();
return(jvResult);
return jvResult;
}
sopTrans->setFieldVL(sfSigningPubKey, naAccountPublic.getAccountPublic());
@@ -888,7 +904,7 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
{
jvResult["error"] = "internalTransaction";
jvResult["error_exception"] = e.what();
return(jvResult);
return jvResult;
}
try
@@ -898,19 +914,19 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
if (!tpTrans) {
jvResult["error"] = "invalidTransaction";
jvResult["error_exception"] = "Unable to sterilize transaction.";
return(jvResult);
return jvResult;
}
}
catch (std::exception& e)
{
jvResult["error"] = "internalSubmit";
jvResult["error_exception"] = e.what();
return(jvResult);
return jvResult;
}
try
{
jvResult["transaction"] = tpTrans->getJson(0);
jvResult["tx_json"] = tpTrans->getJson(0);
if (temUNCERTAIN != tpTrans->getResult())
{
@@ -923,15 +939,14 @@ Json::Value RPCHandler::handleJSONSubmit(const std::string& key, Json::Value& tx
jvResult["engine_result_code"] = tpTrans->getResult();
jvResult["engine_result_message"] = sHuman;
}
return(jvResult);
return jvResult;
}
catch (std::exception& e)
{
jvResult["error"] = "internalJson";
jvResult["error_exception"] = e.what();
return(jvResult);
return jvResult;
}
}
Json::Value RPCHandler::doServerInfo(const Json::Value& params)
@@ -1005,11 +1020,11 @@ Json::Value RPCHandler::doTx(const Json::Value& params)
Json::Value RPCHandler::doLedgerClosed(const Json::Value& params)
{
Json::Value jvResult;
uint256 uLedger = mNetOps->getClosedLedger();
uint256 uLedger = mNetOps->getClosedLedgerHash();
jvResult["ledger_closed_index"] = mNetOps->getLedgerID(uLedger);
jvResult["ledger_closed"] = uLedger.ToString();
//jvResult["ledger_closed_time"] = uLedger.
jvResult["ledger_index"] = mNetOps->getLedgerID(uLedger);
jvResult["ledger_hash"] = uLedger.ToString();
//jvResult["ledger_time"] = uLedger.
return jvResult;
}
@@ -1358,7 +1373,7 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
{
return rpcError(rpcNO_CURRENT);
}
else if ((commandsA[i].iOptions & optClosed) && mNetOps->getClosedLedger().isZero())
else if ((commandsA[i].iOptions & optClosed) && !mNetOps->getClosedLedger())
{
return rpcError(rpcNO_CLOSED);
}
@@ -1603,7 +1618,6 @@ Json::Value RPCHandler::doLedgerAccept(const Json::Value& )
return(jvResult);
}
Json::Value RPCHandler::doTransactionEntry(const Json::Value& params)
{
Json::Value jvResult;
@@ -1640,26 +1654,24 @@ Json::Value RPCHandler::doTransactionEntry(const Json::Value& params)
Transaction::pointer tpTrans;
TransactionMetaSet::pointer tmTrans;
if (!lpLedger-> getTransaction(uTransID, tpTrans, tmTrans))
if (!lpLedger->getTransaction(uTransID, tpTrans, tmTrans))
{
jvResult["error"] = "transactionNotFound";
}
else
{
jvResult["transaction"] = tpTrans->getJson(0);
jvResult["metadata"] = tmTrans->getJson(0);
jvResult["tx_json"] = tpTrans->getJson(0);
jvResult["metadata"] = tmTrans->getJson(0);
// 'accounts'
// 'engine_...'
// 'ledger_...'
}
}
}
return jvResult;
}
Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
{
Json::Value jvResult;
@@ -1667,9 +1679,8 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
Json::Reader reader;
if(!reader.parse(params[0u].asString(),jvRequest))
return rpcError(rpcINVALID_PARAMS);
uint256 uLedger = jvRequest.isMember("ledger_closed") ? uint256(jvRequest["ledger_closed"].asString()) : 0;
uint256 uLedger = jvRequest.isMember("ledger_hash") ? uint256(jvRequest["ledger_hash"].asString()) : 0;
uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0;
Ledger::pointer lpLedger;
@@ -1707,9 +1718,9 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
if (lpLedger->isClosed())
{
if (!!uLedger)
jvResult["ledger_closed"] = uLedger.ToString();
jvResult["ledger_hash"] = uLedger.ToString();
jvResult["ledger_closed_index"] = uLedgerIndex;
jvResult["ledger_index"] = uLedgerIndex;
}
else
{

View File

@@ -154,7 +154,7 @@ public:
Json::Value doCommand(const std::string& command, Json::Value& params,int role);
Json::Value rpcError(int iError);
Json::Value handleJSONSubmit(const std::string& key, Json::Value& txJSON);
Json::Value handleJSONSubmit(const Json::Value& jvRequest);
};

View File

@@ -143,13 +143,13 @@ void WSConnection::doSubscribe(Json::Value& jvResult, Json::Value& jvRequest)
mNetwork.subServer(this);
}else if(streamName=="ledger")
{
mNetwork.subLedger(this);
mNetwork.subLedger(this, jvResult);
}else if(streamName=="transactions")
{
mNetwork.subTransactions(this);
}else if(streamName=="rt_transactions")
{
mNetwork.subRTTransactions(this);
mNetwork.subRTTransactions(this);
}else
{
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
@@ -223,7 +223,7 @@ void WSConnection::doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest)
mNetwork.unsubTransactions(this);
}else if(streamName=="rt_transactions")
{
mNetwork.unsubRTTransactions(this);
mNetwork.unsubRTTransactions(this);
}else
{
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
@@ -276,13 +276,14 @@ void WSConnection::doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest)
}
}
void WSConnection::doRPC(Json::Value& jvResult, Json::Value& jvRequest)
{
if (jvRequest.isMember("rpc_command") )
{
jvResult=theApp->getRPCHandler().doCommand(jvRequest["rpc_command"].asString(),jvRequest["params"],RPCHandler::GUEST);
jvResult=theApp->getRPCHandler().doCommand(
jvRequest["rpc_command"].asString(),
jvRequest["params"],
mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
}else jvResult["error"] = "fieldNotCommand";
@@ -293,15 +294,16 @@ void WSConnection::doSubmit(Json::Value& jvResult, Json::Value& jvRequest)
{
if (!jvRequest.isMember("tx_json"))
{
jvResult["error"] = "fieldNotFoundTransaction";
}else if (!jvRequest.isMember("key"))
jvResult["error"] = "fieldNotFoundTxJson";
}else if (!jvRequest.isMember("secret"))
{
jvResult["error"] = "fieldNotFoundKey";
}else
jvResult["error"] = "fieldNotFoundSecret";
}else
{
jvResult=theApp->getRPCHandler().handleJSONSubmit(jvRequest["key"].asString(),jvRequest["tx_json"]);
jvResult=theApp->getRPCHandler().handleJSONSubmit(jvRequest);
// TODO: track the transaction mNetwork.subSubmit(this, jvResult["tx hash"] );
}
}
// vim:ts=4

View File

@@ -52,4 +52,6 @@ public:
void doSubscribe(Json::Value& jvResult, Json::Value& jvRequest);
void doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest);
};
};
// vim:ts=4

View File

@@ -40,10 +40,6 @@ static DH* handleTmpDh(SSL* ssl, int is_export, int iKeyLength)
return 512 == iKeyLength ? theApp->getWallet().getDh512() : theApp->getWallet().getDh1024();
}
void WSDoor::startListening()
{
// Generate a single SSL context for use by all connections.
@@ -58,7 +54,7 @@ void WSDoor::startListening()
SSL_CTX_set_tmp_dh_callback(mCtx->native_handle(), handleTmpDh);
// Construct a single handler for all requests.
websocketpp::WSDOOR_SERVER::handler::ptr handler(new WSServerHandler<websocketpp::WSDOOR_SERVER>(mCtx));
websocketpp::WSDOOR_SERVER::handler::ptr handler(new WSServerHandler<websocketpp::WSDOOR_SERVER>(mCtx, mPublic));
// Construct a websocket server.
mEndpoint = new websocketpp::WSDOOR_SERVER(handler);
@@ -69,25 +65,22 @@ void WSDoor::startListening()
// Call the main-event-loop of the websocket server.
mEndpoint->listen(
boost::asio::ip::tcp::endpoint(
boost::asio::ip::address().from_string(theConfig.WEBSOCKET_IP), theConfig.WEBSOCKET_PORT));
boost::asio::ip::address().from_string(mIp), mPort));
delete mEndpoint;
}
WSDoor* WSDoor::createWSDoor()
WSDoor* WSDoor::createWSDoor(const std::string& strIp, const int iPort, bool bPublic)
{
WSDoor* wdpResult = new WSDoor();
WSDoor* wdpResult = new WSDoor(strIp, iPort, bPublic);
if (!theConfig.WEBSOCKET_IP.empty() && theConfig.WEBSOCKET_PORT)
{
Log(lsINFO) << "Websocket: Listening: " << theConfig.WEBSOCKET_IP << " " << theConfig.WEBSOCKET_PORT;
cLog(lsINFO) <<
boost::str(boost::format("Websocket: %s: Listening: %s %d ")
% (bPublic ? "Public" : "Private")
% strIp
% iPort);
wdpResult->mThread = new boost::thread(boost::bind(&WSDoor::startListening, wdpResult));
}
else
{
Log(lsINFO) << "Websocket: Disabled";
}
wdpResult->mThread = new boost::thread(boost::bind(&WSDoor::startListening, wdpResult));
return wdpResult;
}

View File

@@ -21,16 +21,19 @@ class WSDoor
private:
websocketpp::WSDOOR_SERVER* mEndpoint;
boost::thread* mThread;
bool mPublic;
std::string mIp;
int mPort;
void startListening();
public:
WSDoor() : mEndpoint(0), mThread(0) { ; }
WSDoor(const std::string& strIp, int iPort, bool bPublic) : mEndpoint(0), mThread(0), mPublic(bPublic), mIp(strIp), mPort(iPort) { ; }
void stop();
static WSDoor* createWSDoor();
static WSDoor* createWSDoor(const std::string& strIp, const int iPort, bool bPublic);
};
#endif

View File

@@ -18,15 +18,18 @@ public:
};
private:
boost::shared_ptr<boost::asio::ssl::context> mCtx;
boost::shared_ptr<boost::asio::ssl::context> mCtx;
protected:
boost::mutex mMapLock;
boost::mutex mMapLock;
// For each connection maintain an associated object to track subscriptions.
boost::unordered_map<connection_ptr, boost::shared_ptr<WSConnection> > mMap;
bool mPublic;
public:
WSServerHandler(boost::shared_ptr<boost::asio::ssl::context> spCtx) : mCtx(spCtx) {}
WSServerHandler(boost::shared_ptr<boost::asio::ssl::context> spCtx, bool bPublic) : mCtx(spCtx), mPublic(bPublic) {}
bool getPublic() { return mPublic; };
boost::shared_ptr<boost::asio::ssl::context> on_tls_init()
{
@@ -87,6 +90,8 @@ public:
Json::Value jvRequest;
Json::Reader jrReader;
cLog(lsDEBUG) << "Ws:: Receiving '" << mpMessage->get_payload() << "'";
if (mpMessage->get_opcode() != websocketpp::frame::opcode::TEXT)
{
Json::Value jvResult(Json::objectValue);
@@ -122,3 +127,5 @@ public:
};
#endif
// vim:ts=4