diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 05812b29f1..3cc427139d 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -239,17 +239,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; @@ -275,6 +279,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttOFFER: case ttCREDIT_SET: case ttTRANSIT_SET: + case ttWALLET_ADD: result = terSUCCESS; break; @@ -325,15 +330,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()) @@ -366,15 +402,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); @@ -384,6 +423,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran if (t_seq) { std::cerr << "applyTransaction: bad sequence for pre-paid transaction" << std::endl; + return terPAST_SEQ; } } @@ -422,6 +462,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran result = doTransitSet(txn, accounts); break; + case ttWALLET_ADD: + result = doWalletAdd(txn, accounts); + break; + default: result = tenUNKNOWN; break; @@ -462,41 +506,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); @@ -509,22 +535,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; } @@ -564,6 +592,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; @@ -858,6 +887,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) { @@ -876,12 +971,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() { ; }