diff -uNr a/bitcoin/manifest b/bitcoin/manifest --- a/bitcoin/manifest 1b686bcb52a6a5df9ee7db45315e32fd9b90ebff8783cde2aec664538b6722a972be2c060c4dc97eb5138f454413a2df670ed361b120bfa43acba686aeb9a54f +++ b/bitcoin/manifest 86bafa3b85db8247906f07182e4e15e72114d6f53df442290891298ed5f1487c8fea8991999a44228ceb6b1db88c345bbad7239881cb6ed1f5ffb0293cc7fe42 @@ -32,3 +32,4 @@ 616451 mod6_phexdigit_fix mod6 Adds missing comma to separate values in the phexdigit array in util.cpp. 617254 mod6_excise_hash_truncation mod6 Regrind of ben_vulpes original; Removes truncation of hashes printed to TRB log file 617255 mod6_whogaveblox mod6 Regrind of asciilifeform original; Record the origin of every incoming candidate block (whether accepted or rejected) +625543 bitcoin_rawtx_get_send jfw Add hex raw transaction RPC commands: 'getrawtransaction' fetches from mempool or database; 'sendrawtransaction' injects to mempool or wallet and broadcasts (based loosely on earlier sendrawtransaction patch by polarbeard). Minor simplifications based on new higher-level mempool accessors. diff -uNr a/bitcoin/src/bitcoinrpc.cpp b/bitcoin/src/bitcoinrpc.cpp --- a/bitcoin/src/bitcoinrpc.cpp aa281513748dd76b77893f0813d9425dfc7163cb1eca4af74d707fd5371b2ec7e7652c2c7a45a0069ac5c877554ca0ac7ec0504b93f5d7c859b29deed20146c7 +++ b/bitcoin/src/bitcoinrpc.cpp 5ff9020cf351544e56c82f4ed5962c8236709dae22ce128199c04be28c179d936acdfa54dde7d31d94a7200ede9cece109a170d52960d218a4277ead71707aec @@ -1895,6 +1895,62 @@ return CBitcoinSecret(vchSecret).ToString(); } +Value getrawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getrawtransaction \n" + "Get hex serialization of from memory pool or database."); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + CTransaction tx; + if (!GetMempoolTx(hash, tx) && !CTxDB("r").ReadDiskTx(hash, tx)) + throw JSONRPCError(-5, "Transaction not found in memory pool or database."); + + CDataStream ssTx; + ssTx << tx; + return HexStr(ssTx.begin(), ssTx.end()); +} + +Value sendrawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "sendrawtransaction \n" + "Submits raw transaction (serialized, hex-encoded) to local node and network."); + + CDataStream ssData(ParseHex(params[0].get_str())); + CTransaction tx; + try + { + ssData >> tx; + } + catch (std::exception &e) + { + throw JSONRPCError(-22, "tx decode failed"); + } + + uint256 hash = tx.GetHash(); + if (!MempoolContainsTx(hash)) + { + if (!tx.AcceptToMemoryPool(true)) + { + if (CTxDB("r").ContainsTx(hash)) + throw JSONRPCError(-27, "tx already included in block"); + throw JSONRPCError(-25, "tx rejected, see log for details"); + } + + SyncWithWallets(tx, NULL, true); + } + + CInv inv(MSG_TX, hash); + RelayMessage(inv, tx); + + return hash.GetHex(); +} + // // Call Table @@ -1946,6 +2002,8 @@ make_pair("eatblock", &eatblock), make_pair("importprivkey", &importprivkey), make_pair("dumpprivkey", &dumpprivkey), + make_pair("getrawtransaction", &getrawtransaction), + make_pair("sendrawtransaction", &sendrawtransaction), }; map mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); diff -uNr a/bitcoin/src/main.cpp b/bitcoin/src/main.cpp --- a/bitcoin/src/main.cpp 1f0735d2cee2f9ca2a177aead4ecc7a1371d59c4375aedb172ee99c28b02fa28e664decec9580a510bfca4738d85e377fb74396fe4979b75adbe1a3ec92b01c9 +++ b/bitcoin/src/main.cpp 64bc481577ff4e2b8fe4a0623332e4b60d1d7e208f29fc5036adca3965fe5766b4ea64f47d5442b8bfd990fe86bd37b4fab949439a402a771400fc346ac7ba7f @@ -58,6 +58,24 @@ int fMinimizeOnClose = true; +bool GetMempoolTx(const uint256 &hash, CTransaction &tx) +{ + CRITICAL_BLOCK(cs_mapTransactions) + { + map::iterator it = mapTransactions.find(hash); + if (it == mapTransactions.end()) + return false; + tx = it->second; + } + return true; +} + +bool MempoolContainsTx(const uint256 &hash) +{ + CRITICAL_BLOCK(cs_mapTransactions) + return mapTransactions.count(hash) != 0; +} + ////////////////////////////////////////////////////////////////////////////// // // dispatching functions @@ -108,7 +126,7 @@ } // make sure all wallets know about the given transaction, in the given block -void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false) +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); @@ -321,9 +339,8 @@ // Do we already have it? uint256 hash = GetHash(); - CRITICAL_BLOCK(cs_mapTransactions) - if (mapTransactions.count(hash)) - return false; + if (MempoolContainsTx(hash)) + return false; if (fCheckInputs) if (txdb.ContainsTx(hash)) return false; @@ -803,12 +820,8 @@ if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) { // Get prev tx from single transactions in memory - CRITICAL_BLOCK(cs_mapTransactions) - { - if (!mapTransactions.count(prevout.hash)) - return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().c_str(), prevout.hash.ToString().c_str()); - txPrev = mapTransactions[prevout.hash]; - } + if (!GetMempoolTx(prevout.hash, txPrev)) + return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().c_str(), prevout.hash.ToString().c_str()); if (!fFound) txindex.vSpent.resize(txPrev.vout.size()); } diff -uNr a/bitcoin/src/main.h b/bitcoin/src/main.h --- a/bitcoin/src/main.h 00bae14f70f53e0826f7f23453a48e59ca34fde46de507482224965ad465acab0c913141e1ea21323c4f5461035b8b4d3ac9b11aa9c16fdea000640145b89fd1 +++ b/bitcoin/src/main.h 6788cbec57850c7ba97f945ea48fbf77e9de12361a067f5a5bcf0149bbdba3e9f9c3e9e676c617ac5f23836cac8249035ae02ade091d0da3b212f98dd5eb7db8 @@ -77,8 +77,11 @@ class CTxDB; class CTxIndex; +bool GetMempoolTx(const uint256 &hash, CTransaction &tx); +bool MempoolContainsTx(const uint256 &hash); void RegisterWallet(CWallet* pwalletIn); void UnregisterWallet(CWallet* pwalletIn); +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); bool ProcessBlock(CNode* pfrom, CBlock* pblock); bool CheckDiskSpace(uint64 nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");