Transaction::pointer Transaction::transactionFromSQL (Database* db, bool bValidate) { Serializer rawTxn; std::string status; uint32 inLedger; int txSize = 2048; rawTxn.resize (txSize); db->getStr ("Status", status); inLedger = db->getInt ("LedgerSeq"); txSize = db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ()); if (txSize > rawTxn.getLength ()) { rawTxn.resize (txSize); db->getBinary ("RawTxn", &*rawTxn.begin (), rawTxn.getLength ()); } rawTxn.resize (txSize); SerializerIterator it (rawTxn); SerializedTransaction::pointer txn = boost::make_shared<SerializedTransaction> (boost::ref (it)); Transaction::pointer tr = boost::make_shared<Transaction> (txn, bValidate); TransStatus st (INVALID); switch (status[0]) { case TXN_SQL_NEW: st = NEW; break; case TXN_SQL_CONFLICT: st = CONFLICTED; break; case TXN_SQL_HELD: st = HELD; break; case TXN_SQL_VALIDATED: st = COMMITTED; break; case TXN_SQL_INCLUDED: st = INCLUDED; break; case TXN_SQL_UNKNOWN: break; default: assert (false); } tr->setStatus (st); tr->setLedger (inLedger); return tr; }
SerializedTransaction::pointer TransactionMaster::fetch (SHAMapItem::ref item, SHAMapTreeNode::TNType type, bool checkDisk, uint32 uCommitLedger) { SerializedTransaction::pointer txn; Transaction::pointer iTx = getApp().getMasterTransaction ().fetch (item->getTag (), false); if (!iTx) { if (type == SHAMapTreeNode::tnTRANSACTION_NM) { SerializerIterator sit (item->peekSerializer ()); txn = boost::make_shared<SerializedTransaction> (boost::ref (sit)); } else if (type == SHAMapTreeNode::tnTRANSACTION_MD) { Serializer s; int length; item->peekSerializer ().getVL (s.modData (), 0, length); SerializerIterator sit (s); txn = boost::make_shared<SerializedTransaction> (boost::ref (sit)); } } else { if (uCommitLedger) iTx->setStatus (COMMITTED, uCommitLedger); txn = iTx->getSTransaction (); } return txn; }
STTx::pointer TransactionMaster::fetch (std::shared_ptr<SHAMapItem> const& item, SHAMapTreeNode::TNType type, bool checkDisk, std::uint32_t uCommitLedger) { STTx::pointer txn; Transaction::pointer iTx = getApp().getMasterTransaction ().fetch (item->getTag (), false); if (!iTx) { if (type == SHAMapTreeNode::tnTRANSACTION_NM) { SerialIter sit (item->slice()); txn = std::make_shared<STTx> (std::ref (sit)); } else if (type == SHAMapTreeNode::tnTRANSACTION_MD) { Serializer s; int length; item->peekSerializer().getVL (s.modData (), 0, length); SerialIter sit (s.slice()); txn = std::make_shared<STTx> (std::ref (sit)); } } else { if (uCommitLedger) iTx->setStatus (COMMITTED, uCommitLedger); txn = iTx->getSTransaction (); } return txn; }
// { // ledger_hash : <ledger>, // ledger_index : <ledger_index> // } // // XXX In this case, not specify either ledger does not mean ledger current. It // means any ledger. Json::Value doTransactionEntry (RPC::Context& context) { Ledger::pointer lpLedger; Json::Value jvResult = RPC::lookupLedger ( context.params_, lpLedger, context.netOps_); if (!lpLedger) return jvResult; if (!context.params_.isMember ("tx_hash")) { jvResult["error"] = "fieldNotFoundTransaction"; } else if (!context.params_.isMember ("ledger_hash") && !context.params_.isMember ("ledger_index")) { // We don't work on ledger current. // XXX We don't support any transaction yet. jvResult["error"] = "notYetImplemented"; } else { uint256 uTransID; // XXX Relying on trusted WSS client. Would be better to have a strict // routine, returning success or failure. uTransID.SetHex (context.params_["tx_hash"].asString ()); if (!lpLedger) { jvResult["error"] = "ledgerNotFound"; } else { Transaction::pointer tpTrans; TransactionMetaSet::pointer tmTrans; if (!lpLedger->getTransaction (uTransID, tpTrans, tmTrans)) { jvResult["error"] = "transactionNotFound"; } else { jvResult["tx_json"] = tpTrans->getJson (0); if (tmTrans) jvResult["metadata"] = tmTrans->getJson (0); // 'accounts' // 'engine_...' // 'ledger_...' } } } return jvResult; }
bool TransactionMaster::inLedger (uint256 const& hash, std::uint32_t ledger) { Transaction::pointer txn = mCache.fetch (hash); if (!txn) return false; txn->setStatus (COMMITTED, ledger); return true; }
void find_transaction_history (){ uint256 hash; char hash_ch[32]; for (int i = 0; i < 32; ++i) hash_ch[i] = i; hash_ch[0] = 1; hash_ch[1] = 2; hash.init (hash_ch); // vector <Transaction::pointer> vet; Account::pointer acc = Bubi::last_ledger->get_account_entry (hash); uint256 tx_hash; std::uint32_t tx_seq; tx_seq = acc->get_previous_ledger_seq (); tx_hash = acc->get_previous_tx_hash (); while ( tx_seq != 0 ){ Transaction::pointer tx = Bubi::last_ledger->get_transaction_entry (tx_hash); std::cout << "------------------------------------" << std::endl; std::cout << tx->get_source_address ().to_string () << std::endl; std::cout << tx->get_destination_address ().to_string () << std::endl; std::cout << tx->get_payment_amount () << std::endl; if (hash == tx->get_source_address ()){ tx_seq = tx->get_source_previous_ledger_seq (); tx_hash = tx->get_source_previous_tx_hash (); } else { tx_seq = tx->get_destination_previous_ledger_seq (); tx_hash = tx->get_destination_previous_tx_hash (); } } }
// DAVID: would you rather duplicate this code or keep the lock longer? Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) { Serializer rawTxn; std::string status; uint32 inLedger; int txSize = 2048; rawTxn.resize(txSize); { ScopedLock sl(theApp->getTxnDB()->getDBLock()); Database* db = theApp->getTxnDB()->getDB(); if (!db->executeSQL(sql, true) || !db->startIterRows()) return Transaction::pointer(); db->getStr("Status", status); inLedger = db->getInt("LedgerSeq"); txSize = db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.getLength()); if (txSize > rawTxn.getLength()) { rawTxn.resize(txSize); db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.getLength()); } db->endIterRows(); } rawTxn.resize(txSize); SerializerIterator it(rawTxn); SerializedTransaction::pointer txn = boost::make_shared<SerializedTransaction>(boost::ref(it)); Transaction::pointer tr = boost::make_shared<Transaction>(txn, true); TransStatus st(INVALID); switch (status[0]) { case TXN_SQL_NEW: st = NEW; break; case TXN_SQL_CONFLICT: st = CONFLICTED; break; case TXN_SQL_HELD: st = HELD; break; case TXN_SQL_VALIDATED: st = COMMITTED; break; case TXN_SQL_INCLUDED: st = INCLUDED; break; case TXN_SQL_UNKNOWN: break; default: assert(false); } tr->setStatus(st); tr->setLedger(inLedger); return tr; }
bool TransactionMaster::canonicalize (Transaction::pointer* pTransaction) { Transaction::pointer txn (*pTransaction); uint256 tid = txn->getID (); if (!tid) return false; // VFALCO NOTE canonicalize can change the value of txn! if (mCache.canonicalize (tid, txn)) { *pTransaction = txn; return true; } // VFALCO NOTE I am unsure if this is necessary but better safe than sorry. *pTransaction = txn; return false; }
std::vector <Transaction::pointer> get_transaction_history (std::string acc_pub){ uint256 hash = string_address_to_uint256 (acc_pub); Account::pointer acc = Bubi::last_ledger->get_account_entry (hash); std::vector <Transaction::pointer> res; uint256 tx_hash; std::uint32_t tx_seq; tx_seq = acc->get_previous_ledger_seq (); tx_hash = acc->get_previous_tx_hash (); while ( tx_seq != 0 ){ Transaction::pointer tx = Bubi::last_ledger->get_transaction_entry (tx_hash); res.push_back (tx); /* std::cout << "------------------------------------" << std::endl; std::cout << tx->get_source_address ().to_string () << std::endl; std::cout << tx->get_destination_address ().to_string () << std::endl; std::cout << tx->get_payment_amount () << std::endl; */ if (hash == tx->get_source_address ()){ tx_seq = tx->get_source_previous_ledger_seq (); tx_hash = tx->get_source_previous_tx_hash (); } else { tx_seq = tx->get_destination_previous_ledger_seq (); tx_hash = tx->get_destination_previous_tx_hash (); } } return res; }
bool ConsensusTransSetSF::haveNode (const SHAMapNode& id, uint256 const& nodeHash, Blob& nodeData) { if (getApp().getTempNodeCache ().retrieve (nodeHash, nodeData)) return true; Transaction::pointer txn = getApp().getMasterTransaction().fetch(nodeHash, false); if (txn) { // this is a transaction, and we have it WriteLog (lsDEBUG, TransactionAcquire) << "Node in our acquiring TX set is TXN we have"; Serializer s; s.add32 (HashPrefix::transactionID); txn->getSTransaction ()->add (s, true); assert (s.getSHA512Half () == nodeHash); nodeData = s.peekData (); return true; } return false; }
// { // transaction: <hex> // } Json::Value doTx (RPC::Context& context) { context.lock_.unlock (); if (!context.params_.isMember (jss::transaction)) return rpcError (rpcINVALID_PARAMS); bool binary = context.params_.isMember (jss::binary) && context.params_[jss::binary].asBool (); std::string strTransaction = context.params_[jss::transaction].asString (); if (Transaction::isHexTxID (strTransaction)) { // transaction by ID uint256 txid (strTransaction); Transaction::pointer txn = getApp().getMasterTransaction ().fetch (txid, true); if (!txn) return rpcError (rpcTXN_NOT_FOUND); #ifdef READY_FOR_NEW_TX_FORMAT Json::Value ret; ret[jss::transaction] = txn->getJson (0, binary); #else Json::Value ret = txn->getJson (0, binary); #endif if (txn->getLedger () != 0) { Ledger::pointer lgr = context.netOps_.getLedgerBySeq (txn->getLedger ()); if (lgr) { bool okay = false; if (binary) { std::string meta; if (lgr->getMetaHex (txid, meta)) { ret[jss::meta] = meta; okay = true; } } else { TransactionMetaSet::pointer set; if (lgr->getTransactionMeta (txid, set)) { okay = true; ret[jss::meta] = set->getJson (0); } } if (okay) ret[jss::validated] = context.netOps_.isValidated (lgr); } } return ret; } return rpcError (rpcNOT_IMPL); }
// { // transaction: <hex> // } Json::Value RPCHandler::doTx (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { masterLockHolder.unlock (); if (!params.isMember ("transaction")) return rpcError (rpcINVALID_PARAMS); bool binary = params.isMember ("binary") && params["binary"].asBool (); std::string strTransaction = params["transaction"].asString (); if (Transaction::isHexTxID (strTransaction)) { // transaction by ID uint256 txid (strTransaction); Transaction::pointer txn = getApp().getMasterTransaction ().fetch (txid, true); if (!txn) return rpcError (rpcTXN_NOT_FOUND); #ifdef READY_FOR_NEW_TX_FORMAT Json::Value ret; ret["transaction"] = txn->getJson (0, binary); #else Json::Value ret = txn->getJson (0, binary); #endif if (txn->getLedger () != 0) { Ledger::pointer lgr = mNetOps->getLedgerBySeq (txn->getLedger ()); if (lgr) { bool okay = false; if (binary) { std::string meta; if (lgr->getMetaHex (txid, meta)) { ret["meta"] = meta; okay = true; } } else { TransactionMetaSet::pointer set; if (lgr->getTransactionMeta (txid, set)) { okay = true; ret["meta"] = set->getJson (0); } } if (okay) ret["validated"] = mNetOps->isValidated (lgr); } } return ret; } return rpcError (rpcNOT_IMPL); }
// VFALCO TODO This function should take a reference to the params, modify it // as needed, and then there should be a separate function to // submit the transaction. // Json::Value transactionSign ( Json::Value params, bool bSubmit, bool bFailHard, RPCDetail::LedgerFacade& ledgerFacade, Role role) { Json::Value jvResult; WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << params; if (! params.isMember ("secret")) return RPC::missing_field_error ("secret"); if (! params.isMember ("tx_json")) return RPC::missing_field_error ("tx_json"); RippleAddress naSeed; if (! naSeed.setSeedGeneric (params["secret"].asString ())) return RPC::make_error (rpcBAD_SEED, RPC::invalid_field_message ("secret")); Json::Value& tx_json (params ["tx_json"]); if (! tx_json.isObject ()) return RPC::object_field_error ("tx_json"); if (! tx_json.isMember ("TransactionType")) return RPC::missing_field_error ("tx_json.TransactionType"); std::string const sType = tx_json ["TransactionType"].asString (); if (! tx_json.isMember ("Account")) return RPC::make_error (rpcSRC_ACT_MISSING, RPC::missing_field_message ("tx_json.Account")); RippleAddress raSrcAddressID; if (! raSrcAddressID.setAccountID (tx_json["Account"].asString ())) return RPC::make_error (rpcSRC_ACT_MALFORMED, RPC::invalid_field_message ("tx_json.Account")); bool const verify = !(params.isMember ("offline") && params["offline"].asBool ()); if (!tx_json.isMember ("Sequence") && !verify) return RPC::missing_field_error ("tx_json.Sequence"); // Check for current ledger. if (verify && !getConfig ().RUN_STANDALONE && (ledgerFacade.getValidatedLedgerAge () > 120)) return rpcError (rpcNO_CURRENT); // Check for load. if (ledgerFacade.isLoadedCluster () && (role != Role::ADMIN)) return rpcError (rpcTOO_BUSY); ledgerFacade.snapshotAccountState (raSrcAddressID); if (verify) { if (!ledgerFacade.isValidAccount ()) { // If not offline and did not find account, error. WriteLog (lsDEBUG, RPCHandler) << "transactionSign: Failed to find source account " << "in current ledger: " << raSrcAddressID.humanAccountID (); return rpcError (rpcSRC_ACT_NOT_FOUND); } } autofill_fee (params, ledgerFacade, jvResult, role == Role::ADMIN); if (RPC::contains_error (jvResult)) return jvResult; if ("Payment" == sType) { auto e = signPayment( params, tx_json, raSrcAddressID, ledgerFacade, role); if (contains_error(e)) return e; } if (!tx_json.isMember ("Sequence")) tx_json["Sequence"] = ledgerFacade.getSeq (); if (!tx_json.isMember ("Flags")) tx_json["Flags"] = tfFullyCanonicalSig; if (verify) { if (!ledgerFacade.hasAccountRoot ()) // XXX Ignore transactions for accounts not created. return rpcError (rpcSRC_ACT_NOT_FOUND); } RippleAddress secret = RippleAddress::createSeedGeneric ( params["secret"].asString ()); RippleAddress masterGenerator = RippleAddress::createGeneratorPublic ( secret); RippleAddress masterAccountPublic = RippleAddress::createAccountPublic ( masterGenerator, 0); if (verify) { WriteLog (lsTRACE, RPCHandler) << "verify: " << masterAccountPublic.humanAccountID () << " : " << raSrcAddressID.humanAccountID (); auto const secretAccountID = masterAccountPublic.getAccountID(); if (raSrcAddressID.getAccountID () == secretAccountID) { if (ledgerFacade.accountMasterDisabled ()) return rpcError (rpcMASTER_DISABLED); } else if (!ledgerFacade.accountMatchesRegularKey (secretAccountID)) { return rpcError (rpcBAD_SECRET); } } STParsedJSONObject parsed ("tx_json", tx_json); if (!parsed.object.get()) { jvResult ["error"] = parsed.error ["error"]; jvResult ["error_code"] = parsed.error ["error_code"]; jvResult ["error_message"] = parsed.error ["error_message"]; return jvResult; } std::unique_ptr<STObject> sopTrans = std::move(parsed.object); sopTrans->setFieldVL ( sfSigningPubKey, masterAccountPublic.getAccountPublic ()); STTx::pointer stpTrans; try { stpTrans = std::make_shared<STTx> (*sopTrans); //WriteLog(lsINFO, RPCHandler) << "radar: before sign " << stpTrans->getFieldAmount(sfAmount); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } std::string reason; if (!passesLocalChecks (*stpTrans, reason)) return RPC::make_error (rpcINVALID_PARAMS, reason); if (params.isMember ("debug_signing")) { jvResult["tx_unsigned"] = strHex ( stpTrans->getSerializer ().peekData ()); jvResult["tx_signing_hash"] = to_string (stpTrans->getSigningHash ()); } // FIXME: For performance, transactions should not be signed in this code // path. RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate ( masterGenerator, secret, 0); stpTrans->sign (naAccountPrivate); Transaction::pointer tpTrans; try { //WriteLog(lsINFO, RPCHandler) << "radar: after sign " << stpTrans->getFieldAmount(sfAmount); tpTrans = std::make_shared<Transaction>(stpTrans, Validate::NO); //WriteLog(lsINFO, RPCHandler) << "radar: after copy" << tpTrans->getSTransaction()->getFieldAmount(sfAmount); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } try { // FIXME: For performance, should use asynch interface. tpTrans = ledgerFacade.submitTransactionSync (tpTrans, role == Role::ADMIN, true, bFailHard, bSubmit); if (!tpTrans) { return RPC::make_error (rpcINTERNAL, "Unable to sterilize transaction."); } } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction submission."); } try { jvResult["tx_json"] = tpTrans->getJson (0); jvResult["tx_blob"] = strHex ( tpTrans->getSTransaction ()->getSerializer ().peekData ()); if (temUNCERTAIN != tpTrans->getResult ()) { std::string sToken; std::string sHuman; transResultInfo (tpTrans->getResult (), sToken, sHuman); jvResult["engine_result"] = sToken; jvResult["engine_result_code"] = tpTrans->getResult (); jvResult["engine_result_message"] = sHuman; } return jvResult; } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during JSON handling."); } }
// VFALCO TODO This function should take a reference to the params, modify it // as needed, and then there should be a separate function to // submit the transaction // Json::Value transactionSign ( Json::Value params, bool bSubmit, bool bFailHard, Application::ScopedLockType& mlh, NetworkOPs& netOps, int role) { Json::Value jvResult; WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << params; if (! params.isMember ("secret")) return RPC::missing_field_error ("secret"); if (! params.isMember ("tx_json")) return RPC::missing_field_error ("tx_json"); RippleAddress naSeed; if (! naSeed.setSeedGeneric (params["secret"].asString ())) return RPC::make_error (rpcBAD_SEED, RPC::invalid_field_message ("secret")); Json::Value& tx_json (params ["tx_json"]); if (! tx_json.isObject ()) return RPC::object_field_error ("tx_json"); if (! tx_json.isMember ("TransactionType")) return RPC::missing_field_error ("tx_json.TransactionType"); std::string const sType = tx_json ["TransactionType"].asString (); if (! tx_json.isMember ("Account")) return RPC::make_error (rpcSRC_ACT_MISSING, RPC::missing_field_message ("tx_json.Account")); RippleAddress raSrcAddressID; if (! raSrcAddressID.setAccountID (tx_json["Account"].asString ())) return RPC::make_error (rpcSRC_ACT_MALFORMED, RPC::invalid_field_message ("tx_json.Account")); bool const verify = !(params.isMember ("offline") && params["offline"].asBool ()); if (!tx_json.isMember ("Sequence") && !verify) return RPC::missing_field_error ("tx_json.Sequence"); // Check for current ledger if (verify && !getConfig ().RUN_STANDALONE && (getApp().getLedgerMaster().getValidatedLedgerAge() > 120)) return rpcError (rpcNO_CURRENT); // Check for load if (getApp().getFeeTrack().isLoadedCluster() && (role != Config::ADMIN)) return rpcError(rpcTOO_BUSY); Ledger::pointer lSnapshot = netOps.getCurrentLedger (); AccountState::pointer asSrc; if (verify) { asSrc = netOps.getAccountState (lSnapshot, raSrcAddressID); if (!asSrc) { // If not offline and did not find account, error. WriteLog (lsDEBUG, RPCHandler) << "transactionSign: Failed to find source account in current ledger: " << raSrcAddressID.humanAccountID (); return rpcError (rpcSRC_ACT_NOT_FOUND); } } autofill_fee (params, lSnapshot, jvResult, role == Config::ADMIN); if (RPC::contains_error (jvResult)) return jvResult; if ("Payment" == sType) { auto e = signPayment(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if ("Genesis" == sType) { auto e = signGenesis(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if ("Transfer" == sType) { auto e = signTransfer(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if ("AccountCreate" == sType) { auto e = signAccountCreate(params, tx_json, raSrcAddressID, lSnapshot, role); if (contains_error(e)) return e; } if (!tx_json.isMember ("Fee")) { auto const& transactionType = tx_json["TransactionType"].asString (); if ("AccountSet" == transactionType || "OfferCreate" == transactionType || "OfferCancel" == transactionType || "TrustSet" == transactionType) { tx_json["Fee"] = (int) getConfig ().FEE_DEFAULT; } } if (!tx_json.isMember ("Sequence")) tx_json["Sequence"] = asSrc->getSeq (); if (!tx_json.isMember ("Flags")) tx_json["Flags"] = tfFullyCanonicalSig; if (verify) { SLE::pointer sleAccountRoot = netOps.getSLEi (lSnapshot, Ledger::getAccountRootIndex (raSrcAddressID.getAccountID ())); if (!sleAccountRoot) // XXX Ignore transactions for accounts not created. return rpcError (rpcSRC_ACT_NOT_FOUND); } RippleAddress naSecret = RippleAddress::createSeedGeneric (params["secret"].asString ()); RippleAddress masterAccountPublic = RippleAddress::createAccountPublic(naSecret); if (verify) { auto account = masterAccountPublic.getAccountID(); auto const& sle = asSrc->peekSLE(); WriteLog (lsWARNING, RPCHandler) << "verify: " << masterAccountPublic.humanAccountID () << " : " << raSrcAddressID.humanAccountID (); if (raSrcAddressID.getAccountID () == account) { if (sle.isFlag(lsfDisableMaster) && "Inflation" != sType) return rpcError (rpcMASTER_DISABLED); } else if (!sle.isFieldPresent(sfRegularKey) || account != sle.getFieldAccount160 (sfRegularKey)) { return rpcError (rpcBAD_SECRET); } } STParsedJSON parsed ("tx_json", tx_json); if (!parsed.object.get()) { jvResult ["error"] = parsed.error ["error"]; jvResult ["error_code"] = parsed.error ["error_code"]; jvResult ["error_message"] = parsed.error ["error_message"]; return jvResult; } std::unique_ptr<STObject> sopTrans = std::move(parsed.object); sopTrans->setFieldVL (sfSigningPubKey, masterAccountPublic.getAccountPublic ()); SerializedTransaction::pointer stpTrans; try { stpTrans = boost::make_shared<SerializedTransaction> (*sopTrans); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } std::string reason; if (!passesLocalChecks (*stpTrans, reason)) return RPC::make_error (rpcINVALID_PARAMS, reason); if (params.isMember ("debug_signing")) { jvResult["tx_unsigned"] = strHex ( stpTrans->getSerializer ().peekData ()); jvResult["tx_signing_hash"] = to_string (stpTrans->getSigningHash ()); } // FIXME: For performance, transactions should not be signed in this code path. RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate (naSecret); stpTrans->sign (naAccountPrivate); Transaction::pointer tpTrans; tpTrans = getApp().getMasterTransaction().fetch(stpTrans->getTransactionID(), false); if (tpTrans) { TER res = tpTrans->getResult(); if (!(isTelLocal(res) || isTemMalformed(res) || isTefFailure(res))) { tpTrans = Transaction::pointer(); } } if (!tpTrans) { try { tpTrans = boost::make_shared<Transaction> (stpTrans, false); } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction"); } try { // FIXME: For performance, should use asynch interface tpTrans = netOps.submitTransactionSync (tpTrans, role == Config::ADMIN, true, bFailHard, bSubmit); if (!tpTrans) { return RPC::make_error (rpcINTERNAL, "Unable to sterilize transaction."); } } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during transaction submission."); } } try { jvResult["tx_json"] = tpTrans->getJson (0); jvResult["tx_blob"] = strHex ( tpTrans->getSTransaction ()->getSerializer ().peekData ()); if (temUNCERTAIN != tpTrans->getResult ()) { std::string sToken; std::string sHuman; transResultInfo (tpTrans->getResult (), sToken, sHuman); jvResult["engine_result"] = sToken; jvResult["engine_result_code"] = tpTrans->getResult (); jvResult["engine_result_message"] = sHuman; } return jvResult; } catch (std::exception&) { return RPC::make_error (rpcINTERNAL, "Exception occurred during JSON handling."); } }