#include "wallet/wallet.h"
#endif
+#include "komodo_defs.h"
+
#include <stdint.h>
#include <boost/assign/list_of.hpp>
using namespace std;
+extern char ASSETCHAINS_SYMBOL[];
+
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
{
txnouttype type;
if (fIncludeHex)
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
- if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
+ if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
+ {
out.push_back(Pair("type", GetTxnOutputType(type)));
return;
}
out.push_back(Pair("addresses", a));
}
-
UniValue TxJoinSplitToJSON(const CTransaction& tx) {
bool useGroth = tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION;
UniValue vjoinsplit(UniValue::VARR);
UniValue joinsplit(UniValue::VOBJ);
joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old)));
+ joinsplit.push_back(Pair("vpub_oldZat", jsdescription.vpub_old));
joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new)));
+ joinsplit.push_back(Pair("vpub_newZat", jsdescription.vpub_new));
joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex()));
return vjoinsplit;
}
+uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
+
UniValue TxShieldedSpendsToJSON(const CTransaction& tx) {
UniValue vdesc(UniValue::VARR);
for (const SpendDescription& spendDesc : tx.vShieldedSpend) {
return vdesc;
}
+int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout)
+{
+ CSpentIndexValue spentInfo; CSpentIndexKey spentKey(txid,vout);
+ if ( GetSpentIndex(spentKey,spentInfo) )
+ {
+ spenttxid = spentInfo.txid;
+ return((int32_t)spentInfo.inputIndex);
+ // out.push_back(Pair("spentHeight", spentInfo.blockHeight));
+ }
+ memset(&spenttxid,0,sizeof(spenttxid));
+ return(-1);
+}
+
+void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0)
+{
+ uint256 txid = tx.GetHash();
+ entry.push_back(Pair("txid", txid.GetHex()));
+ entry.push_back(Pair("overwintered", tx.fOverwintered));
+ entry.push_back(Pair("version", tx.nVersion));
+ if (tx.fOverwintered) {
+ entry.push_back(Pair("versiongroupid", HexInt(tx.nVersionGroupId)));
+ }
+ entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
+ if (tx.fOverwintered) {
+ entry.push_back(Pair("expiryheight", (int64_t)tx.nExpiryHeight));
+ }
+ UniValue vin(UniValue::VARR);
+ BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ UniValue in(UniValue::VOBJ);
+ if (tx.IsCoinBase())
+ in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
+ else if (tx.IsCoinImport()) {
+ in.push_back(Pair("is_import", "1"));
+ }
+ else {
+ in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
+ in.push_back(Pair("vout", (int64_t)txin.prevout.n));
+ {
+ uint256 hash; CTransaction tx; CTxDestination address;
+ if (GetTransaction(txin.prevout.hash,tx,hash,false))
+ {
+ if (ExtractDestination(tx.vout[txin.prevout.n].scriptPubKey, address))
+ in.push_back(Pair("address", CBitcoinAddress(address).ToString()));
+ }
+ }
+ UniValue o(UniValue::VOBJ);
+ o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
+ o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
+ in.push_back(Pair("scriptSig", o));
+
+ // Add address and value info if spentindex enabled
+ CSpentIndexValue spentInfo;
+ CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
+ if (GetSpentIndex(spentKey, spentInfo)) {
+ in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis)));
+ in.push_back(Pair("valueSat", spentInfo.satoshis));
+ if (spentInfo.addressType == 1) {
+ in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
+ }
+ else if (spentInfo.addressType == 2) {
+ in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
+ }
+ }
+ }
+ in.push_back(Pair("sequence", (int64_t)txin.nSequence));
+ vin.push_back(in);
+ }
+ entry.push_back(Pair("vin", vin));
+ BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
+ CBlockIndex *tipindex,*pindex = it->second;
+ uint64_t interest;
+ UniValue vout(UniValue::VARR);
+ for (unsigned int i = 0; i < tx.vout.size(); i++)
+ {
+ const CTxOut& txout = tx.vout[i];
+ UniValue out(UniValue::VOBJ);
+ out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
+ if ( ASSETCHAINS_SYMBOL[0] == 0 && pindex != 0 && tx.nLockTime >= 500000000 && (tipindex= chainActive.LastTip()) != 0 )
+ {
+ int64_t interest; int32_t txheight; uint32_t locktime;
+ interest = komodo_accrued_interest(&txheight,&locktime,tx.GetHash(),i,0,txout.nValue,(int32_t)tipindex->GetHeight());
+ out.push_back(Pair("interest", ValueFromAmount(interest)));
+ }
+ out.push_back(Pair("valueSat", txout.nValue)); // [+] Decker
+ out.push_back(Pair("n", (int64_t)i));
+ UniValue o(UniValue::VOBJ);
+ ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
+ out.push_back(Pair("scriptPubKey", o));
+
+ // Add spent information if spentindex is enabled
+ CSpentIndexValue spentInfo;
+ CSpentIndexKey spentKey(txid, i);
+ if (GetSpentIndex(spentKey, spentInfo)) {
+ out.push_back(Pair("spentTxId", spentInfo.txid.GetHex()));
+ out.push_back(Pair("spentIndex", (int)spentInfo.inputIndex));
+ out.push_back(Pair("spentHeight", spentInfo.blockHeight));
+ }
+
+ vout.push_back(out);
+ }
+ entry.push_back(Pair("vout", vout));
+
+ UniValue vjoinsplit = TxJoinSplitToJSON(tx);
+ entry.push_back(Pair("vjoinsplit", vjoinsplit));
+
+ if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) {
+ entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance)));
+ UniValue vspenddesc = TxShieldedSpendsToJSON(tx);
+ entry.push_back(Pair("vShieldedSpend", vspenddesc));
+ UniValue voutputdesc = TxShieldedOutputsToJSON(tx);
+ entry.push_back(Pair("vShieldedOutput", voutputdesc));
+ if (!(vspenddesc.empty() && voutputdesc.empty())) {
+ entry.push_back(Pair("bindingSig", HexStr(tx.bindingSig.begin(), tx.bindingSig.end())));
+ }
+ }
+
+ if (!hashBlock.IsNull()) {
+ entry.push_back(Pair("blockhash", hashBlock.GetHex()));
+
+ if (nConfirmations > 0) {
+ entry.push_back(Pair("height", nHeight));
+ entry.push_back(Pair("confirmations", nConfirmations));
+ entry.push_back(Pair("time", nBlockTime));
+ entry.push_back(Pair("blocktime", nBlockTime));
+ } else {
+ entry.push_back(Pair("height", -1));
+ entry.push_back(Pair("confirmations", 0));
+ }
+ }
+
+}
+
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
}
entry.push_back(Pair("vin", vin));
UniValue vout(UniValue::VARR);
+ BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
+ CBlockIndex *tipindex,*pindex = it->second;
+ uint64_t interest;
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
+ if ( ASSETCHAINS_SYMBOL[0] == 0 && pindex != 0 && tx.nLockTime >= 500000000 && (tipindex= chainActive.LastTip()) != 0 )
+ {
+ int64_t interest; int32_t txheight; uint32_t locktime;
+ interest = komodo_accrued_interest(&txheight,&locktime,tx.GetHash(),i,0,txout.nValue,(int32_t)tipindex->GetHeight());
+ out.push_back(Pair("interest", ValueFromAmount(interest)));
+ }
out.push_back(Pair("valueZat", txout.nValue));
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
- entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
+ entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->GetHeight()));
entry.push_back(Pair("time", pindex->GetBlockTime()));
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
}
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
- " \"zcashaddress\" (string) Zcash address\n"
+ " \"komodoaddress\" (string) Komodo address\n"
" ,...\n"
" ]\n"
" }\n"
" ],\n"
" \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n"
" {\n"
- " \"vpub_old\" : x.xxx, (numeric) public input value in " + CURRENCY_UNIT + "\n"
- " \"vpub_new\" : x.xxx, (numeric) public output value in " + CURRENCY_UNIT + "\n"
+ " \"vpub_old\" : x.xxx, (numeric) public input value in KMD\n"
+ " \"vpub_new\" : x.xxx, (numeric) public output value in KMD\n"
" \"anchor\" : \"hex\", (string) the anchor\n"
" \"nullifiers\" : [ (json array of string)\n"
" \"hex\" (string) input note nullifier\n"
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
);
- LOCK(cs_main);
uint256 hash = ParseHashV(params[0], "parameter 1");
CTransaction tx;
uint256 hashBlock;
- if (!GetTransaction(hash, tx, hashBlock, true))
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
+ int nHeight = 0;
+ int nConfirmations = 0;
+ int nBlockTime = 0;
+
+ {
+ LOCK(cs_main);
+ if (!GetTransaction(hash, tx, hashBlock, true))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
+
+ BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi != mapBlockIndex.end() && (*mi).second) {
+ CBlockIndex* pindex = (*mi).second;
+ if (chainActive.Contains(pindex)) {
+ nHeight = pindex->GetHeight();
+ nConfirmations = 1 + chainActive.Height() - pindex->GetHeight();
+ nBlockTime = pindex->GetBlockTime();
+ } else {
+ nHeight = -1;
+ nConfirmations = 0;
+ nBlockTime = pindex->GetBlockTime();
+ }
+ }
+ }
string strHex = EncodeHexTx(tx);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", strHex));
- TxToJSON(tx, hashBlock, result);
+ TxToJSONExpanded(tx, hashBlock, result, nHeight, nConfirmations, nBlockTime);
return result;
}
+int32_t gettxout_scriptPubKey(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid,int32_t n)
+{
+ int32_t i,m; uint8_t *ptr;
+ LOCK(cs_main);
+ /*CCoins coins;
+ for (iter=0; iter<2; iter++)
+ {
+ if ( iter == 0 )
+ {
+ LOCK(mempool.cs);
+ CCoinsViewMemPool view(pcoinsTip,mempool);
+ if ( view.GetCoins(txid,coins) == 0 )
+ {
+ //fprintf(stderr,"cant get view\n");
+ continue;
+ }
+ mempool.pruneSpent(txid, coins); // TODO: this should be done by the CCoinsViewMemPool
+ }
+ else if ( pcoinsTip->GetCoins(txid,coins) == 0 )
+ {
+ //fprintf(stderr,"cant get pcoinsTip->GetCoins\n");
+ continue;
+ }
+ if ( n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull() )
+ {
+ fprintf(stderr,"iter.%d n.%d vs voutsize.%d\n",iter,n,(int32_t)coins.vout.size());
+ continue;
+ }
+ ptr = (uint8_t *)coins.vout[n].scriptPubKey.data();
+ m = coins.vout[n].scriptPubKey.size();
+ for (i=0; i<maxsize&&i<m; i++)
+ scriptPubKey[i] = ptr[i];
+ return(i);
+ }*/
+ CTransaction tx;
+ uint256 hashBlock;
+ if ( GetTransaction(txid,tx,hashBlock,false) == 0 )
+ return(-1);
+ else if ( n <= tx.vout.size() ) // vout.size() seems off by 1
+ {
+ ptr = (uint8_t *)&tx.vout[n].scriptPubKey[0];
+ m = tx.vout[n].scriptPubKey.size();
+ for (i=0; i<maxsize&&i<m; i++)
+ scriptPubKey[i] = ptr[i];
+ //fprintf(stderr,"got scriptPubKey via rawtransaction\n");
+ return(i);
+ }
+ return(-1);
+}
+
UniValue gettxoutproof(const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 1 && params.size() != 2))
}
CBlock block;
- if(!ReadBlockFromDisk(block, pblockindex))
+ if(!ReadBlockFromDisk(block, pblockindex,1))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
unsigned int ntxFound = 0;
return res;
LOCK(cs_main);
-
- if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
+ uint256 idx = merkleBlock.header.GetHash();
+ if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || (mapBlockIndex.count(idx) && !chainActive.Contains(mapBlockIndex[idx])))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
BOOST_FOREACH(const uint256& hash, vMatch)
" ]\n"
"2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n"
" {\n"
- " \"address\": x.xxx (numeric, required) The key is the Zcash address, the value is the " + CURRENCY_UNIT + " amount\n"
+ " \"address\": x.xxx (numeric, required) The key is the Komodo address, the value is the " + CURRENCY_UNIT + " amount\n"
" ,...\n"
" }\n"
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
for (const std::string& name_ : addrList) {
CTxDestination destination = DecodeDestination(name_);
if (!IsValidDestination(destination)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Komodo address: ") + name_);
}
if (!destinations.insert(destination).second) {
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
- " \"t12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) zcash address\n"
+ " \"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\" (string) komodo address\n"
" ,...\n"
" ]\n"
" }\n"
" ],\n"
" \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n"
" {\n"
- " \"vpub_old\" : x.xxx, (numeric) public input value in " + CURRENCY_UNIT + "\n"
- " \"vpub_new\" : x.xxx, (numeric) public output value in " + CURRENCY_UNIT + "\n"
+ " \"vpub_old\" : x.xxx, (numeric) public input value in KMD\n"
+ " \"vpub_new\" : x.xxx, (numeric) public output value in KMD\n"
" \"anchor\" : \"hex\", (string) the anchor\n"
" \"nullifiers\" : [ (json array of string)\n"
" \"hex\" (string) input note nullifier\n"
" \"type\":\"type\", (string) The output type\n"
" \"reqSigs\": n, (numeric) The required signatures\n"
" \"addresses\": [ (json array of string)\n"
- " \"address\" (string) Zcash address\n"
+ " \"address\" (string) Komodo address\n"
" ,...\n"
" ],\n"
" \"p2sh\",\"address\" (string) script address\n"
// have a better estimation of the current height and will be more likely to
// determine the correct consensus branch ID. Regtest mode ignores release height.
int chainHeight = chainActive.Height() + 1;
- if (Params().NetworkIDString() != "regtest") {
- chainHeight = std::max(chainHeight, APPROX_RELEASE_HEIGHT);
- }
+
// Grab the current consensus branch ID
auto consensusBranchId = CurrentEpochBranchId(chainHeight, Params().GetConsensus());
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue;
}
- const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
+ const CScript& prevPubKey = CCoinsViewCache::GetSpendFor(coins, txin);
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
SignatureData sigdata;
}
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
- }
+ }
RelayTransaction(tx);
return hashTx.GetHex();