#include #include #include #include #include #include "../json/reader.h" #include "../json/writer.h" #include "RPCServer.h" #include "RequestParser.h" #include "HttpReply.h" #include "HttpsClient.h" #include "Application.h" #include "RPC.h" #include "Wallet.h" #include "Conversion.h" #include "NewcoinAddress.h" #include "AccountState.h" #include "utils.h" #define VALIDATORS_FETCH_SECONDS 30 #define VALIDATORS_FILE_PATH "/" VALIDATORS_FILE_NAME #define VALIDATORS_FILE_BYTES_MAX (50 << 10) /* Just read from wire until the entire request is in. */ RPCServer::RPCServer(boost::asio::io_service& io_service) : mSocket(io_service) { } void RPCServer::connected() { //BOOST_LOG_TRIVIAL(info) << "RPC request"; std::cout << "RPC request" << std::endl; mSocket.async_read_some(boost::asio::buffer(mReadBuffer), boost::bind(&RPCServer::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void RPCServer::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred) { if (!e) { boost::tribool result; result = mRequestParser.parse( mIncomingRequest, mReadBuffer.data(), mReadBuffer.data() + bytes_transferred); if (result) { mReplyStr=handleRequest(mIncomingRequest.mBody); sendReply(); } else if (!result) { // bad request std::cout << "bad request" << std::endl; } else { // not done keep reading mSocket.async_read_some(boost::asio::buffer(mReadBuffer), boost::bind(&RPCServer::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } } else if (e != boost::asio::error::operation_aborted) { } } std::string RPCServer::handleRequest(const std::string& requestStr) { std::cout << "handleRequest " << requestStr << std::endl; Json::Value id; // Parse request Json::Value valRequest; Json::Reader reader; if (!reader.parse(requestStr, valRequest) || valRequest.isNull() || !valRequest.isObject()) return(HTTPReply(400, "")); // Parse id now so errors from here on will have the id id = valRequest["id"]; // Parse method Json::Value valMethod = valRequest["method"]; if (valMethod.isNull()) return(HTTPReply(400, "")); if (!valMethod.isString()) return(HTTPReply(400, "")); std::string strMethod = valMethod.asString(); // Parse params Json::Value valParams = valRequest["params"]; if (valParams.isNull()) valParams = Json::Value(Json::arrayValue); else if (!valParams.isArray()) return(HTTPReply(400, "")); #ifdef DEBUG Json::StyledStreamWriter w; w.write(std::cerr, valParams); #endif Json::Value result(doCommand(strMethod, valParams)); #ifdef DEBUG w.write(std::cerr, result); #endif std::string strReply = JSONRPCReply(result, Json::Value(), id); return( HTTPReply(200, strReply) ); } int RPCServer::getParamCount(const Json::Value& params) { // If non-array, only counts strings if (params.isNull()) return 0; if (params.isArray()) return params.size(); if (!params.isConvertibleTo(Json::stringValue)) return 0; return 1; } bool RPCServer::extractString(std::string& param, const Json::Value& params, int index) { if (params.isNull()) return false; if (index!=0) { if (!params.isArray() || !params.isValidIndex(index)) return false; Json::Value p(params.get(index, Json::nullValue)); if (p.isNull() || !p.isConvertibleTo(Json::stringValue)) return false; param = p.asString(); return true; } if (params.isArray()) { if ( (!params.isValidIndex(0)) || (!params[0u].isConvertibleTo(Json::stringValue)) ) return false; param = params[0u].asString(); return true; } if (!params.isConvertibleTo(Json::stringValue)) return false; param = params.asString(); return true; } // Given a seed and a source account get the public and private key for authorizing transactions for the account. Json::Value RPCServer::authorize(const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID, NewcoinAddress& naAccountPublic, NewcoinAddress& naAccountPrivate, SerializedLedgerEntry::pointer& sleSrc) { Ledger::pointer ledger = theApp->getMasterLedger().getCurrentLedger(); LedgerStateParms qry = lepNONE; sleSrc = ledger->getAccountRoot(qry, naSrcAccountID); if (!sleSrc) { return JSONRPCError(500, "source account does not exist"); } if (!sleSrc->getIFieldPresent(sfAuthorizedKey)) { return JSONRPCError(500, "source account has not been claimed"); } NewcoinAddress naGenerator; NewcoinAddress na0Public; // To find the generator index. NewcoinAddress na0Private; // To decrypt the master generator's cipher. naGenerator.setFamilyGenerator(naSeed); na0Public.setAccountPublic(naGenerator, 0); na0Private.setAccountPrivate(naGenerator, naSeed, 0); qry = lepNONE; SerializedLedgerEntry::pointer sleGen = ledger->getGenerator(qry, na0Public.getAccountID()); if (!sleGen) { // No account has been claimed or has had it password set for seed. return JSONRPCError(500, "wrong password"); } std::vector vucCipher = sleGen->getIFieldVL(sfGenerator); std::vector vucMasterGenerator = na0Private.accountPrivateDecrypt(na0Public, vucCipher); if (vucMasterGenerator.empty()) { return JSONRPCError(500, "internal error: password failed to decrypt master public generator"); } NewcoinAddress naMasterGenerator; naMasterGenerator.setFamilyGenerator(vucMasterGenerator); // // Find the index of the account from the master generator, so we can generate the public and private keys. // NewcoinAddress naMasterAccountPublic; uint iIndex = -1; // Compensate for initial increment. // XXX Stop after Config.account_probe_max // 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. do { ++iIndex; naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex); } while (naSrcAccountID.getAccountID() != naMasterAccountPublic.getAccountID()); naAccountPublic.setAccountPublic(naGenerator, iIndex); naAccountPrivate.setAccountPrivate(naGenerator, naSeed, iIndex); if (sleSrc->getIFieldH160(sfAuthorizedKey) != naAccountPublic.getAccountID()) { std::cerr << "iIndex: " << iIndex << std::endl; std::cerr << "sfAuthorizedKey: " << strHex(sleSrc->getIFieldH160(sfAuthorizedKey)) << std::endl; std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl; return JSONRPCError(500, "wrong password (changed)"); } return Json::Value(Json::objectValue); } // account_info || // account_info || [] Json::Value RPCServer::doAccountInfo(Json::Value ¶ms) { if (params.size() < 1 || params.size() > 2) { return "invalid params"; } else if (!theApp->getOPs().available()) { return "network not available"; } else { std::string strIdent = params[0u].asString(); bool bIndex = 2 == params.size(); int iIndex = bIndex ? boost::lexical_cast(params[1u].asString()) : 0; NewcoinAddress naAccount; NewcoinAddress naSeed; if (!bIndex && (naAccount.setAccountPublic(strIdent) || naAccount.setAccountID(strIdent))) { // Got the account. nothing(); } // Must be a seed. else if (!naSeed.setFamilySeedGeneric(strIdent)) { return "disallowed seed"; } else { // We allow the use of the seeds to access #0. // This is poor practice and merely for debuging convenience. NewcoinAddress naGenerator; NewcoinAddress naRegular0Public; NewcoinAddress naRegular0Private; naGenerator.setFamilyGenerator(naSeed); naRegular0Public.setAccountPublic(naGenerator, 0); naRegular0Private.setAccountPrivate(naGenerator, naSeed, 0); uint160 uGeneratorID = naRegular0Public.getAccountID(); Ledger::pointer ledger = theApp->getMasterLedger().getCurrentLedger(); LedgerStateParms qry = lepNONE; SerializedLedgerEntry::pointer sleGen = ledger->getGenerator(qry, naRegular0Public.getAccountID()); if (!sleGen) { // Didn't find a generator map, assume it is a master generator. nothing(); } else { // Found master public key. std::vector vucCipher = sleGen->getIFieldVL(sfGenerator); std::vector vucMasterGenerator = naRegular0Private.accountPrivateDecrypt(naRegular0Public, vucCipher); if (vucMasterGenerator.empty()) { return "internal error: password failed to decrypt master public generator"; } naGenerator.setFamilyGenerator(vucMasterGenerator); } bIndex = true; naAccount.setAccountPublic(naGenerator, iIndex); } // Get info on account. Json::Value ret(Json::objectValue); AccountState::pointer as=theApp->getMasterLedger().getCurrentLedger()->getAccountState(naAccount); if (as) { as->addJson(ret); } else { ret["account"] = naAccount.humanAccountID(); ret["status"] = "NotFound"; ret["bIndex"] = bIndex; if (bIndex) ret["index"] = iIndex; } return ret; } } Json::Value RPCServer::doConnect(Json::Value& params) { // connect [port] std::string strIp; int iPort = -1; if (!params.isArray() || !params.size() || params.size() > 2) return JSONRPCError(500, "Invalid parameters"); // XXX Might allow domain for manual connections. if (!extractString(strIp, params, 0)) return JSONRPCError(500, "Host IP required"); if (params.size() == 2) { std::string strPort; // YYY Should make an extract int. if (!extractString(strPort, params, 1)) return JSONRPCError(500, "Bad port"); iPort = boost::lexical_cast(strPort); } if (!theApp->getConnectionPool().connectTo(strIp, iPort)) return "connected"; return "connecting"; } Json::Value RPCServer::doPeers(Json::Value& params) { // peers return theApp->getConnectionPool().getPeersJson(); } // send regular_seed paying_account account_id amount [currency] [send_max] [send_currency] Json::Value RPCServer::doSend(Json::Value& params) { NewcoinAddress naSeed; NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; STAmount saSrcAmount; STAmount saDstAmount; std::string sSrcCurrency; std::string sDstCurrency; if (params.size() >= 5) sDstCurrency = params[4u].asString(); if (params.size() >= 7) sSrcCurrency = params[6u].asString(); if (!params.isArray() || params.size() < 3 || params.size() > 7) { return JSONRPCError(500, "Invalid parameters"); } else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { return JSONRPCError(500, "disallowed seed"); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { return JSONRPCError(500, "source account id needed"); } else if (!naDstAccountID.setAccountID(params[2u].asString())) { return JSONRPCError(500, "create account id needed"); } else if (!saDstAmount.setValue(params[3u].asString(), sDstCurrency)) { return JSONRPCError(500, "bad dst amount/currency"); } else if (!saSrcAmount.setValue(params[5u].asString(), sSrcCurrency)) { return JSONRPCError(500, "bad src amount/currency"); } else if (!theApp->getOPs().available()) { return "network not available"; } else { NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; SerializedLedgerEntry::pointer sleSrc; Json::Value obj = authorize(naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, sleSrc); if (!obj.empty()) { std::cerr << "Auth Error" << std::endl; return obj; } STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance); if (saSrcBalance < theConfig.FEE_DEFAULT) { return JSONRPCError(500, "insufficent funds"); } else { STPathSet spPaths; Transaction::pointer trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, sleSrc->getIFieldU32(sfSequence), theConfig.FEE_DEFAULT, 0, // YYY No source tag naDstAccountID, saDstAmount, saSrcAmount, spPaths); (void) theApp->getOPs().processTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); obj["seed"] = naSeed.humanFamilySeed(); obj["srcAccountID"] = naSrcAccountID.humanAccountID(); obj["dstAccountID"] = naDstAccountID.humanAccountID(); obj["srcAmount"] = saSrcAmount.getText(); obj["srcISO"] = saSrcAmount.getCurrencyHuman(); obj["dstAmount"] = saDstAmount.getText(); obj["dstISO"] = saDstAmount.getCurrencyHuman(); } return obj; } } Json::Value RPCServer::doTx(Json::Value& params) { // tx // tx // tx // tx std::string param1, param2; if (!extractString(param1, params, 0)) { // all local transactions return "not implemented"; } if (Transaction::isHexTxID(param1)) { // transaction by ID Json::Value ret; uint256 txid(param1); // if (theApp->getWallet().getTxJson(txid, ret)) // return ret; Transaction::pointer txn=theApp->getMasterTransaction().fetch(txid, true); if (!txn) return JSONRPCError(500, "Transaction not found"); return txn->getJson(true); } if (extractString(param2, params, 1)) { // family seq return "not implemented"; } else { // account } return "not implemented"; } Json::Value RPCServer::doLedger(Json::Value& params) { // ledger // ledger // ledger int paramCount = getParamCount(params); if (paramCount == 0) { Json::Value ret(Json::objectValue), current(Json::objectValue), closed(Json::objectValue); theApp->getMasterLedger().getCurrentLedger()->addJson(current); theApp->getMasterLedger().getClosedLedger()->addJson(closed); ret["open"] = current; ret["closed"] = closed; return ret; } return "not implemented"; } // unl_add [] Json::Value RPCServer::doUnlAdd(Json::Value& params) { if (params.size() == 1 || params.size() == 2) { std::string strNode = params[0u].asString(); std::string strComment = (params.size() == 2) ? "" : params[1u].asString(); NewcoinAddress nodePublic; if (nodePublic.setNodePublic(strNode)) { theApp->getUNL().nodeAddPublic(nodePublic, strComment); return "adding node by public key"; } else { theApp->getUNL().nodeAddDomain(strNode, UniqueNodeList::vsManual, strComment); return "adding node by domain"; } } return "invalid params"; } // validation_create // validation_create // validation_create // validation_create // // NOTE: It is poor security to specify secret information on the command line. This information might be saved in the command // shell history file (e.g. .bash_history) and it may be leaked via the process status command (i.e. ps). Json::Value RPCServer::doValidatorCreate(Json::Value& params) { NewcoinAddress familySeed; NewcoinAddress familyGenerator; NewcoinAddress nodePublicKey; NewcoinAddress nodePrivateKey; if (params.size() > 1) { return "invalid params"; } else if (params.empty()) { std::cerr << "Creating random validation seed." << std::endl; familySeed.setFamilySeedRandom(); // Get a random seed. } else if (!familySeed.setFamilySeedGeneric(params[0u].asString())) { return "disallowed seed"; } // Derive generator from seed. familyGenerator.setFamilyGenerator(familySeed); // The node public and private is 0th of the sequence. nodePublicKey.setNodePublic(CKey(familyGenerator, 0).GetPubKey()); nodePrivateKey.setNodePrivate(CKey(familyGenerator, familySeed.getFamilyPrivateKey(), 0).GetSecret()); // Paranoia assert(1 == familySeed.setFamilySeed1751(familySeed.humanFamilySeed1751())); Json::Value obj(Json::objectValue); obj["validation_public_key"] = nodePublicKey.humanNodePublic(); obj["validation_seed"] = familySeed.humanFamilySeed(); obj["validation_key"] = familySeed.humanFamilySeed1751(); return obj; } Json::Value RPCServer::doWalletAccounts(Json::Value& params) { return "not implemented"; } Json::Value RPCServer::doWalletAdd(Json::Value& params) { return "not implemented"; } // wallet_claim [] [] // // To provide an example to client writers, we do everything we expect a client to do here. Json::Value RPCServer::doWalletClaim(Json::Value& params) { NewcoinAddress naMasterSeed; NewcoinAddress naRegularSeed; if (params.size() < 2 || params.size() > 4) { return "invalid params"; } else if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) { // Should also not allow account id's as seeds. return "master seed expected"; } else if (!naRegularSeed.setFamilySeedGeneric(params[1u].asString())) { // Should also not allow account id's as seeds. return "regular seed expected"; } else { // Building: // peer_wallet_claim // [] // // // Which has no confidential information. // XXX Need better parsing. uint32 uSourceTag = (params.size() == 2) ? 0 : boost::lexical_cast(params[2u].asString()); // XXX Annotation is ignored. std::string strAnnotation = (params.size() == 3) ? "" : params[3u].asString(); NewcoinAddress naMasterGenerator; NewcoinAddress naRegularGenerator; NewcoinAddress naRegular0Public; NewcoinAddress naRegular0Private; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; naMasterGenerator.setFamilyGenerator(naMasterSeed); naAccountPublic.setAccountPublic(naMasterGenerator, 0); naAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, 0); naRegularGenerator.setFamilyGenerator(naRegularSeed); naRegular0Public.setAccountPublic(naRegularGenerator, 0); naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0); // hash of regular account #reserved public key. uint160 uGeneratorID = naRegular0Public.getAccountID(); std::vector vucGeneratorCipher = naRegular0Private.accountPrivateEncrypt(naRegular0Public, naMasterGenerator.getFamilyGenerator()); std::vector vucGeneratorSig; // XXX Check result. naRegular0Private.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig); Transaction::pointer trns = Transaction::sharedClaim( naAccountPublic, naAccountPrivate, naAccountPublic, uSourceTag, vucGeneratorCipher, naRegular0Public.getAccountPublic(), vucGeneratorSig); (void) theApp->getOPs().processTransaction(trns); Json::Value obj(Json::objectValue); // We "echo" the seeds so they can be checked. obj["master_seed"] = naMasterSeed.humanFamilySeed(); obj["master_key"] = naMasterSeed.humanFamilySeed1751(); obj["regular_seed"] = naRegularSeed.humanFamilySeed(); obj["regular_key"] = naRegularSeed.humanFamilySeed1751(); obj["account_id"] = naAccountPublic.humanAccountID(); obj["generator_id"] = strHex(uGeneratorID); obj["generator"] = strHex(vucGeneratorCipher); obj["annotation"] = strAnnotation; obj["transaction"] = trns->getSTransaction()->getJson(0); obj["status"] = trns->getStatus(); return obj; } } // wallet_create regular_seed paying_account account_id [initial_funds] // We don't allow creating an account_id by default here because we want to make sure the person has a chance to write down the // master seed of the account to be created. // YYY Need annotation and source tag Json::Value RPCServer::doWalletCreate(Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; if (params.size() < 3 || params.size() > 4) { return "invalid params"; } else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { return "disallowed seed"; } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { return "source account id needed"; } else if (!naDstAccountID.setAccountID(params[2u].asString())) { return "create account id needed"; } else if (!theApp->getOPs().available()) { // We require access to the paying account's sequence number and key information. return "network not available"; } else if (theApp->getMasterLedger().getCurrentLedger()->getAccountState(naDstAccountID)) { return "account already exists"; } else { // Trying to build: // peer_wallet_create [] [] NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; SerializedLedgerEntry::pointer sleSrc; Json::Value obj = authorize(naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, sleSrc); STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance); STAmount saInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast(params[3u].asString()); if (!obj.isNull()) { nothing(); } else if (saSrcBalance < theConfig.FEE_CREATE + saInitialFunds) { return JSONRPCError(500, "insufficent funds"); } else { Transaction::pointer trans = Transaction::sharedCreate( naAccountPublic, naAccountPrivate, naSrcAccountID, sleSrc->getIFieldU32(sfSequence), theConfig.FEE_CREATE, 0, // YYY No source tag naDstAccountID, saInitialFunds); // Initial funds in XNC. (void) theApp->getOPs().processTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); } return obj; } } // wallet_propose Json::Value RPCServer::doWalletPropose(Json::Value& params) { if (params.size()) { return "invalid params"; } else { NewcoinAddress naSeed; NewcoinAddress naGenerator; NewcoinAddress naAccount; naSeed.setFamilySeedRandom(); naGenerator.setFamilyGenerator(naSeed); naAccount.setAccountPublic(naGenerator, 0); Json::Value obj(Json::objectValue); obj["master_seed"] = naSeed.humanFamilySeed(); obj["master_key"] = naSeed.humanFamilySeed1751(); obj["account_id"] = naAccount.humanAccountID(); return obj; } } // wallet_seed [||] Json::Value RPCServer::doWalletSeed(Json::Value& params) { NewcoinAddress naSeed; if (params.size() > 1) { return "invalid params"; } else if (params.size() && !naSeed.setFamilySeedGeneric(params[0u].asString())) { return "disallowed seed"; } else { NewcoinAddress naGenerator; NewcoinAddress naAccount; if (!params.size()) { naSeed.setFamilySeedRandom(); } naGenerator.setFamilyGenerator(naSeed); naAccount.setAccountPublic(naGenerator, 0); Json::Value obj(Json::objectValue); obj["seed"] = naSeed.humanFamilySeed(); obj["key"] = naSeed.humanFamilySeed1751(); return obj; } } Json::Value RPCServer::doWalletVerify(Json::Value& params) { return "not implemented"; } void RPCServer::validatorsResponse(const boost::system::error_code& err, std::string strResponse) { std::cerr << "Fetch '" VALIDATORS_FILE_NAME "' complete." << std::endl; if (!err) { theApp->getUNL().nodeDefault(strResponse); } else { std::cerr << "Error: " << err.message() << std::endl; } } // Populate the UNL from a validators.txt file. Json::Value RPCServer::doUnlDefault(Json::Value& params) { if (!params.size() || (1==params.size() && !params[0u].compare("network"))) { bool bNetwork = 1 == params.size(); std::string strValidators; if (!bNetwork) { std::ifstream ifsDefault(VALIDATORS_FILE_NAME, std::ios::in); if (!ifsDefault) { std::cerr << "Failed to open '" VALIDATORS_FILE_NAME "'." << std::endl; bNetwork = true; } else { strValidators.assign((std::istreambuf_iterator(ifsDefault)), std::istreambuf_iterator()); if (ifsDefault.bad()) { std::cerr << "Failed to read '" VALIDATORS_FILE_NAME "'." << std::endl; bNetwork = true; } } } if (bNetwork) { HttpsClient::httpsGet( theApp->getIOService(), VALIDATORS_SITE, 443, VALIDATORS_FILE_PATH, VALIDATORS_FILE_BYTES_MAX, boost::posix_time::seconds(VALIDATORS_FETCH_SECONDS), boost::bind(&RPCServer::validatorsResponse, this, _1, _2)); return "fetching " VALIDATORS_FILE_NAME; } else { theApp->getUNL().nodeDefault(strValidators); return "processing " VALIDATORS_FILE_NAME; } } else return "invalid params"; } // unl_delete Json::Value RPCServer::doUnlDelete(Json::Value& params) { if (1 == params.size()) { std::string strNodePublic = params[0u].asString(); NewcoinAddress naNodePublic; if (naNodePublic.setNodePublic(strNodePublic)) { theApp->getUNL().nodeRemove(naNodePublic); return "removing node"; } else { return "invalid public key"; } } else return "invalid params"; } Json::Value RPCServer::doUnlList(Json::Value& params) { return theApp->getUNL().getUnlJson(); } // unl_reset Json::Value RPCServer::doUnlReset(Json::Value& params) { if (!params.size()) { theApp->getUNL().nodeReset(); return "removing nodes"; } else return "invalid params"; } // unl_score Json::Value RPCServer::doUnlScore(Json::Value& params) { if (!params.size()) { theApp->getUNL().nodeScore(); return "scoring requested"; } else return "invalid params"; } Json::Value RPCServer::doStop(Json::Value& params) { if (!params.size()) { theApp->stop(); return SYSTEM_NAME " server stopping"; } else return "invalid params"; } Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params) { std::cerr << "RPC:" << command << std::endl; if (command == "account_info") return doAccountInfo(params); if (command == "connect") return doConnect(params); if (command == "peers") return doPeers(params); if (command == "send") return doSend(params); if (command == "stop") return doStop(params); if (command == "unl_add") return doUnlAdd(params); if (command == "unl_default") return doUnlDefault(params); if (command == "unl_delete") return doUnlDelete(params); if (command == "unl_list") return doUnlList(params); if (command == "unl_reset") return doUnlReset(params); if (command == "unl_score") return doUnlScore(params); if (command == "validation_create") return doValidatorCreate(params); if (command == "wallet_accounts") return doWalletAccounts(params); if (command == "wallet_add") return doWalletAdd(params); if (command == "wallet_claim") return doWalletClaim(params); if (command == "wallet_create") return doWalletCreate(params); if (command == "wallet_propose") return doWalletPropose(params); if (command == "wallet_seed") return doWalletSeed(params); if (command == "wallet_verify") return doWalletVerify(params); // // Obsolete or need rewrite: // if (command=="tx") return doTx(params); if (command=="ledger") return doLedger(params); return "unknown command"; } void RPCServer::sendReply() { boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr), boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error)); } void RPCServer::handle_write(const boost::system::error_code& /*error*/) { } // vim:ts=4