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

This commit is contained in:
JoelKatz
2012-10-08 00:01:41 -07:00
4 changed files with 229 additions and 35 deletions

View File

@@ -12,11 +12,12 @@ var util = require('util');
var WebSocket = require('ws');
// --> trusted: truthy, if remote is trusted
var Remote = function (trusted, websocket_ip, websocket_port, trace) {
var Remote = function (trusted, websocket_ip, websocket_port, config, trace) {
this.trusted = trusted;
this.websocket_ip = websocket_ip;
this.websocket_port = websocket_port;
this.id = 0;
this.config = config;
this.trace = trace;
this.ledger_closed = undefined;
this.ledger_current_index = undefined;
@@ -40,7 +41,18 @@ var Remote = function (trusted, websocket_ip, websocket_port, trace) {
var remoteConfig = function (config, server, trace) {
var serverConfig = config.servers[server];
return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace);
return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, config, trace);
};
var flags = {
// OfferCreate flags:
'tfPassive' : 0x00010000,
// Payment flags:
'tfCreateAccount' : 0x00010000,
'tfPartialPayment' : 0x00020000,
'tfLimitQuality' : 0x00040000,
'tfNoRippleDirect' : 0x00080000,
};
// XXX This needs to be determined from the network.
@@ -257,13 +269,10 @@ Remote.method('request_ledger_entry', function (req, onDone, onFailure) {
// Submit a json transaction.
// done(value)
// XXX <-> value: { 'status', status, 'result' : result, ... }
Remote.method('submit', function (request, onDone, onFailure) {
if (this.trace) console.log("remote: submit: %s", request);
Remote.method('submit', function (req, onDone, onFailure) {
if (this.trace) console.log("remote: submit: %s", JSON.stringify(req));
var req = {};
req.command = 'submit';
req.request = request;
if (req.secret && !this.trusted)
{
@@ -308,7 +317,7 @@ Remote.method('account_seq', function (account, advance, onDone, onFailure) {
if (advance) account_root_entry.seq += 1;
onDone(advance);
onDone(seq);
}
else
{
@@ -323,9 +332,9 @@ Remote.method('account_seq', function (account, advance, onDone, onFailure) {
// Extract the seqence number from the account root entry.
var seq = node.Sequence;
if (!self.accounts[account]) self.accounts[account] = {};
if (!account_root_entry) self.accounts[account] = {};
self.accounts[account].seq = seq + 1;
self.accounts[account].seq = seq + !!advance;
onDone(seq);
},
@@ -335,14 +344,14 @@ Remote.method('account_seq', function (account, advance, onDone, onFailure) {
});
// A submit that fills in the sequence number.
Remote.method('submit_seq', function (transaction, onDirty, onDone, onFailure) {
Remote.method('submit_seq', function (trans, onDirty, onDone, onFailure) {
var self = this;
// Get the next sequence number for the account.
this.account_seq(transaction.fields.Signer, true,
this.account_seq(trans.transaction.Account, true,
function (seq) {
transaction.seq = seq;
self.submit(transaction, onDone, onFailure);
trans.transaction.Sequence = seq;
self.submit(trans, onDone, onFailure);
},
onFailure);
});
@@ -352,8 +361,33 @@ Remote.method('dirty_account_root', function (account) {
delete this.ledgers.current.account_root.account;
});
//
// Transactions
//
Remote.method('send_xns', function (secret, src, dst, amount, create, onDone) {
var secret = this.config.accounts[src] ? this.config.accounts[src].secret : secret;
var src_account = this.config.accounts[src] ? this.config.accounts[src].account : src;
var dst_account = this.config.accounts[dst] ? this.config.accounts[dst].account : dst;
this.submit_seq(
{
'transaction' : {
'TransactionType' : 'Payment',
'Account' : src_account,
'Destination' : dst_account,
'Fee' : create ? fees.account_create : fees['default'],
'Flags' : create ? flags.tfCreateAccount : 0,
'Amount' : amount,
},
'secret' : secret,
}, function () {
}, onDone);
});
exports.Remote = Remote;
exports.remoteConfig = remoteConfig;
exports.fees = fees;
exports.flags = flags;
// vim:sw=2:sts=2:ts=8

View File

@@ -5,7 +5,6 @@
#include "Config.h"
#include "Log.h"
#include "NetworkOPs.h"
#include "NetworkOPs.h"
#include "utils.h"
#include <iostream>
@@ -60,14 +59,15 @@ protected:
WSServerHandler<websocketpp::WSDOOR_SERVER>* mHandler;
connection_ptr mConnection;
NetworkOPs& mNetwork;
public:
WSConnection()
: mHandler((WSServerHandler<websocketpp::WSDOOR_SERVER>*)(NULL)),
mConnection(connection_ptr()) { ; }
// WSConnection()
// : mHandler((WSServerHandler<websocketpp::WSDOOR_SERVER>*)(NULL)),
// mConnection(connection_ptr()) { ; }
WSConnection(WSServerHandler<websocketpp::WSDOOR_SERVER>* wshpHandler, connection_ptr cpConnection)
: mHandler(wshpHandler), mConnection(cpConnection) { ; }
: mHandler(wshpHandler), mConnection(cpConnection), mNetwork(theApp->getOPs()) { ; }
virtual ~WSConnection();
@@ -82,6 +82,7 @@ public:
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);
void doSubmit(Json::Value& jvResult, const Json::Value& jvRequest);
// Streaming Commands
void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest);
@@ -305,6 +306,7 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest)
{ "ledger_closed", &WSConnection::doLedgerClosed },
{ "ledger_current", &WSConnection::doLedgerCurrent },
{ "ledger_entry", &WSConnection::doLedgerEntry },
{ "submit", &WSConnection::doSubmit },
// Streaming commands:
{ "account_info_subscribe", &WSConnection::doAccountInfoSubscribe },
@@ -422,7 +424,7 @@ void WSConnection::doAccountInfoSubscribe(Json::Value& jvResult, const Json::Val
mSubAccountInfo.insert(naAccountID);
}
theApp->getOPs().subAccountInfo(this, usnaAccoundIds);
mNetwork.subAccountInfo(this, usnaAccoundIds);
}
}
}
@@ -454,7 +456,7 @@ void WSConnection::doAccountInfoUnsubscribe(Json::Value& jvResult, const Json::V
mSubAccountInfo.erase(naAccountID);
}
theApp->getOPs().unsubAccountInfo(this, usnaAccoundIds);
mNetwork.unsubAccountInfo(this, usnaAccoundIds);
}
}
}
@@ -486,7 +488,7 @@ void WSConnection::doAccountTransactionSubscribe(Json::Value& jvResult, const Js
mSubAccountTransaction.insert(naAccountID);
}
theApp->getOPs().subAccountTransaction(this, usnaAccoundIds);
mNetwork.subAccountTransaction(this, usnaAccoundIds);
}
}
}
@@ -518,14 +520,14 @@ void WSConnection::doAccountTransactionUnsubscribe(Json::Value& jvResult, const
mSubAccountTransaction.erase(naAccountID);
}
theApp->getOPs().unsubAccountTransaction(this, usnaAccoundIds);
mNetwork.unsubAccountTransaction(this, usnaAccoundIds);
}
}
}
void WSConnection::doLedgerAccountsSubcribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().subLedgerAccounts(this))
if (!mNetwork.subLedgerAccounts(this))
{
jvResult["error"] = "ledgerAccountsSubscribed";
}
@@ -533,7 +535,7 @@ void WSConnection::doLedgerAccountsSubcribe(Json::Value& jvResult, const Json::V
void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().unsubLedgerAccounts(this))
if (!mNetwork.unsubLedgerAccounts(this))
{
jvResult["error"] = "ledgerAccountsNotSubscribed";
}
@@ -541,20 +543,20 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json
void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest)
{
uint256 uLedger = theApp->getOPs().getClosedLedger();
uint256 uLedger = mNetwork.getClosedLedger();
jvResult["ledger_closed_index"] = theApp->getOPs().getLedgerID(uLedger);
jvResult["ledger_closed_index"] = mNetwork.getLedgerID(uLedger);
jvResult["ledger_closed"] = uLedger.ToString();
}
void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest)
{
jvResult["ledger_current_index"] = theApp->getOPs().getCurrentLedgerID();
jvResult["ledger_current_index"] = mNetwork.getCurrentLedgerID();
}
void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest)
{
NetworkOPs& noNetwork = theApp->getOPs();
NetworkOPs& noNetwork = mNetwork;
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;
@@ -781,7 +783,7 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq
void WSConnection::doServerSubscribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().subLedger(this))
if (!mNetwork.subLedger(this))
{
jvResult["error"] = "serverSubscribed";
}
@@ -792,22 +794,169 @@ void WSConnection::doServerSubscribe(Json::Value& jvResult, const Json::Value& j
// XXX Make sure these values are available before returning them.
// XXX return connected status.
jvResult["ledger_closed"] = theApp->getOPs().getClosedLedger().ToString();
jvResult["ledger_current_index"] = theApp->getOPs().getCurrentLedgerID();
jvResult["ledger_closed"] = mNetwork.getClosedLedger().ToString();
jvResult["ledger_current_index"] = mNetwork.getCurrentLedgerID();
}
}
void WSConnection::doServerUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().unsubLedger(this))
if (!mNetwork.unsubLedger(this))
{
jvResult["error"] = "serverNotSubscribed";
}
}
// XXX Current requires secret. Allow signed transaction as an alternative.
void WSConnection::doSubmit(Json::Value& jvResult, const Json::Value& jvRequest)
{
NewcoinAddress naAccount;
if (!jvRequest.isMember("transaction"))
{
jvResult["error"] = "fieldNotFoundTransaction";
}
else if (!jvRequest["transaction"].isMember("Account"))
{
jvResult["error"] = "fieldNotFoundAccount";
}
else if (!naAccount.setAccountID(jvRequest["transaction"]["Account"].asString()))
{
jvResult["error"] = "malformedAccount";
}
else if (!jvRequest.isMember("secret"))
{
jvResult["error"] = "fieldNotFoundSecret";
}
else
{
Ledger::pointer lpCurrent = mNetwork.getCurrentLedger();
SLE::pointer sleAccountRoot = mNetwork.getSLE(lpCurrent, Ledger::getAccountRootIndex(naAccount.getAccountID()));
if (!sleAccountRoot)
{
// XXX Ignore transactions for accounts not created.
jvResult["error"] = "accountNotFound";
return;
}
bool bHaveAuthKey = false;
NewcoinAddress naAuthorizedPublic;
#if 0
if (sleAccountRoot->isFieldPresent(sfAuthorizedKey))
{
naAuthorizedPublic = mLedgerEntry->getFieldAccount(sfAuthorizedKey);
// Json::Value obj = getMasterGenerator(uLedger, naRegularSeed, naMasterGenerator);
}
#endif
NewcoinAddress naSecret = NewcoinAddress::createSeedGeneric(jvRequest["secret"].asString());
NewcoinAddress naMasterGenerator = NewcoinAddress::createGeneratorPublic(naSecret);
// Find the index of Account from the master generator, so we can generate the public and private keys.
NewcoinAddress naMasterAccountPublic;
unsigned int iIndex = 0;
bool bFound = false;
// Don't look at ledger entries to determine if the account exists. Don't want to leak to thin server that these accounts are
// related.
while (!bFound && iIndex != theConfig.ACCOUNT_PROBE_MAX)
{
naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
Log(lsWARNING) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naAccount.humanAccountID();
bFound = naAccount.getAccountID() == naMasterAccountPublic.getAccountID();
if (!bFound)
++iIndex;
}
if (!bFound)
{
jvResult["error"] = "accountNotMatched";
return;
}
// Use the generator to determine the associated public and private keys.
NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naSecret);
NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(naGenerator, iIndex);
NewcoinAddress naAccountPrivate = NewcoinAddress::createAccountPrivate(naGenerator, naSecret, iIndex);
if (bHaveAuthKey
// The generated pair must match authorized...
&& naAuthorizedPublic.getAccountID() != naAccountPublic.getAccountID()
// ... or the master key must have been used.
&& naAccount.getAccountID() != naAccountPublic.getAccountID())
{
// std::cerr << "iIndex: " << iIndex << std::endl;
// std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl;
// std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl;
jvResult["error"] = "passwordChanged";
return;
}
std::auto_ptr<STObject> sopTrans;
try
{
sopTrans = STObject::parseJson(jvRequest["transaction"]);
}
catch (std::exception& e)
{
jvResult["error"] = "malformedTransaction";
jvResult["error_exception"] = e.what();
return;
}
sopTrans->setFieldVL(sfSigningPubKey, naAccountPublic.getAccountPublic());
SerializedTransaction::pointer stpTrans = boost::make_shared<SerializedTransaction>(*sopTrans);
stpTrans->sign(naAccountPrivate);
Transaction::pointer tpTrans;
try
{
tpTrans = boost::make_shared<Transaction>(stpTrans, false);
}
catch (std::exception& e)
{
jvResult["error"] = "internalTransaction";
jvResult["error_exception"] = e.what();
return;
}
try
{
tpTrans = mNetwork.submitTransaction(tpTrans);
}
catch (std::exception& e)
{
jvResult["error"] = "internalSubmit";
jvResult["error_exception"] = e.what();
return;
}
try
{
jvResult["submitted"] = tpTrans->getJson(0);
}
catch (std::exception& e)
{
jvResult["error"] = "internalJson";
jvResult["error_exception"] = e.what();
return;
}
}
}
void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().subTransaction(this))
if (!mNetwork.subTransaction(this))
{
jvResult["error"] = "TransactionsSubscribed";
}
@@ -815,7 +964,7 @@ void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Valu
void WSConnection::doTransactionUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest)
{
if (!theApp->getOPs().unsubTransaction(this))
if (!mNetwork.unsubTransaction(this))
{
jvResult["error"] = "TransactionsNotSubscribed";
}

View File

@@ -52,6 +52,7 @@ Server.method('serverSpawnSync', function() {
config.newcoind,
[
"-a",
"-v",
"--conf=newcoind.cfg"
],
{

View File

@@ -184,6 +184,16 @@ buster.testCase("Websocket commands", {
});
});
},
'create account' :
function (done) {
alpha.send_xns(undefined, 'root', 'alice', 10000, true, function (r) {
console.log(r);
buster.refute(r.error);
done();
});
},
});
// vim:sw=2:sts=2:ts=8