diff --git a/src/Config.h b/src/Config.h index 4eb84dc279..ce595905a1 100644 --- a/src/Config.h +++ b/src/Config.h @@ -83,3 +83,4 @@ public: extern Config theConfig; #endif +// vim:ts=4 diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index f53458ad8f..1c7bdcd1c2 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -205,7 +205,8 @@ Json::Value RPCServer::getGenerator(const uint256& uLedger, const NewcoinAddress Json::Value RPCServer::authorize(const uint256& uLedger, const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID, NewcoinAddress& naAccountPublic, NewcoinAddress& naAccountPrivate, - AccountState::pointer& asSrc) + AccountState::pointer& asSrc, + const NewcoinAddress& naVerifyGenerator) { asSrc = mNetOps->getAccountState(uLedger, naSrcAccountID); if (!asSrc) @@ -225,6 +226,13 @@ Json::Value RPCServer::authorize(const uint256& uLedger, if (!obj.empty()) return obj; + if (naVerifyGenerator.isValid() && naMasterGenerator != naVerifyGenerator) + { + std::cerr << "naAccountPublic: wrong seed" << std::endl; + + return JSONRPCError(500, "wrong seed"); + } + // // Find the index of the account from the master generator, so we can generate the public and private keys. // @@ -322,7 +330,8 @@ Json::Value RPCServer::doAccountInfo(Json::Value ¶ms) { return "invalid params"; } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { return JSONRPCError(503, "network not available"); } else @@ -368,7 +377,8 @@ Json::Value RPCServer::doAccountLines(Json::Value ¶ms) { return "invalid params"; } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { return JSONRPCError(503, "network not available"); } else @@ -525,16 +535,18 @@ Json::Value RPCServer::doCreditSet(Json::Value& params) { return JSONRPCError(500, "bad src amount/currency"); } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { return JSONRPCError(503, "network not available"); } else { + NewcoinAddress naMasterGenerator; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; uint256 uLedger = mNetOps->getClosedLedger(); - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc); + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc, naMasterGenerator); if (!obj.empty()) return obj; @@ -613,16 +625,18 @@ Json::Value RPCServer::doSend(Json::Value& params) { return JSONRPCError(500, "bad src amount/currency"); } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { return JSONRPCError(503, "network not available"); } else { + NewcoinAddress naMasterGenerator; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; uint256 uLedger = mNetOps->getClosedLedger(); - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc); + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc, naMasterGenerator); if (!obj.empty()) { @@ -704,16 +718,18 @@ Json::Value RPCServer::doTransitSet(Json::Value& params) { return JSONRPCError(500, "source account id needed"); } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { return JSONRPCError(503, "network not available"); } else { + NewcoinAddress naMasterGenerator; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; uint256 uLedger = mNetOps->getClosedLedger(); - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc); + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc, naMasterGenerator); if (!obj.empty()) { @@ -917,7 +933,8 @@ Json::Value RPCServer::doWalletAccounts(Json::Value& params) { return "seed expected"; } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { return JSONRPCError(503, "network not available"); } else if ((uLedger = mNetOps->getClosedLedger()).isZero()) @@ -955,9 +972,122 @@ Json::Value RPCServer::doWalletAccounts(Json::Value& params) } } +// wallet_add [] [] Json::Value RPCServer::doWalletAdd(Json::Value& params) { - return "not implemented"; + NewcoinAddress naMasterSeed; + NewcoinAddress naRegularSeed; + NewcoinAddress naSrcAccountID; + STAmount saAmount; + std::string sDstCurrency; + + if (params.size() < 3 || params.size() > 5) + { + return "invalid params"; + } + else if (!naRegularSeed.setFamilySeedGeneric(params[0u].asString())) + { + return "regular seed expected"; + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) + { + return JSONRPCError(500, "source account id needed"); + } + else if (!naMasterSeed.setFamilySeedGeneric(params[2u].asString())) + { + return "master seed expected"; + } + else if (params.size() >= 4 && !saAmount.setValue(params[3u].asString(), sDstCurrency)) + { + return JSONRPCError(500, "bad dst amount/currency"); + } + else if (!mNetOps->available()) + { + return JSONRPCError(503, "network not available"); + } + else + { + NewcoinAddress naMasterGenerator; + NewcoinAddress naRegularGenerator; + + naMasterGenerator.setFamilyGenerator(naMasterSeed); + naRegularGenerator.setFamilyGenerator(naRegularSeed); + + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + uint256 uLedger = mNetOps->getClosedLedger(); + Json::Value obj = authorize(uLedger, naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc, naMasterGenerator); + + if (!obj.empty()) + { + return obj; + } + + // XXX Confirm total funds. + + STAmount saSrcBalance = asSrc->getBalance(); + + if (saSrcBalance < theConfig.FEE_CREATE) + { + return JSONRPCError(500, "insufficent funds"); + } + else + { + NewcoinAddress naNewAccountPublic; + NewcoinAddress naNewAccountPrivate; + NewcoinAddress naAuthKeyID; + uint160 uAuthKeyID; + AccountState::pointer asNew; + std::vector vucSignature; + bool bAgain = true; + int iIndex = -1; + + // Find an unmade account. + do { + ++iIndex; + naNewAccountPublic.setAccountPublic(naMasterGenerator, iIndex); + + asNew = mNetOps->getAccountState(uLedger, naNewAccountPublic); + if (!asNew) + bAgain = false; + } while (bAgain); + + // XXX Have a maximum number of accounts per wallet? + + // Determine corrisponding master private key. + naNewAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, iIndex); + + // Determine new accounts authorized regular key. + naAuthKeyID.setAccountPublic(naRegularGenerator, iIndex); + + uAuthKeyID = naAuthKeyID.getAccountID(); + + // Sign anything (naAuthKeyID) to prove we know new master private key. + naNewAccountPrivate.accountPrivateSign(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature); + + Transaction::pointer trans = Transaction::sharedWalletAdd( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + theConfig.FEE_CREATE, + 0, // YYY No source tag + saAmount, + naAuthKeyID, + naNewAccountPublic, + vucSignature); + + (void) mNetOps->processTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + obj["srcAccountID"] = naSrcAccountID.humanAccountID(); + obj["newAccountID"] = naNewAccountPublic.humanAccountID(); + obj["amount"] = saAmount.getText(); + + return obj; + } + } } // wallet_claim [] [] @@ -1013,12 +1143,13 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params) naRegular0Public.setAccountPublic(naRegularGenerator, 0); naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0); - // hash of regular account #reserved public key. + // Hash of regular account #0 public key. uint160 uGeneratorID = naRegular0Public.getAccountID(); std::vector vucGeneratorCipher = naRegular0Private.accountPrivateEncrypt(naRegular0Public, naMasterGenerator.getFamilyGenerator()); std::vector vucGeneratorSig; // XXX Check result. + // Prove that we have the corrisponding private key to the generator id. So, we can get the generator id. naRegular0Private.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig); Transaction::pointer trns = Transaction::sharedClaim( @@ -1078,7 +1209,8 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) { return "create account id needed"; } - else if (!mNetOps->available()) { + else if (!mNetOps->available()) + { // We require access to the paying account's sequence number and key information. return JSONRPCError(503, "network not available"); } @@ -1095,11 +1227,12 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) // Trying to build: // peer_wallet_create [] [] + NewcoinAddress naMasterGenerator; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; uint256 uLedger = mNetOps->getClosedLedger(); - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc); + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc, naMasterGenerator); STAmount saSrcBalance = asSrc->getBalance(); STAmount saInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast(params[3u].asString()); diff --git a/src/RPCServer.h b/src/RPCServer.h index 33710e9b18..fd2ca9fbea 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -42,7 +42,8 @@ private: Json::Value getGenerator(const uint256& uLedger, const NewcoinAddress& naSeed, NewcoinAddress& naMasterGenerator); Json::Value authorize(const uint256& uLedger, const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID, NewcoinAddress& naAccountPublic, NewcoinAddress& naAccountPrivate, - AccountState::pointer& asSrc); + AccountState::pointer& asSrc, + const NewcoinAddress& naVerifyGenerator); Json::Value accounts(const uint256& uLedger, const NewcoinAddress& naMasterGenerator); Json::Value accountFromString(const uint256& uLedger, NewcoinAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex); diff --git a/src/Transaction.cpp b/src/Transaction.cpp index f102710cfb..1e2908496d 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -305,6 +305,45 @@ Transaction::pointer Transaction::sharedTransitSet( return tResult->setTransitSet(naPrivateKey, uTransitRate, uTransitStart, uTransitExpire); } +// +// WalletAdd +// + +Transaction::pointer Transaction::setWalletAdd( + const NewcoinAddress& naPrivateKey, + const STAmount& saAmount, + const NewcoinAddress& naAuthKeyID, + const NewcoinAddress& naNewPubKey, + const std::vector& vucSignature) +{ + mTransaction->setITFieldAmount(sfAmount, saAmount); + mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); + mTransaction->setITFieldVL(sfPubKey, naNewPubKey.getAccountPublic()); + mTransaction->setITFieldVL(sfSignature, vucSignature); + + sign(naPrivateKey); + + return shared_from_this(); +} + +Transaction::pointer Transaction::sharedWalletAdd( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + const STAmount& saFee, + uint32 uSourceTag, + const STAmount& saAmount, + const NewcoinAddress& naAuthKeyID, + const NewcoinAddress& naNewPubKey, + const std::vector& vucSignature) +{ + pointer tResult = boost::make_shared(ttWALLET_ADD, + naPublicKey, naSourceAccount, + uSeq, saFee, uSourceTag); + + return tResult->setWalletAdd(naPrivateKey, saAmount, naAuthKeyID, naNewPubKey, vucSignature); +} + // // Misc. // diff --git a/src/Transaction.h b/src/Transaction.h index 5f5789b328..9a28f5b283 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -76,6 +76,13 @@ private: uint32 uTransitStart, uint32 uTransitExpire); + Transaction::pointer setWalletAdd( + const NewcoinAddress& naPrivateKey, + const STAmount& saAmount, + const NewcoinAddress& naAuthKeyID, + const NewcoinAddress& naNewPubKey, + const std::vector& vucSignature); + public: Transaction(const SerializedTransaction::pointer st, bool bValidate); @@ -142,6 +149,18 @@ public: uint32 uTransitStart, uint32 uTransitExpire); + // Add an account to a wallet. + static Transaction::pointer sharedWalletAdd( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + const STAmount& saFee, + uint32 uSourceTag, + const STAmount& saAmount, // Initial funds in XNC. + const NewcoinAddress& naAuthKeyID, // ID of regular public to auth. + const NewcoinAddress& naNewPubKey, // Public key of new account + const std::vector& vucSignature); // Proof know new account's private key. + bool sign(const NewcoinAddress& naAccountPrivate); bool checkSign() const; void updateID() { mTransactionID=mTransaction->getTransactionID(); } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 9997b47103..09be834c25 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -263,17 +263,21 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran return tenINVALID; } + // + // Verify transaction is signed properly. + // + // Extract signing key // Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed // without going to disk. Each transaction also notes a source account id. This is used to verify that the signing key is // associated with the account. // XXX This could be a lot cleaner to prevent unnecessary copying. - NewcoinAddress naPubKey; + NewcoinAddress naSigningPubKey; - naPubKey.setAccountPublic(txn.peekSigningPubKey()); + naSigningPubKey.setAccountPublic(txn.peekSigningPubKey()); - // check signature - if (!txn.checkSign(naPubKey)) + // Consistency: really signed. + if (!txn.checkSign(naSigningPubKey)) { std::cerr << "applyTransaction: Invalid transaction: bad signature" << std::endl; return tenINVALID; @@ -299,6 +303,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttOFFER: case ttCREDIT_SET: case ttTRANSIT_SET: + case ttWALLET_ADD: result = terSUCCESS; break; @@ -349,15 +354,46 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran boost::recursive_mutex::scoped_lock sl(mLedger->mLock); // find source account - // If we are only verifying some transactions, this would be probablistic. + // If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probablistic. LedgerStateParms lspRoot = lepNONE; SLE::pointer sleSrc = mLedger->getAccountRoot(lspRoot, srcAccountID); if (!sleSrc) { std::cerr << str(boost::format("applyTransaction: Delay transaction: source account does not exisit: %s") % txn.getSourceAccount().humanAccountID()) << std::endl; + return terNO_ACCOUNT; } + // Consistency: Check signature + switch (txn.getTxnType()) + { + case ttCLAIM: + if (naSigningPubKey.getAccountID() != srcAccountID) + { + // Signing Pub Key must be for Source Account ID. + std::cerr << "sourceAccountID: " << naSigningPubKey.humanAccountID() << std::endl; + std::cerr << "txn accountID: " << txn.getSourceAccount().humanAccountID() << std::endl; + + return tenINVALID; + } + break; + + default: + if (!sleSrc->getIFieldPresent(sfAuthorizedKey)) + { + std::cerr << "applyTransaction: Can not use unclaimed account." << std::endl; + + return tenUNCLAIMED; + } + else if (naSigningPubKey.getAccountID() != sleSrc->getIFieldH160(sfAuthorizedKey)) + { + std::cerr << "applyTransaction: Not authorized to use account." << std::endl; + + return tenBAD_AUTH; + } + break; + } + // deduct the fee, so it's not available during the transaction // we only write the account back if the transaction succeeds if (!saCost.isZero()) @@ -390,15 +426,18 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran if (a_seq < t_seq) { std::cerr << "applyTransaction: future sequence number" << std::endl; + return terPRE_SEQ; } if (mLedger->hasTransaction(txID)) { std::cerr << "applyTransaction: duplicate sequence number" << std::endl; + return terALREADY; } std::cerr << "applyTransaction: past sequence number" << std::endl; + return terPAST_SEQ; } else sleSrc->setIFieldU32(sfSequence, t_seq); @@ -408,6 +447,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran if (t_seq) { std::cerr << "applyTransaction: bad sequence for pre-paid transaction" << std::endl; + return terPAST_SEQ; } } @@ -446,6 +486,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran result = doTransitSet(txn, accounts); break; + case ttWALLET_ADD: + result = doWalletAdd(txn, accounts); + break; + default: result = tenUNKNOWN; break; @@ -486,41 +530,23 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& std::vector& accounts) { std::cerr << "doClaim>" << std::endl; - NewcoinAddress naSigningPubKey; - naSigningPubKey.setAccountPublic(txn.peekSigningPubKey()); - - uint160 sourceAccountID = naSigningPubKey.getAccountID(); - - if (sourceAccountID != txn.getSourceAccount().getAccountID()) - { - // Signing Pub Key must be for Source Account ID. - std::cerr << "sourceAccountID: " << naSigningPubKey.humanAccountID() << std::endl; - std::cerr << "txn accountID: " << txn.getSourceAccount().humanAccountID() << std::endl; - return tenINVALID; - } - - LedgerStateParms qry = lepNONE; SLE::pointer sleDst = accounts[0].second; - if (!sleDst) - { - // Source account does not exist. Could succeed if it was created first. - std::cerr << str(boost::format("doClaim: no such account: %s") % txn.getSourceAccount().humanAccountID()) << std::endl; - return terNO_ACCOUNT; - } - std::cerr << str(boost::format("doClaim: %s") % sleDst->getFullText()) << std::endl; + // Verify not already claimed. if (sleDst->getIFieldPresent(sfAuthorizedKey)) { - // Source account already claimed. std::cerr << "doClaim: source already claimed" << std::endl; + return terCLAIMED; } // - // Verify claim is authorized for public key. + // Generator ID is based on regular account #0 public key. + // Verify that submitter knows the private key for the generator. + // Otherwise, people could deny access to generators. // std::vector vucCipher = txn.getITFieldVL(sfGenerator); @@ -533,22 +559,24 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature)) { - std::cerr << "doClaim: bad signature unauthorized claim" << std::endl; - return tenINVALID; + std::cerr << "doClaim: bad signature unauthorized generator claim" << std::endl; + + return tenBAD_GEN_AUTH; } // // Verify generator not already in use. // - uint160 hGeneratorID = naAccountPublic.getAccountID(); + uint160 hGeneratorID = naAccountPublic.getAccountID(); - qry = lepNONE; - SLE::pointer sleGen = mLedger->getGenerator(qry, hGeneratorID); + LedgerStateParms qry = lepNONE; + SLE::pointer sleGen = mLedger->getGenerator(qry, hGeneratorID); if (sleGen) { // Generator is already in use. Regular passphrases limited to one wallet. std::cerr << "doClaim: generator already in use" << std::endl; + return tenGEN_IN_USE; } @@ -588,6 +616,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti std::cerr << "doCreditSet: Invalid transaction: Payment destination account not specifed." << std::endl; return tenDST_NEEDED; } + // XXX Might make sense for ripple. else if (uSrcAccountID == uDstAccountID) { std::cerr << "doCreditSet: Invalid transaction: Source account is the same as destination." << std::endl; @@ -882,6 +911,72 @@ TransactionEngineResult TransactionEngine::doTransitSet(const SerializedTransact return tenINVALID; } +TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn, + std::vector& accounts) +{ + std::cerr << "WalletAdd>" << std::endl; + + SLE::pointer sleDst = accounts[0].second; + + std::cerr << str(boost::format("WalletAdd: %s") % sleDst->getFullText()) << std::endl; + + // Verify not already claimed. + if (sleDst->getIFieldPresent(sfAuthorizedKey)) + { + std::cerr << "WalletAdd: source already claimed" << std::endl; + + return terCLAIMED; + } + + // + // Generator ID is based on regular account #0 public key. + // Verify that submitter knows the private key for the generator. + // Otherwise, people could deny access to generators. + // + + std::vector vucCipher = txn.getITFieldVL(sfGenerator); + std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + std::vector vucSignature = txn.getITFieldVL(sfSignature); + + NewcoinAddress naAccountPublic; + + naAccountPublic.setAccountPublic(vucPubKey); + + if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature)) + { + std::cerr << "WalletAdd: bad signature unauthorized generator claim" << std::endl; + + return tenBAD_GEN_AUTH; + } + + // + // Verify generator not already in use. + // + + uint160 hGeneratorID = naAccountPublic.getAccountID(); + + LedgerStateParms qry = lepNONE; + SLE::pointer sleGen = mLedger->getGenerator(qry, hGeneratorID); + if (sleGen) + { + // Generator is already in use. Regular passphrases limited to one wallet. + std::cerr << "WalletAdd: generator already in use" << std::endl; + + return tenGEN_IN_USE; + } + + // + // Claim the account. + // + + // Set the public key needed to use the account. + sleDst->setIFieldH160(sfAuthorizedKey, hGeneratorID); + + std::cerr << "WalletAdd<" << std::endl; + + return terSUCCESS; +} + TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn, std::vector& accounts) { @@ -900,12 +995,6 @@ TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& t return tenUNKNOWN; } -TransactionEngineResult TransactionEngine::doCancel(const SerializedTransaction& txn, - std::vector& accounts) -{ - return tenUNKNOWN; -} - TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn, std::vector& accounts) { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index d4ce916822..679cc8d29a 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -18,7 +18,11 @@ enum TransactionEngineResult tenEXPLICITXNC, // XNC is used by default, don't specify it. tenDST_NEEDED, // Destination not specified. tenDST_IS_SRC, // Destination may not be source. + tenBAD_GEN_AUTH, // Not authorized to claim generator. + // Invalid: Ledger won't allow. + tenUNCLAIMED = -200, // Can not use an unclaimed account. + tenBAD_AUTH, // Transaction's public key is not authorized. // Other tenFAILED = -100, // Something broke horribly @@ -86,7 +90,6 @@ private: protected: Ledger::pointer mLedger; - TransactionEngineResult doCancel(const SerializedTransaction&, std::vector&); TransactionEngineResult doClaim(const SerializedTransaction&, std::vector&); TransactionEngineResult doCreditSet(const SerializedTransaction&, std::vector&, const uint160& srcAccountID); @@ -98,6 +101,7 @@ protected: TransactionEngineResult doStore(const SerializedTransaction&, std::vector&); TransactionEngineResult doTake(const SerializedTransaction&, std::vector&); TransactionEngineResult doTransitSet(const SerializedTransaction&, std::vector&); + TransactionEngineResult doWalletAdd(const SerializedTransaction&, std::vector&); public: TransactionEngine() { ; } diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 10d435f26c..3aaaa40c1e 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -69,6 +69,16 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + { "WalletAdd", ttWALLET_ADD, { + { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, { NULL, ttINVALID } }; diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index f6fc893134..008486e6e6 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -8,8 +8,9 @@ enum TransactionType ttINVALID = -1, ttPAYMENT = 0, ttCLAIM = 1, - ttINVOICE = 2, - ttOFFER = 3, + ttWALLET_ADD = 2, + ttINVOICE = 3, + ttOFFER = 4, ttCREDIT_SET = 20, ttTRANSIT_SET = 21, }; diff --git a/src/main.cpp b/src/main.cpp index 39cdf7a908..5f678033a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -53,6 +53,7 @@ void printHelp(const po::options_description& desc) cout << " unl_list" << endl; cout << " unl_reset" << endl; cout << " validation_create [||]" << endl; + cout << " wallet_add [] []" << endl; cout << " wallet_accounts " << endl; cout << " wallet_claim [] []" << endl; cout << " wallet_seed [||]" << endl;