From 0eac106b85d78d6da3599a9001e584118558d025 Mon Sep 17 00:00:00 2001 From: codeofalltrades Date: Sat, 16 Nov 2019 00:22:20 -0600 Subject: [PATCH 1/9] Add key_image value(s) to gettransaction rpc output --- src/wallet/rpcwallet.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 563969aaeb..c562148925 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2531,7 +2531,10 @@ static UniValue gettransaction(const JSONRPCRequest& request) obj_vin.pushKV("from_me", fIsMyInput); if (txin.IsAnonInput()) { obj_vin.pushKV("type", "ringct"); + COutPoint myOutpoint; + uint32_t nSigInputs, nSigRingSize; + txin.GetAnonInfo(nSigInputs, nSigRingSize); bool isMyInput = pwalletAnon->IsMyAnonInput(txin, myOutpoint); obj_vin.pushKV("is_mine_ki", isMyInput); if (isMyInput) { @@ -2549,6 +2552,19 @@ static UniValue gettransaction(const JSONRPCRequest& request) arrRing.push_back(obj); } obj_vin.pushKV("ringct_inputs", arrRing); + + const std::vector vKeyImages = txin.scriptData.stack[0]; + uint32_t nInputs, nRingSize; + txin.GetAnonInfo(nInputs, nRingSize); + + UniValue arrKeyImages(UniValue::VARR); + for (unsigned int k = 0; k < nSigInputs; k++) { + const CCmpPubKey &ki = *((CCmpPubKey*)&vKeyImages[k*nSigInputs]); + UniValue objKeyImage(UniValue::VOBJ); + objKeyImage.pushKV(std::to_string(k), HexStr(ki.begin(), ki.end())); + arrKeyImages.push_back(objKeyImage); + } + obj_vin.pushKV("key_images", arrKeyImages); } else if (txin.IsZerocoinSpend()) { obj_vin.pushKV("type", "zerocoinspend"); auto spend = TxInToZerocoinSpend(txin); @@ -2621,6 +2637,11 @@ static UniValue gettransaction(const JSONRPCRequest& request) vchEphemPK.resize(33); memcpy(&vchEphemPK[0], &outRingCT->vData[0], 33); obj_out.pushKV("ephemeral_pubkey", HexStr(vchEphemPK)); + + std::vector objKeyImage; + objKeyImage.resize(33); + memcpy(&objKeyImage[0], &outRingCT->pk[0], 33); + obj_out.pushKV("key_image", HexStr(objKeyImage)); } else if (pout->GetType() == OUTPUT_DATA) { obj_out.pushKV("type", "data"); CTxOutData* outData = (CTxOutData*)pout.get(); From 88a6f408d2a2620b35b7d864b5da0179ee704ae1 Mon Sep 17 00:00:00 2001 From: Mimir Date: Tue, 19 Nov 2019 21:05:15 +0700 Subject: [PATCH 2/9] Remove unneeded debug information from `gettransaction` This debug information was only temporarily added to check out some stuff. --- src/wallet/rpcwallet.cpp | 145 +-------------------------------------- 1 file changed, 1 insertion(+), 144 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c562148925..c826153f43 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2494,7 +2494,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,149 +2522,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; - uint32_t nSigInputs, nSigRingSize; - txin.GetAnonInfo(nSigInputs, nSigRingSize); - 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); - - const std::vector vKeyImages = txin.scriptData.stack[0]; - uint32_t nInputs, nRingSize; - txin.GetAnonInfo(nInputs, nRingSize); - - UniValue arrKeyImages(UniValue::VARR); - for (unsigned int k = 0; k < nSigInputs; k++) { - const CCmpPubKey &ki = *((CCmpPubKey*)&vKeyImages[k*nSigInputs]); - UniValue objKeyImage(UniValue::VOBJ); - objKeyImage.pushKV(std::to_string(k), HexStr(ki.begin(), ki.end())); - arrKeyImages.push_back(objKeyImage); - } - obj_vin.pushKV("key_images", arrKeyImages); - } 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)); - - std::vector objKeyImage; - objKeyImage.resize(33); - memcpy(&objKeyImage[0], &outRingCT->pk[0], 33); - obj_out.pushKV("key_image", HexStr(objKeyImage)); - } 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); From d8bfadc1e00bbc3aef22853f91651ce34f63311e Mon Sep 17 00:00:00 2001 From: Mimir Date: Tue, 19 Nov 2019 21:16:59 +0700 Subject: [PATCH 3/9] Overload method for Core functionality TxtoUniv Cleaner to add in an overload method than to pass in anything empty. Lots of duplicate code so this absolutely can be improved greater than this. The reason for this is that veil-tx and some test files will fail to build if `GetTxRingCtInputs`is there. --- src/core_io.h | 3 +- src/core_write.cpp | 76 ++++++++++++++++++++++++++++++- src/rest.cpp | 2 +- src/rpc/blockchain.cpp | 2 +- src/rpc/rawtransaction.cpp | 17 ++++--- src/veil-tx.cpp | 2 +- src/veil/ringct/rpcanonwallet.cpp | 2 +- 7 files changed, 91 insertions(+), 13 deletions(-) diff --git a/src/core_io.h b/src/core_io.h index 63fe1c1f98..667fe00f0d 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -36,6 +36,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..e01fc0444b 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -257,7 +257,7 @@ 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) +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()); @@ -279,8 +279,82 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, const std::vecto 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!"); //Add ring ct inputs + } 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); + + 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", "anon"); + uint32_t nSigInputs, nSigRingSize; + txin.GetAnonInfo(nSigInputs, nSigRingSize); + in.pushKV("num_inputs", (int) nSigInputs); + in.pushKV("ring_size", (int) nSigRingSize); + if (vTxRingCtInputs.size() > i) { std::vector vRingCtInputs = vTxRingCtInputs[i]; UniValue arrRing(UniValue::VARR); diff --git a/src/rest.cpp b/src/rest.cpp index a71252ffb9..d89624e68b 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -380,7 +380,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..f18b00d613 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -146,7 +146,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx UniValue objTx(UniValue::VOBJ); std::vector > vInputs; GetRingCtInputs(tx->vin[0], vInputs); - TxToUniv(*tx, uint256(), vInputs, objTx, true, RPCSerializationFlags()); + TxToUniv(*tx, uint256(), objTx, vInputs, true, RPCSerializationFlags()); txs.push_back(objTx); } else diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1175ac0822..a75158bd1d 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -40,14 +40,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 +202,10 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) } //Get ringct inputs - std::vector > vTxRingCtInputs = GetTxRingCtInputs(tx); + // std::vector > vTxRingCtInputs = *tx.GetTxRingCtInputs(); 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..eaecd28311 100644 --- a/src/veil-tx.cpp +++ b/src/veil-tx.cpp @@ -719,7 +719,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/rpcanonwallet.cpp b/src/veil/ringct/rpcanonwallet.cpp index 4a3a66390b..5eaae49c21 100644 --- a/src/veil/ringct/rpcanonwallet.cpp +++ b/src/veil/ringct/rpcanonwallet.cpp @@ -1902,7 +1902,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); } From f281df7cbe0432c826bead00d4e3cb9a4726b80e Mon Sep 17 00:00:00 2001 From: Mimir Date: Tue, 19 Nov 2019 21:18:00 +0700 Subject: [PATCH 4/9] GetTxringCtInputs takes in an actual reference This should be faster to do it like this. I'm not sure why the other class was considered. --- src/veil/ringct/anon.cpp | 4 ++-- src/veil/ringct/anon.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/veil/ringct/anon.cpp b/src/veil/ringct/anon.cpp index 3587bc19e1..9b28316ac1 100644 --- a/src/veil/ringct/anon.cpp +++ b/src/veil/ringct/anon.cpp @@ -296,10 +296,10 @@ bool RollBackRCTIndex(int64_t nLastValidRCTOutput, int64_t nExpectErase, std::se return true; } -std::vector> GetTxRingCtInputs(const CTransactionRef ptx) +std::vector> GetTxRingCtInputs(const CTransaction& tx) { std::vector > vTxRingCtInputs; - for (const CTxIn& txin : ptx->vin) { + for (const CTxIn& txin : tx.vin) { if (txin.IsAnonInput()) { std::vector vInputs = GetRingCtInputs(txin); vTxRingCtInputs.emplace_back(vInputs); diff --git a/src/veil/ringct/anon.h b/src/veil/ringct/anon.h index e45d783f6c..304273ca04 100644 --- a/src/veil/ringct/anon.h +++ b/src/veil/ringct/anon.h @@ -31,7 +31,7 @@ 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> GetTxRingCtInputs(const CTransaction& tx); #endif //VEIL_ANON_H From 480aa7893a9bb0be8b28a9c10004ff9bedb381e1 Mon Sep 17 00:00:00 2001 From: Mimir Date: Tue, 19 Nov 2019 21:19:30 +0700 Subject: [PATCH 5/9] KeyImage code added to TxToUniv We need the RPC to be able to display the key images for RingCT. This allows us to extend Veil more beyond just Veil Core. --- src/core_write.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index e01fc0444b..bbd1b0d943 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -281,7 +281,14 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, in.pushKV("ring_size", (int) nSigRingSize); in.pushKV("ringct_inputs", "To see the RingCT inputs, you must run the core library!"); - //Add ring ct inputs + const std::vector vKeyImages = txin.scriptData.stack[0]; + UniValue arrKeyImages(UniValue::VARR); + for (unsigned int k = 0; k < nSigInputs; k++) { + UniValue objKeyImage(UniValue::VOBJ); + objKeyImage.pushKV(std::to_string(k), HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant + arrKeyImages.push_back(objKeyImage); + } + in.pushKV("key_images", arrKeyImages); } else { in.pushKV("txid", txin.prevout.hash.GetHex()); if (txin.IsZerocoinSpend()) { @@ -366,6 +373,15 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, } in.pushKV("ringct_inputs", arrRing); } + + const std::vector vKeyImages = txin.scriptData.stack[0]; + UniValue arrKeyImages(UniValue::VARR); + for (unsigned int k = 0; k < nSigInputs; k++) { + UniValue objKeyImage(UniValue::VOBJ); + objKeyImage.pushKV(std::to_string(k), HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant + arrKeyImages.push_back(objKeyImage); + } + in.pushKV("key_images", arrKeyImages); } else { in.pushKV("txid", txin.prevout.hash.GetHex()); if (txin.IsZerocoinSpend()) { From 3abedee94e5fa2f4d52d3df3442d66d971e2d567 Mon Sep 17 00:00:00 2001 From: Mimir Date: Wed, 20 Nov 2019 23:05:49 +0700 Subject: [PATCH 6/9] Copyright and cleanup Copyrights added to changed flies and commented line removed as per review request. --- src/core_io.h | 1 + src/core_write.cpp | 1 + src/rest.cpp | 1 + src/rpc/rawtransaction.cpp | 2 +- src/veil-tx.cpp | 1 + src/veil/ringct/anon.cpp | 1 + src/veil/ringct/anon.h | 1 + src/veil/ringct/rpcanonwallet.cpp | 1 + src/wallet/rpcwallet.cpp | 1 + 9 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core_io.h b/src/core_io.h index 667fe00f0d..01c9b870e0 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. diff --git a/src/core_write.cpp b/src/core_write.cpp index bbd1b0d943..b98f69df7e 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. diff --git a/src/rest.cpp b/src/rest.cpp index d89624e68b..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. diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index a75158bd1d..2b4f84ddfc 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. @@ -202,7 +203,6 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) } //Get ringct inputs - // std::vector > vTxRingCtInputs = *tx.GetTxRingCtInputs(); UniValue result(UniValue::VOBJ); if (blockindex) result.pushKV("in_active_chain", in_active_chain); TxToJSON(*tx, hash_block, result); diff --git a/src/veil-tx.cpp b/src/veil-tx.cpp index eaecd28311..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. diff --git a/src/veil/ringct/anon.cpp b/src/veil/ringct/anon.cpp index 9b28316ac1..ffeccdaf7e 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. diff --git a/src/veil/ringct/anon.h b/src/veil/ringct/anon.h index 304273ca04..ec807f8f67 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 diff --git a/src/veil/ringct/rpcanonwallet.cpp b/src/veil/ringct/rpcanonwallet.cpp index 5eaae49c21..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. diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c826153f43..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. From 1e699d7ef91d951051c20b0a91d92e02c2008480 Mon Sep 17 00:00:00 2001 From: Mimir Date: Thu, 21 Nov 2019 17:21:53 +0700 Subject: [PATCH 7/9] Change key images from array sequence map to array. The count up from 0 is too much and the map itself should've been sequential. Erasing the map and putting it all together as an array makes a lot more sense. --- src/core_write.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index b98f69df7e..8996a3cd35 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -283,13 +283,11 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, in.pushKV("ringct_inputs", "To see the RingCT inputs, you must run the core library!"); const std::vector vKeyImages = txin.scriptData.stack[0]; - UniValue arrKeyImages(UniValue::VARR); + UniValue objKeyImage(UniValue::VARR); for (unsigned int k = 0; k < nSigInputs; k++) { - UniValue objKeyImage(UniValue::VOBJ); - objKeyImage.pushKV(std::to_string(k), HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant - arrKeyImages.push_back(objKeyImage); + objKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant } - in.pushKV("key_images", arrKeyImages); + in.pushKV("key_images", objKeyImage); } else { in.pushKV("txid", txin.prevout.hash.GetHex()); if (txin.IsZerocoinSpend()) { @@ -376,13 +374,11 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, } const std::vector vKeyImages = txin.scriptData.stack[0]; - UniValue arrKeyImages(UniValue::VARR); + UniValue objKeyImage(UniValue::VARR); for (unsigned int k = 0; k < nSigInputs; k++) { - UniValue objKeyImage(UniValue::VOBJ); - objKeyImage.pushKV(std::to_string(k), HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant - arrKeyImages.push_back(objKeyImage); + objKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant } - in.pushKV("key_images", arrKeyImages); + in.pushKV("key_images", objKeyImage); } else { in.pushKV("txid", txin.prevout.hash.GetHex()); if (txin.IsZerocoinSpend()) { From 9cd12421d19fb7c9c118b70ad866761fcf017a5f Mon Sep 17 00:00:00 2001 From: Mimir Date: Thu, 21 Nov 2019 22:14:09 +0700 Subject: [PATCH 8/9] Correct naming for array and ephemeral public key `data_hex` in this context is infact the ephemeral public key. Best to name it as such. Also, the `objKeyImage` is in fact `arrKeyImage`. Missed that on my go through. --- src/core_write.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index 8996a3cd35..0e8db5fadd 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -190,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); } @@ -203,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); } @@ -258,6 +258,8 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } +// 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()); @@ -283,11 +285,11 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, in.pushKV("ringct_inputs", "To see the RingCT inputs, you must run the core library!"); const std::vector vKeyImages = txin.scriptData.stack[0]; - UniValue objKeyImage(UniValue::VARR); + UniValue arrKeyImage(UniValue::VARR); for (unsigned int k = 0; k < nSigInputs; k++) { - objKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant + arrKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); } - in.pushKV("key_images", objKeyImage); + in.pushKV("key_images", arrKeyImage); } else { in.pushKV("txid", txin.prevout.hash.GetHex()); if (txin.IsZerocoinSpend()) { @@ -374,11 +376,11 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, } const std::vector vKeyImages = txin.scriptData.stack[0]; - UniValue objKeyImage(UniValue::VARR); + UniValue arrKeyImage(UniValue::VARR); for (unsigned int k = 0; k < nSigInputs; k++) { - objKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); // TODO: add in constant + arrKeyImage.push_back(HexStr(&vKeyImages[k*33], &vKeyImages[(k*33)+33])); } - in.pushKV("key_images", objKeyImage); + in.pushKV("key_images", arrKeyImage); } else { in.pushKV("txid", txin.prevout.hash.GetHex()); if (txin.IsZerocoinSpend()) { From f6ea7a138c2e22dff1070ca89917b67f6040e68e Mon Sep 17 00:00:00 2001 From: Mimir Date: Fri, 29 Nov 2019 19:35:53 +0700 Subject: [PATCH 9/9] RingCT inputs organized with related data Visually, it didn't look great at all to lump all the commitment, inputs, and key_images together when they are related to one another in groups. This is meant to visually represent that accurately. This should make it easier to turn the Json into objects from other clients and make representation in explorers better. --- src/core_io.h | 2 +- src/core_write.cpp | 40 ++++++++++++------- src/rpc/blockchain.cpp | 6 +-- src/rpc/rawtransaction.cpp | 4 +- src/veil/ringct/anon.cpp | 79 ++++++++++++++++++++++++++++---------- src/veil/ringct/anon.h | 8 ++-- 6 files changed, 95 insertions(+), 44 deletions(-) diff --git a/src/core_io.h b/src/core_io.h index 01c9b870e0..e2156e33e9 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -38,6 +38,6 @@ 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, 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); +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 0e8db5fadd..74e432d109 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -341,7 +341,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, } } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, const std::vector>& vTxRingCtInputs, bool include_hex, int serialize_flags) { +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); @@ -350,6 +350,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, 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]; @@ -357,30 +360,39 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); if (txin.IsAnonInput()) { - in.pushKV("type", "anon"); + 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); - 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); } - - 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()) { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f18b00d613..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(), objTx, vInputs, 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 2b4f84ddfc..7386ad232a 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -48,7 +48,7 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& // 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. - const std::vector>& vTxRingCtInputs = GetTxRingCtInputs(tx); + const std::vector>> &vTxRingCtInputs = GetTxRingCtInputs(tx); TxToUniv(tx, uint256(), entry, vTxRingCtInputs, true, RPCSerializationFlags()); if (!hashBlock.IsNull()) { @@ -583,7 +583,7 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); CTransaction tx = std::move(mtx); - std::vector> vTxRingCtInputs = GetTxRingCtInputs(tx); + std::vector>> vTxRingCtInputs = GetTxRingCtInputs(tx); TxToUniv(tx, uint256(), result, vTxRingCtInputs, false); return result; diff --git a/src/veil/ringct/anon.cpp b/src/veil/ringct/anon.cpp index ffeccdaf7e..a771ca84de 100644 --- a/src/veil/ringct/anon.cpp +++ b/src/veil/ringct/anon.cpp @@ -297,21 +297,24 @@ bool RollBackRCTIndex(int64_t nLastValidRCTOutput, int64_t nExpectErase, std::se return true; } -std::vector> GetTxRingCtInputs(const CTransaction& tx) +// Gets the RingCT inputs from the transaction. +std::vector>> GetTxRingCtInputs(const CTransaction& tx) { - std::vector > vTxRingCtInputs; + 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); @@ -319,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) { @@ -346,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); @@ -369,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) { @@ -392,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 ec807f8f67..3d6581f42b 100644 --- a/src/veil/ringct/anon.h +++ b/src/veil/ringct/anon.h @@ -30,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 CTransaction& tx); - +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