diff --git a/src/Transaction.cpp b/src/Transaction.cpp index cdc051806..cf76b88b5 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -57,8 +57,9 @@ Transaction::Transaction( const NewcoinAddress& naSourceAccount, uint32 uSeq, uint64 uFee, - uint32 uSourceTag) : - mInLedger(0), mStatus(NEW) + uint32 uSourceTag, + uint32 uLedger) : + mStatus(NEW) { mAccountFrom = naSourceAccount; mFromPubKey = naPublicKey; @@ -78,6 +79,12 @@ Transaction::Transaction( mTransaction->makeITFieldPresent(sfSourceTag); mTransaction->setITFieldU32(sfSourceTag, uSourceTag); } + + if (uLedger) + { + mTransaction->makeITFieldPresent(sfTargetLedger); + mTransaction->setITFieldU32(sfTargetLedger, uLedger); + } } bool Transaction::sign(const NewcoinAddress& naAccountPrivate) @@ -148,6 +155,41 @@ Transaction::pointer Transaction::sharedClaim( return tResult->setClaim(naPrivateKey, vucGenerator, vucPubKey, vucSignature); } +// +// Create +// + +Transaction::pointer Transaction::setCreate( + const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naCreateAccountID, + uint64 uFund) +{ + mTransaction->setITFieldU32(sfFlags, tfCreateAccount); + mTransaction->setITFieldAccount(sfDestination, naCreateAccountID); + mTransaction->setITFieldU64(sfAmount, uFund); + + sign(naPrivateKey); + + return shared_from_this(); +} + +Transaction::pointer Transaction::sharedCreate( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + uint64 uFee, + uint32 uSourceTag, + uint32 uLedger, + const NewcoinAddress& naCreateAccountID, + uint64 uFund) +{ + pointer tResult = boost::make_shared(ttPAYMENT, + naPublicKey, naSourceAccount, + uSeq, uFee, uSourceTag, uLedger); + + return tResult->setCreate(naPrivateKey, naCreateAccountID, uFund); +} + // // Payment // @@ -155,18 +197,11 @@ Transaction::pointer Transaction::sharedClaim( Transaction::pointer Transaction::setPayment( const NewcoinAddress& naPrivateKey, const NewcoinAddress& toAccount, - uint64 uAmount, - uint32 ledger) + uint64 uAmount) { mTransaction->setITFieldAccount(sfDestination, toAccount); mTransaction->setITFieldU64(sfAmount, uAmount); - if (ledger != 0) - { - mTransaction->makeITFieldPresent(sfTargetLedger); - mTransaction->setITFieldU32(sfTargetLedger, ledger); - } - sign(naPrivateKey); return shared_from_this(); @@ -178,15 +213,15 @@ Transaction::pointer Transaction::sharedPayment( uint32 uSeq, uint64 uFee, uint32 uSourceTag, + uint32 uLedger, const NewcoinAddress& toAccount, - uint64 uAmount, - uint32 ledger) + uint64 uAmount) { - pointer tResult = boost::make_shared(ttMAKE_PAYMENT, + pointer tResult = boost::make_shared(ttPAYMENT, naPublicKey, naSourceAccount, - uSeq, uFee, uSourceTag); + uSeq, uFee, uSourceTag, uLedger); - return tResult->setPayment(naPrivateKey, toAccount, uAmount, ledger); + return tResult->setPayment(naPrivateKey, toAccount, uAmount); } // diff --git a/src/Transaction.h b/src/Transaction.h index 52c93471f..eb6c86703 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -47,18 +47,22 @@ private: SerializedTransaction::pointer mTransaction; - Transaction::pointer setPayment( - const NewcoinAddress& naPrivateKey, - const NewcoinAddress& toAccount, - uint64 uAmount, - uint32 ledger); - Transaction::pointer setClaim( const NewcoinAddress& naPrivateKey, const std::vector& vucGenerator, const std::vector& vucPubKey, const std::vector& vucSignature); + Transaction::pointer setCreate( + const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naCreateAccountID, + uint64 uFund); + + Transaction::pointer setPayment( + const NewcoinAddress& naPrivateKey, + const NewcoinAddress& toAccount, + uint64 uAmount); + public: Transaction(const SerializedTransaction::pointer st, bool bValidate); @@ -66,22 +70,14 @@ public: Transaction( TransactionType ttKind, - const NewcoinAddress& naPublicKey, - const NewcoinAddress& naSourceAccount, - uint32 uSeq, - uint64 uFee, - uint32 uSourceTag); - - static Transaction::pointer sharedPayment( - const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, - const NewcoinAddress& naSourceAccount, - uint32 uSeq, - uint64 uFee, - uint32 uSourceTag, - const NewcoinAddress& toAccount, - uint64 uAmount, - uint32 ledger); + const NewcoinAddress& naPublicKey, // To prove transaction is consistent and authorized. + const NewcoinAddress& naSourceAccount, // To identify the paying account. + uint32 uSeq, // To order transactions. + uint64 uFee, // Transaction fee. + uint32 uSourceTag, // User call back value. + uint32 uLedger=0); + // Claim a wallet. static Transaction::pointer sharedClaim( const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, const NewcoinAddress& naSourceAccount, @@ -89,6 +85,29 @@ public: const std::vector& vucGenerator, const std::vector& vucPubKey, const std::vector& vucSignature); + + // Create an account. + static Transaction::pointer sharedCreate( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + uint64 uFee, + uint32 uSourceTag, + uint32 uLedger, + const NewcoinAddress& naCreateAccountID, // Account to create. + uint64 uFund); // Initial funds in XNC. + + // Make a payment. + static Transaction::pointer sharedPayment( + const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey, + const NewcoinAddress& naSourceAccount, + uint32 uSeq, + uint64 uFee, + uint32 uSourceTag, + uint32 uLedger, + const NewcoinAddress& toAccount, + uint64 uAmount); + #if 0 Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID, CKey::pointer pubKey, uint64 uAmount, uint64 fee, uint32 fromSeq, uint32 fromLedger, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 64c7da433..e53d89380 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -29,7 +29,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // check signature if (!txn.checkSign(naPubKey)) { - std::cerr << "applyTransaction: invalid signature" << std::endl; + std::cerr << "applyTransaction: Invalid transaction: bad signature" << std::endl; return tenINVALID; } @@ -42,19 +42,19 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran bPrepaid = true; break; - case ttMAKE_PAYMENT: + case ttPAYMENT: case ttINVOICE: case ttEXCHANGE_OFFER: result = terSUCCESS; break; case ttINVALID: - std::cerr << "applyTransaction: ttINVALID transaction type" << std::endl; + std::cerr << "applyTransaction: Invalid transaction: ttINVALID transaction type" << std::endl; result = tenINVALID; break; default: - std::cerr << "applyTransaction: unknown transaction type" << std::endl; + std::cerr << "applyTransaction: Invalid transaction: unknown transaction type" << std::endl; result = tenUNKNOWN; break; } @@ -85,9 +85,9 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } } - // get source account ID - uint160 srcAccount = txn.getSourceAccount().getAccountID(); - if (!srcAccount) + // Get source account ID. + uint160 srcAccountID = txn.getSourceAccount().getAccountID(); + if (!srcAccountID) { std::cerr << "applyTransaction: bad source id" << std::endl; return tenINVALID; @@ -98,10 +98,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // find source account // If we are only verifying some transactions, this would be probablistic. LedgerStateParms qry = lepNONE; - SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccount); + SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccountID); if (!src) { - std::cerr << str(boost::format("applyTransaction: no such account: %s") % txn.getSourceAccount().humanAccountID()) << std::endl; + std::cerr << str(boost::format("applyTransaction: Delay transaction: source account does not exisit: %s") % txn.getSourceAccount().humanAccountID()) << std::endl; return terNO_ACCOUNT; } @@ -109,15 +109,15 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // we only write the account back if the transaction succeeds if (txnFee) { - uint64 balance = src->getIFieldU64(sfBalance); + uint64 uSrcBalance = src->getIFieldU64(sfBalance); - if (balance < txnFee) + if (uSrcBalance < txnFee) { - std::cerr << "applyTransaction: insufficent balance" << std::endl; + std::cerr << "applyTransaction: Delay transaction: insufficent balance" << std::endl; return terINSUF_FEE_B; } - src->setIFieldU64(sfBalance, balance - txnFee); + src->setIFieldU64(sfBalance, uSrcBalance - txnFee); } // Validate sequence @@ -169,8 +169,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran result = doClaim(txn, accounts); break; - case ttMAKE_PAYMENT: - result = doPayment(txn, accounts); + case ttPAYMENT: + result = doPayment(txn, accounts, srcAccountID); break; case ttINVOICE: @@ -308,43 +308,82 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& } TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, - std::vector& accounts) + std::vector& accounts, + uint160 srcAccountID) { - uint32 txFlags = txn.getFlags(); - uint160 destAccount = txn.getITFieldAccount(sfDestination); + uint32 txFlags = txn.getFlags(); + uint160 dstAccountID = txn.getITFieldAccount(sfDestination); // Does the destination account exist? - if (!destAccount) return tenINVALID; + if (!dstAccountID) + { + std::cerr << "doPayment: Invalid transaction: Payment destination account not specifed." << std::endl; + return tenINVALID; + } + else if (srcAccountID == dstAccountID) + { + std::cerr << "doPayment: Invalid transaction: Source account is the same as destination." << std::endl; + return tenINVALID; + } + + bool bCreate = !(txFlags & tfCreateAccount); + + uint160 currency; + if (txn.getITFieldPresent(sfCurrency)) + currency = txn.getITFieldH160(sfCurrency); + // XXX No XNC don't allow currency. + LedgerStateParms qry = lepNONE; - // FIXME: If this transfer is to the same account, bad things will happen - SerializedLedgerEntry::pointer dest = mLedger->getAccountRoot(qry, destAccount); + SerializedLedgerEntry::pointer dest = mLedger->getAccountRoot(qry, dstAccountID); if (!dest) - { // can this transaction create an account - if ((txFlags & 0x00010000) == 0) // no + { + // Destination account does not exist. + if (bCreate && !!currency) + { + std::cerr << "doPayment: Invalid transaction: Create account may only fund XBC." << std::endl; + return tenCREATEXNC; + } + else if (!bCreate) + { + std::cerr << "doPayment: Delay transaction: Destination account does not exist." << std::endl; return terNO_TARGET; + } + // Create the account. dest = boost::make_shared(ltACCOUNT_ROOT); - dest->setIndex(Ledger::getAccountRootIndex(destAccount)); - dest->setIFieldAccount(sfAccount, destAccount); + + dest->setIndex(Ledger::getAccountRootIndex(dstAccountID)); + dest->setIFieldAccount(sfAccount, dstAccountID); dest->setIFieldU32(sfSequence, 1); + accounts.push_back(std::make_pair(taaCREATE, dest)); } - else accounts.push_back(std::make_pair(taaMODIFY, dest)); - - uint64 amount = txn.getITFieldU64(sfAmount); - - uint160 currency; - if(txn.getITFieldPresent(sfCurrency)) - currency = txn.getITFieldH160(sfCurrency); - bool native = !!currency; - - if (native) + // Destination exists. + else if (bCreate) { - uint64 balance = accounts[0].second->getIFieldU64(sfBalance); - if (balance < amount) return terUNFUNDED; - accounts[0].second->setIFieldU64(sfBalance, balance - amount); - accounts[1].second->setIFieldU64(sfBalance, accounts[1].second->getIFieldU64(sfBalance) + amount); + std::cerr << "doPayment: Invalid transaction: Account already created." << std::endl; + return tenCREATED; + } + else + { + accounts.push_back(std::make_pair(taaMODIFY, dest)); + } + + uint64 uAmount = txn.getITFieldU64(sfAmount); + + if (!currency) + { + uint64 uSrcBalance = accounts[0].second->getIFieldU64(sfBalance); + + if (uSrcBalance < uAmount) + { + std::cerr << "doPayment: Delay transaction: Insufficent funds." << std::endl; + return terUNFUNDED; + } + + accounts[0].second->setIFieldU64(sfBalance, uSrcBalance - uAmount); + accounts[1].second->setIFieldU64(sfBalance, accounts[1].second->getIFieldU64(sfBalance) + uAmount); } else { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 254e3dde0..9a0c50317 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -13,9 +13,17 @@ enum TransactionEngineResult { // tenCAN_NEVER_SUCCEED = <0 - tenGEN_IN_USE = -100, // Generator already in use. + + // Malformed + tenGEN_IN_USE = -300, // Generator already in use. + tenCREATEXNC, // Can not specify non XNC for Create. + + // Not possible due to ledger database. + tenCREATED = -200, // Can not create a previously created account. tenCLAIMED, // Can not claim a previously claimed account. - tenFAILED, // Something broke horribly + + // Other + tenFAILED = -100, // Something broke horribly tenUNKNOWN, // The transactions requires logic not implemented yet tenINSUF_FEE_P, // fee totally insufficient tenINVALID, // The transaction is ill-formed @@ -63,7 +71,8 @@ protected: TransactionEngineResult doDelete(const SerializedTransaction&, std::vector&); TransactionEngineResult doInvoice(const SerializedTransaction&, std::vector&); TransactionEngineResult doOffer(const SerializedTransaction&, std::vector&); - TransactionEngineResult doPayment(const SerializedTransaction&, std::vector&); + TransactionEngineResult doPayment(const SerializedTransaction&, std::vector&, + uint160 srcAccountID); TransactionEngineResult doStore(const SerializedTransaction&, std::vector&); TransactionEngineResult doTake(const SerializedTransaction&, std::vector&); diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index c541322a0..070233965 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -5,7 +5,7 @@ TransactionFormat InnerTxnFormats[]= { - { "MakePayment", ttMAKE_PAYMENT, { + { "Payment", ttPAYMENT, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index ed851be04..fc1d70d94 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -6,7 +6,7 @@ enum TransactionType { ttINVALID = -1, - ttMAKE_PAYMENT = 0, + ttPAYMENT = 0, ttCLAIM = 1, ttINVOICE = 2, ttEXCHANGE_OFFER = 3 @@ -31,6 +31,9 @@ const int TransactionIFee = 5; const int TransactionMinLen=32; const int TransactionMaxLen=1048576; +// Transaction flags. +const uint32 tfCreateAccount = 0x00010000; + extern TransactionFormat InnerTxnFormats[]; extern TransactionFormat* getTxnFormat(TransactionType t); #endif