diff --git a/src/core_io.h b/src/core_io.h index 63fe1c1f98..e2156e33e9 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -1,4 +1,5 @@ // Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -36,6 +37,7 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); std::string SighashToStr(unsigned char sighash_type); void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void ScriptToUniv(const CScript& script, UniValue& out, bool include_address); -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, const std::vector>& vTxRingCtInputs, UniValue& entry, bool include_hex = true, int serialize_flags = 0); +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0); +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, const std::vector>>& vTxRingCTInputs, bool include_hex = true, int serialize_flags = 0); #endif // BITCOIN_CORE_IO_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 61bd834300..74e432d109 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -189,11 +190,11 @@ void OutputToJSON(uint256 &txid, int i, { CTxOutCT *s = (CTxOutCT*) baseOut; entry.pushKV("type", "blind"); - entry.pushKV("valueCommitment", HexStr(&s->commitment.data[0], &s->commitment.data[0]+33)); + entry.pushKV("ephemeral_pubkey", HexStr(s->vData.begin(), s->vData.end())); UniValue o(UniValue::VOBJ); ScriptPubKeyToUniv(s->scriptPubKey, o, true); entry.pushKV("scriptPubKey", o); - entry.pushKV("data_hex", HexStr(s->vData.begin(), s->vData.end())); + entry.pushKV("valueCommitment", HexStr(&s->commitment.data[0], &s->commitment.data[0]+33)); AddRangeproof(s->vRangeproof, entry); } @@ -202,9 +203,9 @@ void OutputToJSON(uint256 &txid, int i, { CTxOutRingCT *s = (CTxOutRingCT*) baseOut; entry.pushKV("type", "ringct"); + entry.pushKV("ephemeral_pubkey", HexStr(s->vData.begin(), s->vData.end())); entry.pushKV("pubkey", HexStr(s->pk.begin(), s->pk.end())); entry.pushKV("valueCommitment", HexStr(&s->commitment.data[0], &s->commitment.data[0]+33)); - entry.pushKV("data_hex", HexStr(s->vData.begin(), s->vData.end())); AddRangeproof(s->vRangeproof, entry); } @@ -257,7 +258,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, const std::vector>& vTxRingCtInputs, UniValue& entry, bool include_hex, int serialize_flags) +// TODO: Fix duplicate code. This was done as such to prevent veil-tx and some tests from failing to build. +// One requires core lib, the other doesn't. +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) { entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); @@ -275,19 +278,117 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, const std::vecto in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); if (txin.IsAnonInput()) { in.pushKV("type", "anon"); + uint32_t nSigInputs, nSigRingSize; + txin.GetAnonInfo(nSigInputs, nSigRingSize); + in.pushKV("num_inputs", (int) nSigInputs); + in.pushKV("ring_size", (int) nSigRingSize); + in.pushKV("ringct_inputs", "To see the RingCT inputs, you must run the core library!"); + + const std::vector vKeyImages = txin.scriptData.stack[0]; + UniValue arrKeyImage(UniValue::VARR); + for (unsigned int k = 0; k < nSigInputs; k++) { + arrKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); + } + in.pushKV("key_images", arrKeyImage); + } else { + in.pushKV("txid", txin.prevout.hash.GetHex()); + if (txin.IsZerocoinSpend()) { + in.pushKV("type", "zerocoinspend"); + in.pushKV("denomination", FormatMoney(txin.GetZerocoinSpent())); + std::vector > dataTxIn; + dataTxIn.insert(dataTxIn.end(), txin.scriptSig.begin() + 4, txin.scriptSig.end()); + CDataStream serializedCoinSpend(dataTxIn, SER_NETWORK, PROTOCOL_VERSION); + libzerocoin::CoinSpend spend(Params().Zerocoin_Params(), serializedCoinSpend); + in.pushKV("serial", spend.getCoinSerialNumber().GetHex()); + if (spend.getVersion() >= 4) { + in.pushKV("pubcoin", spend.getPubcoinValue().GetHex()); + } + } + in.pushKV("vout", (int64_t)txin.prevout.n); + UniValue o(UniValue::VOBJ); + o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); + o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); + in.pushKV("scriptSig", o); + if (!tx.vin[i].scriptWitness.IsNull()) { + UniValue txinwitness(UniValue::VARR); + for (const auto& item : tx.vin[i].scriptWitness.stack) { + txinwitness.push_back(HexStr(item.begin(), item.end())); + } + in.pushKV("txinwitness", txinwitness); + } + } + in.pushKV("sequence", (int64_t)txin.nSequence); + vin.push_back(in); + } + entry.pushKV("vin", vin); + + UniValue vout(UniValue::VARR); + auto txid = tx.GetHash(); + for (unsigned int i = 0; i < tx.vpout.size(); i++) { + const auto& pout = tx.vpout[i]; + UniValue out(UniValue::VOBJ); + OutputToJSON(txid, i, pout.get(), out, tx.IsCoinBase()); + vout.push_back(out); + } + + entry.pushKV("vout", vout); + + if (!hashBlock.IsNull()) + entry.pushKV("blockhash", hashBlock.GetHex()); + + if (include_hex) { + entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction". + } +} + +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, const std::vector>>& vTxRingCTInputs, bool include_hex, int serialize_flags) { + entry.pushKV("txid", tx.GetHash().GetHex()); + entry.pushKV("hash", tx.GetWitnessHash().GetHex()); + entry.pushKV("version", tx.nVersion); + entry.pushKV("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)); + entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); + entry.pushKV("weight", GetTransactionWeight(tx)); + entry.pushKV("locktime", (int64_t)tx.nLockTime); + + // For tracking position in RingCT transactions. Its possible to have more than 1 RingCT inputs in a tx. + unsigned int j = 0; + unsigned int k = 0; + UniValue vin(UniValue::VARR); + for (unsigned int i = 0; i < tx.vin.size(); i++) { + const CTxIn& txin = tx.vin[i]; + UniValue in(UniValue::VOBJ); + if (tx.IsCoinBase()) + in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); + if (txin.IsAnonInput()) { + in.pushKV("type", "ringct"); // FIXME: Should match the type from enum? + uint32_t nSigInputs, nSigRingSize; txin.GetAnonInfo(nSigInputs, nSigRingSize); in.pushKV("num_inputs", (int) nSigInputs); in.pushKV("ring_size", (int) nSigRingSize); - //Add ring ct inputs - if (vTxRingCtInputs.size() > i) { - std::vector vRingCtInputs = vTxRingCtInputs[i]; + const std::vector vCommitments = txin.scriptWitness.stack[1]; + in.pushKV("commitment_sig", HexStr(&vCommitments[j], &vCommitments[j + 32])); + + if (vTxRingCTInputs.size() > i) { UniValue arrRing(UniValue::VARR); - for (const COutPoint& outpoint : vRingCtInputs) { + const std::vector vKeyImages = txin.scriptData.stack[0]; + for (k; k < nSigInputs; k++) { UniValue obj(UniValue::VOBJ); - obj.pushKV("txid", outpoint.hash.GetHex()); - obj.pushKV("vout.n", (uint64_t) outpoint.n); + obj.pushKV("key_image", HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); + + std::vector> vRingCtInputs = vTxRingCTInputs[i]; + obj.pushKV("txid", vRingCtInputs[k].second.hash.GetHex()); + obj.pushKV("vout.n", (uint64_t) vRingCtInputs[k].second.n); + obj.pushKV("index", vRingCtInputs[k].first); + + UniValue arrCommitment(UniValue::VARR); + for (unsigned int m = 0; m < (nSigRingSize); m++) { + j += 1; + arrCommitment.push_back(HexStr(&vCommitments[j*32], &vCommitments[(j*32)+32])); + } + obj.pushKV("commitments", arrCommitment); + arrRing.push_back(obj); } in.pushKV("ringct_inputs", arrRing); diff --git a/src/rest.cpp b/src/rest.cpp index a71252ffb9..fa3ce16273 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -380,7 +381,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) case RetFormat::JSON: { UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, hashBlock, {{}}, objTx); + TxToUniv(*tx, hashBlock, objTx); std::string strJSON = objTx.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index cd4d36529c..9c71c6acd6 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -144,9 +144,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if(txDetails) { UniValue objTx(UniValue::VOBJ); - std::vector > vInputs; - GetRingCtInputs(tx->vin[0], vInputs); - TxToUniv(*tx, uint256(), vInputs, objTx, true, RPCSerializationFlags()); + std::vector>> vTxRingCTInputs; + GetRingCtInputs(tx->vin[0], vTxRingCTInputs); + TxToUniv(*tx, uint256(), objTx, vTxRingCTInputs, true, RPCSerializationFlags()); txs.push_back(objTx); } else diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1175ac0822..7386ad232a 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,14 +41,15 @@ #include -static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, const std::vector>& vTxRingCtInputs) +static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) { // Call into TxToUniv() in bitcoin-common to decode the transaction hex. // // Blockchain contextual information (confirmations and blocktime) is not // available to code in bitcoin-common, so we query them here and push the // data into the returned UniValue. - TxToUniv(tx, uint256(), vTxRingCtInputs, entry, true, RPCSerializationFlags()); + const std::vector>> &vTxRingCtInputs = GetTxRingCtInputs(tx); + TxToUniv(tx, uint256(), entry, vTxRingCtInputs, true, RPCSerializationFlags()); if (!hashBlock.IsNull()) { LOCK(cs_main); @@ -201,10 +203,9 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) } //Get ringct inputs - std::vector > vTxRingCtInputs = GetTxRingCtInputs(tx); UniValue result(UniValue::VOBJ); if (blockindex) result.pushKV("in_active_chain", in_active_chain); - TxToJSON(*tx, hash_block, result, vTxRingCtInputs); + TxToJSON(*tx, hash_block, result); return result; } @@ -581,7 +582,9 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) } UniValue result(UniValue::VOBJ); - TxToUniv(CTransaction(std::move(mtx)), uint256(), {{}}, result, false); + CTransaction tx = std::move(mtx); + std::vector>> vTxRingCtInputs = GetTxRingCtInputs(tx); + TxToUniv(tx, uint256(), result, vTxRingCtInputs, false); return result; } @@ -1425,7 +1428,7 @@ UniValue decodepsbt(const JSONRPCRequest& request) // Add the decoded tx UniValue tx_univ(UniValue::VOBJ); - TxToUniv(CTransaction(*psbtx.tx), uint256(), {{}}, tx_univ, false); + TxToUniv(CTransaction(*psbtx.tx), uint256(), tx_univ, false); result.pushKV("tx", tx_univ); // Unknown data @@ -1457,7 +1460,7 @@ UniValue decodepsbt(const JSONRPCRequest& request) in.pushKV("witness_utxo", out); } else if (input.non_witness_utxo) { UniValue non_wit(UniValue::VOBJ); - TxToUniv(*input.non_witness_utxo, uint256(), {{}}, non_wit, false); + TxToUniv(*input.non_witness_utxo, uint256(), non_wit, false); in.pushKV("non_witness_utxo", non_wit); total_in += input.non_witness_utxo->vpout[psbtx.tx->vin[i].prevout.n]->GetValue(); } else { diff --git a/src/veil-tx.cpp b/src/veil-tx.cpp index b3f1d6a50c..8804f60f2b 100644 --- a/src/veil-tx.cpp +++ b/src/veil-tx.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -719,7 +720,7 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command, static void OutputTxJSON(const CTransaction& tx) { UniValue entry(UniValue::VOBJ); - TxToUniv(tx, uint256(), {{}}, entry); + TxToUniv(tx, uint256(), entry); std::string jsonOutput = entry.write(4); fprintf(stdout, "%s\n", jsonOutput.c_str()); diff --git a/src/veil/ringct/anon.cpp b/src/veil/ringct/anon.cpp index 3587bc19e1..a771ca84de 100644 --- a/src/veil/ringct/anon.cpp +++ b/src/veil/ringct/anon.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2017-2019 The Particl developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. @@ -296,21 +297,24 @@ bool RollBackRCTIndex(int64_t nLastValidRCTOutput, int64_t nExpectErase, std::se return true; } -std::vector> GetTxRingCtInputs(const CTransactionRef ptx) +// Gets the RingCT inputs from the transaction. +std::vector>> GetTxRingCtInputs(const CTransaction& tx) { - std::vector > vTxRingCtInputs; - for (const CTxIn& txin : ptx->vin) { + std::vector>> vTxRingCtInputs; + // In the tx vin vector, if the transaction is an anon input, it gets the RingCT vOutPoint vector. + for (const CTxIn& txin : tx.vin) { if (txin.IsAnonInput()) { - std::vector vInputs = GetRingCtInputs(txin); - vTxRingCtInputs.emplace_back(vInputs); + std::vector> mapInputs = GetRingCtInputs(txin); + vTxRingCtInputs.push_back(mapInputs); } } + // Returns a vector of the vector of RingCT Outpoints. return vTxRingCtInputs; } -std::vector GetRingCtInputs(const CTxIn& txin) +std::vector> GetRingCtInputs(const CTxIn& txin) { - std::vector vInputs; + std::vector> vRingCTInputs; uint32_t nInputs, nRingSize; txin.GetAnonInfo(nInputs, nRingSize); @@ -318,19 +322,16 @@ std::vector GetRingCtInputs(const CTxIn& txin) size_t nRows = nInputs + 1; if (txin.scriptData.stack.size() != 1) - return vInputs; + return vRingCTInputs; if (txin.scriptWitness.stack.size() != 2) - return vInputs; + return vRingCTInputs; const std::vector vKeyImages = txin.scriptData.stack[0]; const std::vector vMI = txin.scriptWitness.stack[0]; - const std::vector vDL = txin.scriptWitness.stack[1]; if (vKeyImages.size() != nInputs * 33) - return vInputs; - std::vector vM(nCols * nRows * 33); - std::set setKeyCandidates; + return vRingCTInputs; size_t ofs = 0, nB = 0; for (size_t k = 0; k < nInputs; ++k) { @@ -345,15 +346,57 @@ std::vector GetRingCtInputs(const CTxIn& txin) if (!pblocktree->ReadRCTOutput(nIndex, ao)) { continue; } - vInputs.emplace_back(ao.outpoint); + vRingCTInputs.emplace_back(std::make_pair(nIndex, ao.outpoint)); } } - return vInputs; + return vRingCTInputs; } -bool GetRingCtInputs(const CTxIn& txin, std::vector >& vInputs) +bool GetRingCtInputs(const CTxIn& txin, std::vector>>& vTxRingCTInputs) { - vInputs.clear(); + vTxRingCTInputs.clear(); + uint32_t nInputs, nRingSize; + txin.GetAnonInfo(nInputs, nRingSize); + + size_t nCols = nRingSize; + size_t nRows = nInputs + 1; + + if (txin.scriptData.stack.size() != 1) + return false; + + if (txin.scriptWitness.stack.size() != 2) + return false; + + const std::vector vKeyImages = txin.scriptData.stack[0]; + const std::vector vMI = txin.scriptWitness.stack[0]; + + if (vKeyImages.size() != nInputs * 33) + return false; + + size_t ofs = 0, nB = 0; + for (size_t k = 0; k < nInputs; ++k) { + std::vector> vRingCTInputs; + for (size_t i = 0; i < nCols; ++i) { + int64_t nIndex; + + if (0 != GetVarInt(vMI, ofs, (uint64_t&) nIndex, nB)) + return false; + ofs += nB; + + CAnonOutput ao; + if (!pblocktree->ReadRCTOutput(nIndex, ao)) { + return false; + } + vRingCTInputs.emplace_back(std::make_pair(nIndex, ao.outpoint)); + } + vTxRingCTInputs.emplace_back(vRingCTInputs); + } + return true; +} + +bool GetRingCtInputs(const CTxIn& txin, std::vector>& vTxRingCTInputs) +{ + vTxRingCTInputs.clear(); uint32_t nInputs, nRingSize; txin.GetAnonInfo(nInputs, nRingSize); @@ -368,12 +411,9 @@ bool GetRingCtInputs(const CTxIn& txin, std::vector >& vI const std::vector vKeyImages = txin.scriptData.stack[0]; const std::vector vMI = txin.scriptWitness.stack[0]; - const std::vector vDL = txin.scriptWitness.stack[1]; if (vKeyImages.size() != nInputs * 33) return false; - std::vector vM(nCols * nRows * 33); - std::set setKeyCandidates; size_t ofs = 0, nB = 0; for (size_t k = 0; k < nInputs; ++k) { @@ -391,7 +431,7 @@ bool GetRingCtInputs(const CTxIn& txin, std::vector >& vI } vOutpoints.emplace_back(ao.outpoint); } - vInputs.emplace_back(vOutpoints); + vTxRingCTInputs.emplace_back(vOutpoints); } return true; } diff --git a/src/veil/ringct/anon.h b/src/veil/ringct/anon.h index e45d783f6c..3d6581f42b 100644 --- a/src/veil/ringct/anon.h +++ b/src/veil/ringct/anon.h @@ -1,4 +1,5 @@ // Copyright (c) 2017-2019 The Particl developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef VEIL_ANON_H @@ -29,9 +30,9 @@ bool RollBackRCTIndex(int64_t nLastValidRCTOutput, int64_t nExpectErase, std::se bool RewindToCheckpoint(int nCheckPointHeight, int &nBlocks, std::string &sError); -std::vector GetRingCtInputs(const CTxIn& txin); -bool GetRingCtInputs(const CTxIn& txin, std::vector >& vInputs); -std::vector> GetTxRingCtInputs(const CTransactionRef ptx); - +std::vector> GetRingCtInputs(const CTxIn& txin); +std::vector>> GetTxRingCtInputs(const CTransaction& tx); +bool GetRingCtInputs(const CTxIn& txin, std::vector>>& vTxRingCTInputs); +bool GetRingCtInputs(const CTxIn& txin, std::vector>& vTxRingCTInputs); #endif //VEIL_ANON_H diff --git a/src/veil/ringct/rpcanonwallet.cpp b/src/veil/ringct/rpcanonwallet.cpp index 4a3a66390b..600e6ca2fe 100644 --- a/src/veil/ringct/rpcanonwallet.cpp +++ b/src/veil/ringct/rpcanonwallet.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2017-2019 The Particl Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1902,7 +1903,7 @@ static UniValue verifyrawtransaction(const JSONRPCRequest &request) if (!request.params[2].isNull() && request.params[2].get_bool()) { UniValue txn(UniValue::VOBJ); - TxToUniv(CTransaction(std::move(mtx)), uint256(), {{}}, txn, false); + TxToUniv(CTransaction(std::move(mtx)), uint256(), txn, false); result.pushKV("txn", txn); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 563969aaeb..476216fffc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2019 The Veil developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -2494,7 +2495,7 @@ static UniValue gettransaction(const JSONRPCRequest& request) nDebitAnon = pwalletAnon->GetDebit(*tx.tx, ISMINE_SPENDABLE); } } - + const CWalletTx& wtx = it->second; assert(wtx.tx); CAmount nCreditBase = wtx.GetCredit(filter); @@ -2522,128 +2523,6 @@ static UniValue gettransaction(const JSONRPCRequest& request) ListTransactions(pwallet, wtx, "*", 0, false, details, filter); entry.pushKV("details", details); - UniValue obj_debug(UniValue::VOBJ); - UniValue arr_vin(UniValue::VARR); - for (auto txin : wtx.tx->vin) { - UniValue obj_vin(UniValue::VOBJ); - bool fIsMyInput = pwallet->IsMine(txin, true, true); - - obj_vin.pushKV("from_me", fIsMyInput); - if (txin.IsAnonInput()) { - obj_vin.pushKV("type", "ringct"); - COutPoint myOutpoint; - bool isMyInput = pwalletAnon->IsMyAnonInput(txin, myOutpoint); - obj_vin.pushKV("is_mine_ki", isMyInput); - if (isMyInput) { - UniValue obj(UniValue::VOBJ); - obj.pushKV("txid", myOutpoint.hash.GetHex()); - obj.pushKV("vout.n", (uint64_t)myOutpoint.n); - obj_vin.pushKV("outpoint_spent", obj); - } - std::vector vInputs = GetRingCtInputs(txin); - UniValue arrRing(UniValue::VARR); - for (auto outpoint : vInputs) { - UniValue obj(UniValue::VOBJ); - obj.pushKV("txid", outpoint.hash.GetHex()); - obj.pushKV("vout.n", (uint64_t)outpoint.n); - arrRing.push_back(obj); - } - obj_vin.pushKV("ringct_inputs", arrRing); - } else if (txin.IsZerocoinSpend()) { - obj_vin.pushKV("type", "zerocoinspend"); - auto spend = TxInToZerocoinSpend(txin); - if (spend) { - auto bnSerial = spend->getCoinSerialNumber(); - obj_vin.pushKV("serial", bnSerial.GetHex()); - obj_vin.pushKV("serial_hash", GetSerialHash(bnSerial).GetHex()); - obj_vin.pushKV("denom", (int64_t)spend->getDenomination()); - obj_vin.pushKV("version", (int64_t)spend->getVersion()); - if (spend->getVersion() == 4) { - obj_vin.pushKV("pubcoin", spend->getPubcoinValue().GetHex()); - } - } - } else { - //Have to specifically look up type to determine whether it is CT or Basecoin - uint256 hashBlock; - CTransactionRef txPrev; - if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), hashBlock)) { - obj_vin.pushKV("type", "failed"); - continue; - } - - obj_vin.pushKV("prevout_hash", txin.prevout.hash.GetHex()); - obj_vin.pushKV("prevout_n", (double)txin.prevout.n); - auto nType = txPrev->vpout[txin.prevout.n]->GetType(); - if (nType == OUTPUT_STANDARD) - obj_vin.pushKV("type", "basecoin"); - else { - obj_vin.pushKV("type", "ct"); - if (fIsMyInput) { - auto mi = pwalletAnon->mapRecords.find(txin.prevout.hash); - obj_vin.pushKV("has_tx_rec", bool(mi != pwalletAnon->mapRecords.end())); - if (mi != pwalletAnon->mapRecords.end()) { - const COutputRecord *oR = mi->second.GetOutput(txin.prevout.n); - if (oR) - obj_vin.pushKV("output_record", OutputRecordToUniValue(pwalletAnon, oR)); - } - } - } - } - arr_vin.push_back(obj_vin); - } - obj_debug.pushKV("vin", arr_vin); - - UniValue arr_vout(UniValue::VARR); - for (unsigned int i = 0; i < wtx.tx->vpout.size(); i++) { - UniValue obj_out(UniValue::VOBJ); - auto pout = wtx.tx->vpout[i]; - bool fIsMyOutput = pwallet->IsMine(pout.get()); - if (pout->GetType() == OUTPUT_STANDARD) { - if (pout->IsZerocoinMint()) { - obj_out.pushKV("type", "zerocoinmint"); - obj_out.pushKV("metadata", ZerocoinMintToUniValue(pwallet, pout)); - } else { - obj_out.pushKV("type", "basecoin"); - - CTxDestination dest; - if (ExtractDestination(*pout->GetPScriptPubKey(), dest)) { - obj_out.pushKV("sent_to", EncodeDestination(dest, true)); - } - } - obj_out.pushKV("amount", FormatMoney(pout->GetValue())); - } else if (pout->GetType() == OUTPUT_CT) { - obj_out.pushKV("type", "ct"); - } else if (pout->GetType() == OUTPUT_RINGCT) { - obj_out.pushKV("type", "ringct"); - CTxOutRingCT* outRingCT = (CTxOutRingCT*)pout.get(); - - std::vector vchEphemPK; - vchEphemPK.resize(33); - memcpy(&vchEphemPK[0], &outRingCT->vData[0], 33); - obj_out.pushKV("ephemeral_pubkey", HexStr(vchEphemPK)); - } else if (pout->GetType() == OUTPUT_DATA) { - obj_out.pushKV("type", "data"); - CTxOutData* outData = (CTxOutData*)pout.get(); - CAmount nFeeData; - if (outData->GetCTFee(nFeeData)) { - obj_out.pushKV("ct_fee", FormatMoney(nFeeData)); - } - obj_out.pushKV("data", HexStr(outData->vData)); - } - - obj_out.pushKV("is_mine", fIsMyOutput); - auto mi = pwalletAnon->mapRecords.find(hash); - obj_out.pushKV("has_tx_rec", bool(mi != pwalletAnon->mapRecords.end())); - if (mi != pwalletAnon->mapRecords.end()) { - const COutputRecord *oR = mi->second.GetOutput(i); - if (oR) - obj_out.pushKV("output_record", OutputRecordToUniValue(pwalletAnon, oR)); - } - arr_vout.push_back(obj_out); - } - obj_debug.pushKV("vout", arr_vout); - - entry.pushKV("debug", obj_debug); std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); entry.pushKV("hex", strHex);