From c939ec9913d2dc371cca793d76079f3a3b165b8e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 17 May 2012 20:38:57 -0700 Subject: [PATCH] Work on RPC wallet_create. --- src/LedgerNode.cpp | 5 + src/NetworkOPs.h | 15 ++- src/RPCServer.cpp | 266 ++++++++++++++++++++++++++------------------- 3 files changed, 168 insertions(+), 118 deletions(-) diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index 67216fc1d..fb5422f89 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -90,6 +90,11 @@ SerializedLedgerEntry::pointer Ledger::getAccountRoot(LedgerStateParms& parms, c } } +SerializedLedgerEntry::pointer Ledger::getAccountRoot(LedgerStateParms& parms, const NewcoinAddress& naAccountID) +{ + return getAccountRoot(parms, naAccountID.getAccountID()); +} + SerializedLedgerEntry::pointer Ledger::getNickname(LedgerStateParms& parms, const std::string& nickname) { return getNickname(parms, Serializer::getSHA512Half(nickname)); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index bb1c3c903..5b8ce6c80 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -17,16 +17,16 @@ class NetworkOPs public: enum Fault { // exceptions these functions can throw - IO_ERROR = 1, - NO_NETWORK = 2, + IO_ERROR = 1, + NO_NETWORK = 2, }; enum OperatingMode { // how we process transactions or account balance requests - omDISCONNECTED = 0, // not ready to process requests - omCONNECTED = 1, // convinced we are talking to the network - omTRACKING = 2, // convinced we agree with the network - omFULL = 3 // we have the ledger and can even validate + omDISCONNECTED = 0, // not ready to process requests + omCONNECTED = 1, // convinced we are talking to the network + omTRACKING = 2, // convinced we agree with the network + omFULL = 3 // we have the ledger and can even validate }; protected: @@ -41,6 +41,9 @@ public: boost::posix_time::ptime getNetworkTimePT(); uint32 getCurrentLedgerID(); OperatingMode getOperatingMode() { return mMode; } + inline bool available() { + return omDISCONNECTED != mMode; + } // transaction operations Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 7d342ef45..104d87037 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -182,6 +182,9 @@ Json::Value RPCServer::doAccountInfo(Json::Value ¶ms) { return "invalid params"; } + else if (!theApp->getOPs().available()) { + return "network not available"; + } else { std::string strIdent = params[0u].asString(); @@ -196,31 +199,46 @@ Json::Value RPCServer::doAccountInfo(Json::Value ¶ms) // Got the account. nothing(); } + // Must be a seed. + else if (!naSeed.setFamilySeedGeneric(strIdent)) + { + return "disallowed seed"; + } else { - // Must be a seed. - naSeed.setFamilySeedGeneric(strIdent); - + // We allow the use of the seeds to access #0. + // This is poor practice and merely for debuging convenience. NewcoinAddress naGenerator; - NewcoinAddress naRegularReservedPublic; + NewcoinAddress naRegular0Public; + NewcoinAddress naRegular0Private; naGenerator.setFamilyGenerator(naSeed); - naRegularReservedPublic.setAccountPublic(naGenerator, -1); + naRegular0Public.setAccountPublic(naGenerator, 0); + naRegular0Private.setAccountPrivate(naGenerator, naSeed, 0); - uint160 uGeneratorID = naRegularReservedPublic.getAccountID(); + uint160 uGeneratorID = naRegular0Public.getAccountID(); - // if (probe (uGeneratorID)) - if (false) - { - // Found master public key. - - } - else + 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; @@ -497,17 +515,20 @@ Json::Value RPCServer::doValidatorCreate(Json::Value& params) { NewcoinAddress nodePublicKey; NewcoinAddress nodePrivateKey; - if (params.empty()) + 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 (1 == params.size()) + else if (!familySeed.setFamilySeedGeneric(params[0u].asString())) { - familySeed.setFamilySeedGeneric(params[0u].asString()); + return "disallowed seed"; } - else return "invalid params"; // Derive generator from seed. familyGenerator.setFamilyGenerator(familySeed); @@ -533,22 +554,19 @@ Json::Value RPCServer::doValidatorCreate(Json::Value& params) { // 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 naTemp; + NewcoinAddress naMasterSeed; + NewcoinAddress naRegularSeed; if (params.size() < 2 || params.size() > 4) { return "invalid params"; } - else if (naTemp.setAccountID(params[0u].asString()) - || naTemp.setAccountPublic(params[0u].asString()) - || naTemp.setAccountPrivate(params[0u].asString())) + else if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) { // Should also not allow account id's as seeds. return "master seed expected"; } - else if (naTemp.setAccountID(params[1u].asString()) - || naTemp.setAccountPublic(params[1u].asString()) - || naTemp.setAccountPrivate(params[1u].asString())) + else if (!naRegularSeed.setFamilySeedGeneric(params[1u].asString())) { // Should also not allow account id's as seeds. return "regular seed expected"; @@ -556,7 +574,7 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params) else { // Trying to build: - // peer_wallet_claim + // peer_wallet_claim // [] // // @@ -567,43 +585,37 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params) // XXX Annotation is ignored. std::string strAnnotation = (params.size() == 3) ? "" : params[3u].asString(); - NewcoinAddress naMasterSeed; NewcoinAddress naMasterGenerator; - - NewcoinAddress naRegularSeed; NewcoinAddress naRegularGenerator; - NewcoinAddress naRegularReservedPublic; - NewcoinAddress naRegularReservedPrivate; + NewcoinAddress naRegular0Public; + NewcoinAddress naRegular0Private; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; - naMasterSeed.setFamilySeedGeneric(params[0u].asString()); - naRegularSeed.setFamilySeedGeneric(params[1u].asString()); - naMasterGenerator.setFamilyGenerator(naMasterSeed); naAccountPublic.setAccountPublic(naMasterGenerator, 0); naAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, 0); naRegularGenerator.setFamilyGenerator(naRegularSeed); - naRegularReservedPublic.setAccountPublic(naRegularGenerator, -1); - naRegularReservedPrivate.setAccountPrivate(naRegularGenerator, naRegularSeed, -1); + naRegular0Public.setAccountPublic(naRegularGenerator, 0); + naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0); // hash of regular account #reserved public key. - uint160 uGeneratorID = naRegularReservedPublic.getAccountID(); - std::vector vucGeneratorCipher = naRegularReservedPrivate.accountPrivateEncrypt(naRegularReservedPublic, naMasterGenerator.getFamilyGenerator()); + uint160 uGeneratorID = naRegular0Public.getAccountID(); + std::vector vucGeneratorCipher = naRegular0Private.accountPrivateEncrypt(naRegular0Public, naMasterGenerator.getFamilyGenerator()); std::vector vucGeneratorSig; // XXX Check result. - naRegularReservedPrivate.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig); + naRegular0Private.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig); Transaction::pointer trns = Transaction::sharedClaim( naAccountPublic, naAccountPrivate, naAccountPublic, uSourceTag, vucGeneratorCipher, - naRegularReservedPublic.getAccountPublic(), + naRegular0Public.getAccountPublic(), vucGeneratorSig); (void) theApp->getOPs().processTransaction(trns); @@ -629,12 +641,16 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params) } // 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 naSourceID; NewcoinAddress naCreateID; + NewcoinAddress naRegularSeed; - if (params.size() < 3 || params.size() > 2) + if (params.size() < 3 || params.size() > 4) { return "invalid params"; } @@ -646,6 +662,18 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) { return "create account id needed"; } + else if (!naRegularSeed.setFamilySeedGeneric(params[0u].asString())) + { + return "disallowed seed"; + } + 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(naCreateID)) + { + return "account already exists"; + } else { // Trying to build: @@ -653,88 +681,100 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) // peer_payment // // Which has no confidential information. -#if 0 - NewcoinAddress naRegularSeed; + + Ledger::pointer ledger = theApp->getMasterLedger().getCurrentLedger(); + LedgerStateParms qry = lepNONE; + SerializedLedgerEntry::pointer sleSrc = ledger->getAccountRoot(qry, naSourceID); + + if (!sleSrc) + { + return "source account does not exist"; + } + + uint64 uSrcBalance = sleSrc->getIFieldU64(sfBalance); + uint64 uInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast(params[3u].asString()); + + if (uSrcBalance < theConfig.FEE_CREATE + uInitialFunds) + { + return "insufficent funds"; + } + else if (!sleSrc->getIFieldPresent(sfAuthorizedKey)) + { + return "source account has not been claimed"; + } + NewcoinAddress naRegularGenerator; - NewcoinAddress naRegularReservedPublic; - NewcoinAddress naRegularReservedPrivate; + NewcoinAddress naRegular0Public; + NewcoinAddress naRegular0Private; + + naRegularGenerator.setFamilyGenerator(naRegularSeed); + naRegular0Public.setAccountPublic(naRegularGenerator, 0); + naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0); + + qry = lepNONE; + SerializedLedgerEntry::pointer sleGen = ledger->getGenerator(qry, naRegular0Public.getAccountID()); + + if (!sleGen) + { + // No account has been claimed or has had it password set for seed. + return "wrong password"; + } + + 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"; + } + + NewcoinAddress naMasterGenerator; + + naMasterGenerator.setFamilyGenerator(vucMasterGenerator); + + // + // Find the index of the account from the master generator, so we can generator the public and private keys. + // + NewcoinAddress naMasterAccountPublic; + uint iIndex = -1; // Compensate for initial increment. + + // XXX Stop after Config.account_probe_max + do { + ++iIndex; + naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex); + } while (naSourceID.getAccountID() != naMasterAccountPublic.getAccountID()); NewcoinAddress naRegularAccountPublic; NewcoinAddress naRegularAccountPrivate; - naRegularSeed.setFamilySeedGeneric(params[0u].asString()); + naRegularAccountPublic.setAccountPublic(naRegularGenerator, iIndex); + naRegularAccountPrivate.setAccountPrivate(naRegularGenerator, naRegularSeed, iIndex); - seed-> master_public_generator -> master_accounts & regular_accounts - -> regular_public_key (verified) -> regular_private_key + if (sleSrc->getIFieldH160(sfAuthorizedKey) != naRegularAccountPublic.getAccountID()) + { + std::cerr << "iIndex: " << iIndex << std::endl; + std::cerr << "sfAuthorizedKey: " << strHex(sleSrc->getIFieldH160(sfAuthorizedKey)) << std::endl; + std::cerr << "naRegularAccountPublic: " << strHex(naRegularAccountPublic.getAccountID()) << std::endl; - AccountState::pointer account=theApp->getMasterLedger().getCurrentLedger()->getAccountState(naAccount); + return "wrong password (changed)"; + } Transaction::pointer trans = Transaction::sharedCreate( - const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + naRegularAccountPublic, naRegularAccountPrivate, naSourceID, - uint32 uSeq, - uint64 uFee, - uint32 uSourceTag, - uint32 uLedger, - const NewcoinAddress& naCreateAccountID, // Account to create. - uint64 uFund); // Initial funds in XNC. -#endif - return "not implemented"; -#if 0 - // XXX Need better parsing. - uint64 uInitalFunds = 0; - 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(); + sleSrc->getIFieldU32(sfSequence), + theConfig.FEE_CREATE, + 0, // YYY No source tag + naCreateID, + uInitialFunds); // Initial funds in XNC. - NewcoinAddress naMasterSeed; - NewcoinAddress naMasterGenerator; - - NewcoinAddress naAccountPublic; - NewcoinAddress naAccountPrivate; - - naMasterSeed.setFamilySeedGeneric(params[0u].asString()); - - naMasterGenerator.setFamilyGenerator(naMasterSeed); - naAccountPublic.setAccountPublic(naMasterGenerator, 0); - naAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, 0); - - naRegularGenerator.setFamilyGenerator(naRegularSeed); - - naRegularReservedPublic.setAccountPublic(naRegularGenerator, -1); - naRegularReservedPrivate.setAccountPrivate(naRegularGenerator, naRegularSeed, -1); - - // hash of regular account #reserved public key. - uint160 uGeneratorID = naRegularReservedPublic.getAccountID(); - std::vector vucGeneratorCipher = naRegularReservedPrivate.accountPrivateEncrypt(naRegularReservedPublic, naMasterGenerator.getFamilyGenerator()); - std::vector vucGeneratorSig; - - // XXX Check result. - naRegularReservedPrivate.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig); - - Transaction::pointer trns = Transaction::sharedWalletCreate( - naAccountPublic, naAccountPrivate, - naAccountPublic, - uSourceTag, - vucGeneratorCipher, - naRegularReservedPublic.getAccountPublic(), - vucGeneratorSig); - - (void) theApp->getOPs().processTransaction(trns); + (void) theApp->getOPs().processTransaction(trans); Json::Value obj(Json::objectValue); - - 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(); + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); return obj; -#endif } } @@ -768,21 +808,23 @@ Json::Value RPCServer::doWalletPropose(Json::Value& params) // 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 naSeed; NewcoinAddress naGenerator; NewcoinAddress naAccount; - if (params.size()) - { - naSeed.setFamilySeedGeneric(params[0u].asString()); - } - else + if (!params.size()) { naSeed.setFamilySeedRandom(); }