mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 21:45:52 +00:00
refactor Transaction. compiling. still need to test
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "TransactionEngine.h"
|
||||
#include "Transactor.h"
|
||||
|
||||
#include "../json/writer.h"
|
||||
|
||||
@@ -88,401 +89,74 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
|
||||
}
|
||||
#endif
|
||||
|
||||
TER terResult = tesSUCCESS;
|
||||
uint256 txID = txn.getTransactionID();
|
||||
if (!txID)
|
||||
Transactor::pointer transactor=Transactor::makeTransactor(txn,params,shared_from_this());
|
||||
if(transactor)
|
||||
{
|
||||
cLog(lsWARNING) << "applyTransaction: invalid transaction id";
|
||||
|
||||
terResult = temINVALID;
|
||||
}
|
||||
|
||||
//
|
||||
// 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.
|
||||
RippleAddress naSigningPubKey;
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
naSigningPubKey = RippleAddress::createAccountPublic(txn.getSigningPubKey());
|
||||
|
||||
// Consistency: really signed.
|
||||
if ((tesSUCCESS == terResult) && !isSetBit(params, tapNO_CHECK_SIGN) && !txn.checkSign(naSigningPubKey))
|
||||
{
|
||||
cLog(lsWARNING) << "applyTransaction: Invalid transaction: bad signature";
|
||||
|
||||
terResult = temINVALID;
|
||||
}
|
||||
|
||||
STAmount saCost = theConfig.FEE_DEFAULT;
|
||||
|
||||
// Customize behavior based on transaction type.
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
switch (txn.getTxnType())
|
||||
uint256 txID = txn.getTransactionID();
|
||||
if (!txID)
|
||||
{
|
||||
case ttCLAIM:
|
||||
case ttREGULAR_KEY_SET:
|
||||
saCost = 0;
|
||||
break;
|
||||
cLog(lsWARNING) << "applyTransaction: invalid transaction id";
|
||||
|
||||
case ttPAYMENT:
|
||||
if (txn.getFlags() & tfCreateAccount)
|
||||
{
|
||||
saCost = theConfig.FEE_ACCOUNT_CREATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ttNICKNAME_SET:
|
||||
{
|
||||
SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getFieldH256(sfNickname));
|
||||
|
||||
if (!sleNickname)
|
||||
saCost = theConfig.FEE_NICKNAME_CREATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ttACCOUNT_SET:
|
||||
case ttTRUST_SET:
|
||||
case ttOFFER_CREATE:
|
||||
case ttOFFER_CANCEL:
|
||||
case ttPASSWORD_FUND:
|
||||
case ttWALLET_ADD:
|
||||
nothing();
|
||||
break;
|
||||
|
||||
case ttINVALID:
|
||||
cLog(lsWARNING) << "applyTransaction: Invalid transaction: ttINVALID transaction type";
|
||||
terResult = temINVALID;
|
||||
break;
|
||||
|
||||
default:
|
||||
cLog(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type";
|
||||
terResult = temUNKNOWN;
|
||||
break;
|
||||
return temINVALID;
|
||||
}
|
||||
}
|
||||
|
||||
STAmount saPaid = txn.getTransactionFee();
|
||||
TER terResult= transactor->apply();
|
||||
std::string strToken;
|
||||
std::string strHuman;
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
if (saCost)
|
||||
transResultInfo(terResult, strToken, strHuman);
|
||||
|
||||
cLog(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman;
|
||||
|
||||
if (isTepPartial(terResult) && isSetBit(params, tapRETRY))
|
||||
{
|
||||
// Only check fee is sufficient when the ledger is open.
|
||||
if (isSetBit(params, tapOPEN_LEDGER) && saPaid < saCost)
|
||||
// Partial result and allowed to retry, reclassify as a retry.
|
||||
terResult = terRETRY;
|
||||
}
|
||||
|
||||
if ((tesSUCCESS == terResult) || isTepPartial(terResult))
|
||||
{
|
||||
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
|
||||
Serializer m;
|
||||
mNodes.calcRawMeta(m, terResult);
|
||||
|
||||
txnWrite();
|
||||
|
||||
Serializer s;
|
||||
txn.add(s);
|
||||
|
||||
if (isSetBit(params, tapOPEN_LEDGER))
|
||||
{
|
||||
cLog(lsINFO) << "applyTransaction: insufficient fee";
|
||||
|
||||
terResult = telINSUF_FEE_P;
|
||||
if (!mLedger->addTransaction(txID, s))
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (saPaid)
|
||||
{
|
||||
// Transaction is malformed.
|
||||
cLog(lsWARNING) << "applyTransaction: fee not allowed";
|
||||
|
||||
terResult = temINSUF_FEE_P;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get source account ID.
|
||||
mTxnAccountID = txn.getSourceAccount().getAccountID();
|
||||
if (tesSUCCESS == terResult && !mTxnAccountID)
|
||||
{
|
||||
cLog(lsWARNING) << "applyTransaction: bad source id";
|
||||
|
||||
terResult = temINVALID;
|
||||
}
|
||||
|
||||
if (tesSUCCESS != terResult)
|
||||
return terResult;
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
|
||||
|
||||
mTxnAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID));
|
||||
|
||||
// Find source account
|
||||
// If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probablistic.
|
||||
|
||||
STAmount saSrcBalance;
|
||||
uint32 t_seq = txn.getSequence();
|
||||
bool bHaveAuthKey = false;
|
||||
|
||||
if (!mTxnAccount)
|
||||
{
|
||||
cLog(lsTRACE) << boost::str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") %
|
||||
txn.getSourceAccount().humanAccountID());
|
||||
|
||||
terResult = terNO_ACCOUNT;
|
||||
}
|
||||
else
|
||||
{
|
||||
saSrcBalance = mTxnAccount->getFieldAmount(sfBalance);
|
||||
bHaveAuthKey = mTxnAccount->isFieldPresent(sfAuthorizedKey);
|
||||
}
|
||||
|
||||
// Check if account claimed.
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
switch (txn.getTxnType())
|
||||
{
|
||||
case ttCLAIM:
|
||||
if (bHaveAuthKey)
|
||||
{
|
||||
cLog(lsWARNING) << "applyTransaction: Account already claimed.";
|
||||
|
||||
terResult = tefCLAIMED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
nothing();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Consistency: Check signature
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
switch (txn.getTxnType())
|
||||
{
|
||||
case ttCLAIM:
|
||||
// Transaction's signing public key must be for the source account.
|
||||
// To prove the master private key made this transaction.
|
||||
if (naSigningPubKey.getAccountID() != mTxnAccountID)
|
||||
{
|
||||
// Signing Pub Key must be for Source Account ID.
|
||||
cLog(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID();
|
||||
cLog(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID();
|
||||
|
||||
terResult = tefBAD_CLAIM_ID;
|
||||
}
|
||||
break;
|
||||
|
||||
case ttREGULAR_KEY_SET:
|
||||
// Transaction's signing public key must be for the source account.
|
||||
// To prove the master private key made this transaction.
|
||||
if (naSigningPubKey.getAccountID() != mTxnAccountID)
|
||||
{
|
||||
// Signing Pub Key must be for Source Account ID.
|
||||
cLog(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID();
|
||||
cLog(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID();
|
||||
|
||||
terResult = temBAD_SET_ID;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Verify the transaction's signing public key is the key authorized for signing.
|
||||
if (bHaveAuthKey && naSigningPubKey.getAccountID() == mTxnAccount->getFieldAccount(sfAuthorizedKey).getAccountID())
|
||||
{
|
||||
// Authorized to continue.
|
||||
nothing();
|
||||
}
|
||||
else if (naSigningPubKey.getAccountID() == mTxnAccountID)
|
||||
{
|
||||
// Authorized to continue.
|
||||
nothing();
|
||||
}
|
||||
else if (bHaveAuthKey)
|
||||
{
|
||||
cLog(lsINFO) << "applyTransaction: Delay: Not authorized to use account.";
|
||||
|
||||
terResult = tefBAD_AUTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "applyTransaction: Invalid: Not authorized to use account.";
|
||||
|
||||
terResult = temBAD_AUTH_MASTER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Deduct the fee, so it's not available during the transaction.
|
||||
// Will only write the account back, if the transaction succeeds.
|
||||
if (tesSUCCESS != terResult || !saCost)
|
||||
{
|
||||
nothing();
|
||||
}
|
||||
else if (saSrcBalance < saPaid)
|
||||
{
|
||||
cLog(lsINFO)
|
||||
<< boost::str(boost::format("applyTransaction: Delay: insufficient balance: balance=%s paid=%s")
|
||||
% saSrcBalance.getText()
|
||||
% saPaid.getText());
|
||||
|
||||
terResult = terINSUF_FEE_B;
|
||||
}
|
||||
else
|
||||
{
|
||||
mTxnAccount->setFieldAmount(sfBalance, saSrcBalance - saPaid);
|
||||
}
|
||||
|
||||
// Validate sequence
|
||||
if (tesSUCCESS != terResult)
|
||||
{
|
||||
nothing();
|
||||
}
|
||||
else if (saCost)
|
||||
{
|
||||
uint32 a_seq = mTxnAccount->getFieldU32(sfSequence);
|
||||
|
||||
cLog(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
|
||||
|
||||
if (t_seq != a_seq)
|
||||
{
|
||||
if (a_seq < t_seq)
|
||||
{
|
||||
cLog(lsINFO) << "applyTransaction: future sequence number";
|
||||
|
||||
terResult = terPRE_SEQ;
|
||||
}
|
||||
else if (mLedger->hasTransaction(txID))
|
||||
terResult = tefALREADY;
|
||||
else
|
||||
{
|
||||
cLog(lsWARNING) << "applyTransaction: past sequence number";
|
||||
if (!mLedger->addTransaction(txID, s, m))
|
||||
assert(false);
|
||||
|
||||
terResult = tefPAST_SEQ;
|
||||
STAmount saPaid = txn.getTransactionFee();
|
||||
// Charge whatever fee they specified.
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
mTxnAccount.reset();
|
||||
mNodes.clear();
|
||||
|
||||
if (!isSetBit(params, tapOPEN_LEDGER)
|
||||
&& (isTemMalformed(terResult) || isTefFailure(terResult)))
|
||||
{
|
||||
mTxnAccount->setFieldU32(sfSequence, t_seq + 1);
|
||||
// XXX Malformed or failed transaction in closed ledger must bow out.
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
return terResult;
|
||||
}else
|
||||
{
|
||||
cLog(lsINFO) << "applyTransaction: Zero cost transaction";
|
||||
|
||||
if (t_seq)
|
||||
{
|
||||
cLog(lsINFO) << "applyTransaction: bad sequence for pre-paid transaction";
|
||||
|
||||
terResult = tefPAST_SEQ;
|
||||
}
|
||||
cLog(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type";
|
||||
return temUNKNOWN;
|
||||
}
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
entryModify(mTxnAccount);
|
||||
|
||||
switch (txn.getTxnType())
|
||||
{
|
||||
case ttACCOUNT_SET:
|
||||
terResult = doAccountSet(txn);
|
||||
break;
|
||||
|
||||
case ttCLAIM:
|
||||
terResult = doClaim(txn);
|
||||
break;
|
||||
|
||||
case ttTRUST_SET:
|
||||
terResult = doTrustSet(txn);
|
||||
break;
|
||||
|
||||
case ttINVALID:
|
||||
cLog(lsINFO) << "applyTransaction: invalid type";
|
||||
terResult = temINVALID;
|
||||
break;
|
||||
|
||||
//case ttINVOICE:
|
||||
// terResult = doInvoice(txn);
|
||||
// break;
|
||||
|
||||
case ttOFFER_CREATE:
|
||||
terResult = doOfferCreate(txn);
|
||||
break;
|
||||
|
||||
case ttOFFER_CANCEL:
|
||||
terResult = doOfferCancel(txn);
|
||||
break;
|
||||
|
||||
case ttREGULAR_KEY_SET:
|
||||
terResult = doRegularKeySet(txn);
|
||||
break;
|
||||
|
||||
case ttPAYMENT:
|
||||
terResult = doPayment(txn, params);
|
||||
break;
|
||||
|
||||
case ttWALLET_ADD:
|
||||
terResult = doWalletAdd(txn);
|
||||
break;
|
||||
|
||||
case ttCONTRACT:
|
||||
terResult = doContractAdd(txn);
|
||||
break;
|
||||
case ttCONTRACT_REMOVE:
|
||||
terResult = doContractRemove(txn);
|
||||
break;
|
||||
|
||||
default:
|
||||
terResult = temUNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string strToken;
|
||||
std::string strHuman;
|
||||
|
||||
transResultInfo(terResult, strToken, strHuman);
|
||||
|
||||
cLog(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman;
|
||||
|
||||
if (isTepPartial(terResult) && isSetBit(params, tapRETRY))
|
||||
{
|
||||
// Partial result and allowed to retry, reclassify as a retry.
|
||||
terResult = terRETRY;
|
||||
}
|
||||
|
||||
if ((tesSUCCESS == terResult) || isTepPartial(terResult))
|
||||
{
|
||||
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
|
||||
Serializer m;
|
||||
mNodes.calcRawMeta(m, terResult);
|
||||
|
||||
txnWrite();
|
||||
|
||||
Serializer s;
|
||||
txn.add(s);
|
||||
|
||||
if (isSetBit(params, tapOPEN_LEDGER))
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s))
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s, m))
|
||||
assert(false);
|
||||
|
||||
// Charge whatever fee they specified.
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
}
|
||||
}
|
||||
|
||||
mTxnAccount.reset();
|
||||
mNodes.clear();
|
||||
|
||||
if (!isSetBit(params, tapOPEN_LEDGER)
|
||||
&& (isTemMalformed(terResult) || isTefFailure(terResult)))
|
||||
{
|
||||
// XXX Malformed or failed transaction in closed ledger must bow out.
|
||||
}
|
||||
|
||||
return terResult;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
|
||||
Reference in New Issue
Block a user