From 67d038bcf2a329ea1304aede5997a5bc3d2c8062 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 1 Mar 2013 20:45:19 +0400 Subject: [PATCH] Merge non-wallet transactions support for gettransaction RPC from bitcoin 0.7 --- src/bitcoinrpc.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 40 ++++++---- src/main.h | 2 +- 3 files changed, 262 insertions(+), 16 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index a973d37..4239f3f 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -127,6 +127,40 @@ unsigned int BitsHex(std::string HexBits) return uBits.nBits; } +void TxToJSON(const CTransaction &tx, Object& entry) +{ + entry.push_back(Pair("version", tx.nVersion)); + entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); + entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); + Array vin; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + Object in; + if (tx.IsCoinBase()) + in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + else + { + Object prevout; + prevout.push_back(Pair("hash", txin.prevout.hash.GetHex())); + prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n)); + in.push_back(Pair("prevout", prevout)); + in.push_back(Pair("scriptSig", txin.scriptSig.ToString())); + } + in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); + vin.push_back(in); + } + entry.push_back(Pair("vin", vin)); + Array vout; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + Object out; + out.push_back(Pair("value", ValueFromAmount(txout.nValue))); + out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString())); + vout.push_back(out); + } + entry.push_back(Pair("vout", vout)); +} + void WalletTxToJSON(const CWalletTx& wtx, Object& entry) { int confirms = wtx.GetDepthInMainChain(); @@ -1534,6 +1568,7 @@ Value listsinceblock(const Array& params, bool fHelp) return ret; } +/* Value gettransaction(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -1567,6 +1602,75 @@ Value gettransaction(const Array& params, bool fHelp) return entry; } +*/ + + +Value gettransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "gettransaction \n" + "Get detailed information about "); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + Object entry; + + if (pwalletMain->mapWallet.count(hash)) + { + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + + TxToJSON(wtx, entry); + + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); + + entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); + if (wtx.IsFromMe()) + entry.push_back(Pair("fee", ValueFromAmount(nFee))); + + WalletTxToJSON(wtx, entry); + + Array details; + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); + entry.push_back(Pair("details", details)); + } + else + { + CTransaction tx; + uint256 hashBlock = 0; + if (GetTransaction(hash, tx, hashBlock)) + { + entry.push_back(Pair("txid", hash.GetHex())); + TxToJSON(tx, entry); + if (hashBlock == 0) + entry.push_back(Pair("confirmations", 0)); + else + { + entry.push_back(Pair("blockhash", hashBlock.GetHex())); + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + { + entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); + entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); + } + else + entry.push_back(Pair("confirmations", 0)); + } + } + } + else + throw JSONRPCError(-5, "No information available about transaction"); + } + + return entry; +} Value backupwallet(const Array& params, bool fHelp) @@ -1884,6 +1988,137 @@ Value validatepubkey(const Array& params, bool fHelp) return ret; } +Value getworkex(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getworkex [data, coinbase]\n" + "If [data, coinbase] is not specified, returns extended work data.\n" + ); + + if (vNodes.empty()) + throw JSONRPCError(-9, "NovaCoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "NovaCoin is downloading blocks..."); + + typedef map > mapNewBlock_t; + static mapNewBlock_t mapNewBlock; + static vector vNewBlock; + static CReserveKey reservekey(pwalletMain); + + if (params.size() == 0) + { + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) + { + if (pindexPrev != pindexBest) + { + // Deallocate old blocks since they're obsolete now + mapNewBlock.clear(); + BOOST_FOREACH(CBlock* pblock, vNewBlock) + delete pblock; + vNewBlock.clear(); + } + nTransactionsUpdatedLast = nTransactionsUpdated; + pindexPrev = pindexBest; + nStart = GetTime(); + + // Create new block + pblock = CreateNewBlock(pwalletMain); + if (!pblock) + throw JSONRPCError(-7, "Out of memory"); + vNewBlock.push_back(pblock); + } + + // Update nTime + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nNonce = 0; + + // Update nExtraNonce + static unsigned int nExtraNonce = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + // Save + mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); + + // Prebuild hash buffers + char pmidstate[32]; + char pdata[128]; + char phash1[64]; + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + CTransaction coinbaseTx = pblock->vtx[0]; + std::vector merkle = pblock->GetMerkleBranch(0); + + Object result; + result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); + result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << coinbaseTx; + result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end()))); + + Array merkle_arr; + printf("DEBUG: merkle size %i\n", merkle.size()); + + BOOST_FOREACH(uint256 merkleh, merkle) { + printf("%s\n", merkleh.ToString().c_str()); + merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh))); + } + + result.push_back(Pair("merkle", merkle_arr)); + + + return result; + } + else + { + // Parse parameters + vector vchData = ParseHex(params[0].get_str()); + vector coinbase; + + if(params.size() == 2) + coinbase = ParseHex(params[1].get_str()); + + if (vchData.size() != 128) + throw JSONRPCError(-8, "Invalid parameter"); + + CBlock* pdata = (CBlock*)&vchData[0]; + + // Byte reverse + for (int i = 0; i < 128/4; i++) + ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); + + // Get saved block + if (!mapNewBlock.count(pdata->hashMerkleRoot)) + return false; + CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; + + pblock->nTime = pdata->nTime; + pblock->nNonce = pdata->nNonce; + + if(coinbase.size() == 0) + pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; + else + CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK! + + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + if (!pblock->SignBlock(*pwalletMain)) + throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); + + return CheckWork(pblock, *pwalletMain, reservekey); + } +} + Value getwork(const Array& params, bool fHelp) { @@ -2633,6 +2868,7 @@ static const CRPCCommand vRPCCommands[] = { "signmessage", &signmessage, false }, { "verifymessage", &verifymessage, false }, { "getwork", &getwork, true }, + { "getworkex", &getworkex, true }, { "listaccounts", &listaccounts, false }, { "settxfee", &settxfee, false }, { "getmemorypool", &getmemorypool, true }, diff --git a/src/main.cpp b/src/main.cpp index c27b8c2..d92f528 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -679,11 +679,6 @@ bool CTxMemPool::remove(CTransaction &tx) return true; } - - - - - int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const { if (hashBlock == 0 || nIndex == -1) @@ -738,8 +733,6 @@ bool CMerkleTx::AcceptToMemoryPool() return AcceptToMemoryPool(txdb); } - - bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) { @@ -782,14 +775,31 @@ int CTxIndex::GetDepthInMainChain() const return 1 + nBestHeight - pindex->nHeight; } - - - - - - - - +// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock +bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) +{ + { + LOCK(cs_main); + { + LOCK(mempool.cs); + if (mempool.exists(hash)) + { + tx = mempool.lookup(hash); + return true; + } + } + CTxDB txdb("r"); + CTxIndex txindex; + if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) + { + CBlock block; + if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + hashBlock = block.GetHash(); + return true; + } + } + return false; +} ////////////////////////////////////////////////////////////////////////////// // diff --git a/src/main.h b/src/main.h index 781f54a..7e05562 100644 --- a/src/main.h +++ b/src/main.h @@ -121,6 +121,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); +bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); uint256 WantedByOrphan(const CBlock* pblockOrphan); const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); void BitcoinMiner(CWallet *pwallet, bool fProofOfStake); @@ -857,7 +858,6 @@ public: return !(a == b); } int GetDepthInMainChain() const; - }; -- 1.7.1