// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "amount.h"
+#include "chain.h"
+#include "chainparams.h"
#include "checkpoints.h"
+#include "base58.h"
#include "consensus/validation.h"
+#include "cc/betprotocol.h"
#include "main.h"
#include "primitives/transaction.h"
#include "rpcserver.h"
#include "sync.h"
#include "util.h"
+#include "script/script.h"
+#include "script/script_error.h"
+#include "script/sign.h"
+#include "script/standard.h"
#include <stdint.h>
int nShiftAmount = (powLimit >> 24) & 0xff;
double dDiff =
- (double)(powLimit & 0x00ffffff) /
+ (double)(powLimit & 0x00ffffff) /
(double)(bits & 0x00ffffff);
while (nShift < nShiftAmount)
return GetDifficultyINTERNAL(blockindex, true);
}
+static UniValue ValuePoolDesc(
+ const std::string &name,
+ const boost::optional<CAmount> chainValue,
+ const boost::optional<CAmount> valueDelta)
+{
+ UniValue rv(UniValue::VOBJ);
+ rv.push_back(Pair("id", name));
+ rv.push_back(Pair("monitored", (bool)chainValue));
+ if (chainValue) {
+ rv.push_back(Pair("chainValue", ValueFromAmount(*chainValue)));
+ rv.push_back(Pair("chainValueZat", *chainValue));
+ }
+ if (valueDelta) {
+ rv.push_back(Pair("valueDelta", ValueFromAmount(*valueDelta)));
+ rv.push_back(Pair("valueDeltaZat", *valueDelta));
+ }
+ return rv;
+}
+
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
UniValue result(UniValue::VOBJ);
return result;
}
+UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
+{
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("hash", block.GetHash().GetHex()));
+ int confirmations = -1;
+ // Only report confirmations if the block is on the main chain
+ if (chainActive.Contains(blockindex)) {
+ confirmations = chainActive.Height() - blockindex->nHeight + 1;
+ } else {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan");
+ }
+ result.push_back(Pair("confirmations", confirmations));
+ result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
+ result.push_back(Pair("height", blockindex->nHeight));
+ result.push_back(Pair("version", block.nVersion));
+ result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
+
+ UniValue deltas(UniValue::VARR);
+
+ for (unsigned int i = 0; i < block.vtx.size(); i++) {
+ const CTransaction &tx = block.vtx[i];
+ const uint256 txhash = tx.GetHash();
+
+ UniValue entry(UniValue::VOBJ);
+ entry.push_back(Pair("txid", txhash.GetHex()));
+ entry.push_back(Pair("index", (int)i));
+
+ UniValue inputs(UniValue::VARR);
+
+ if (!tx.IsCoinBase()) {
+
+ for (size_t j = 0; j < tx.vin.size(); j++) {
+ const CTxIn input = tx.vin[j];
+
+ UniValue delta(UniValue::VOBJ);
+
+ CSpentIndexValue spentInfo;
+ CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n);
+
+ if (GetSpentIndex(spentKey, spentInfo)) {
+ if (spentInfo.addressType == 1) {
+ delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
+ } else if (spentInfo.addressType == 2) {
+ delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
+ } else {
+ continue;
+ }
+ delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis));
+ delta.push_back(Pair("index", (int)j));
+ delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex()));
+ delta.push_back(Pair("prevout", (int)input.prevout.n));
+
+ inputs.push_back(delta);
+ } else {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available");
+ }
+
+ }
+ }
+
+ entry.push_back(Pair("inputs", inputs));
+
+ UniValue outputs(UniValue::VARR);
+
+ for (unsigned int k = 0; k < tx.vout.size(); k++) {
+ const CTxOut &out = tx.vout[k];
+
+ UniValue delta(UniValue::VOBJ);
+
+ if (out.scriptPubKey.IsPayToScriptHash()) {
+ vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
+ delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString()));
+
+ } else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
+ vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
+ delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString()));
+ } else {
+ continue;
+ }
+
+ delta.push_back(Pair("satoshis", out.nValue));
+ delta.push_back(Pair("index", (int)k));
+
+ outputs.push_back(delta);
+ }
+
+ entry.push_back(Pair("outputs", outputs));
+ deltas.push_back(entry);
+
+ }
+ result.push_back(Pair("deltas", deltas));
+ result.push_back(Pair("time", block.GetBlockTime()));
+ result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
+ result.push_back(Pair("nonce", block.nNonce.GetHex()));
+ result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
+ result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
+ result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
+
+ if (blockindex->pprev)
+ result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
+ CBlockIndex *pnext = chainActive.Next(blockindex);
+ if (pnext)
+ result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
+ return result;
+}
+
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
UniValue result(UniValue::VOBJ);
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("anchor", blockindex->hashAnchorEnd.GetHex()));
+ UniValue valuePools(UniValue::VARR);
+ valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue));
+ result.push_back(Pair("valuePools", valuePools));
+
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
CBlockIndex *pnext = chainActive.Next(blockindex);
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockcount\n"
- "\nReturns the number of blocks in the longest block chain.\n"
+ "\nReturns the number of blocks in the best valid block chain.\n"
"\nResult:\n"
"n (numeric) The current block count\n"
"\nExamples:\n"
{
LOCK(mempool.cs);
UniValue o(UniValue::VOBJ);
- BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
+ BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx)
{
- const uint256& hash = entry.first;
- const CTxMemPoolEntry& e = entry.second;
+ const uint256& hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
info.push_back(Pair("size", (int)e.GetTxSize()));
info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
" \"size\" : n, (numeric) transaction size in bytes\n"
- " \"fee\" : n, (numeric) transaction fee in bitcoins\n"
+ " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
return mempoolToJSON(fVerbose);
}
+UniValue getblockdeltas(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error("");
+
+ std::string strHash = params[0].get_str();
+ uint256 hash(uint256S(strHash));
+
+ if (mapBlockIndex.count(hash) == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+
+ CBlock block;
+ CBlockIndex* pblockindex = mapBlockIndex[hash];
+
+ if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
+
+ if(!ReadBlockFromDisk(block, pblockindex,1))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+
+ return blockToDeltasJSON(block, pblockindex);
+}
+
+UniValue getblockhashes(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2)
+ throw runtime_error(
+ "getblockhashes timestamp\n"
+ "\nReturns array of hashes of blocks within the timestamp range provided.\n"
+ "\nArguments:\n"
+ "1. high (numeric, required) The newer block timestamp\n"
+ "2. low (numeric, required) The older block timestamp\n"
+ "3. options (string, required) A json object\n"
+ " {\n"
+ " \"noOrphans\":true (boolean) will only include blocks on the main chain\n"
+ " \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n"
+ " }\n"
+ "\nResult:\n"
+ "[\n"
+ " \"hash\" (string) The block hash\n"
+ "]\n"
+ "[\n"
+ " {\n"
+ " \"blockhash\": (string) The block hash\n"
+ " \"logicalts\": (numeric) The logical timestamp\n"
+ " }\n"
+ "]\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getblockhashes", "1231614698 1231024505")
+ + HelpExampleRpc("getblockhashes", "1231614698, 1231024505")
+ + HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'")
+ );
+
+ unsigned int high = params[0].get_int();
+ unsigned int low = params[1].get_int();
+ bool fActiveOnly = false;
+ bool fLogicalTS = false;
+
+ if (params.size() > 2) {
+ if (params[2].isObject()) {
+ UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans");
+ UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes");
+
+ if (noOrphans.isBool())
+ fActiveOnly = noOrphans.get_bool();
+
+ if (returnLogical.isBool())
+ fLogicalTS = returnLogical.get_bool();
+ }
+ }
+
+ std::vector<std::pair<uint256, unsigned int> > blockHashes;
+
+ if (fActiveOnly)
+ LOCK(cs_main);
+
+ if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes");
+ }
+
+ UniValue result(UniValue::VARR);
+
+ for (std::vector<std::pair<uint256, unsigned int> >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) {
+ if (fLogicalTS) {
+ UniValue item(UniValue::VOBJ);
+ item.push_back(Pair("blockhash", it->first.GetHex()));
+ item.push_back(Pair("logicalts", (int)it->second));
+ result.push_back(item);
+ } else {
+ result.push_back(it->first.GetHex());
+ }
+ }
+
+ return result;
+}
+
UniValue getblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
return pblockindex->GetBlockHash().GetHex();
}
-uint256 _komodo_getblockhash(int32_t nHeight)
+/*uint256 _komodo_getblockhash(int32_t nHeight)
{
uint256 hash;
LOCK(cs_main);
printf(" blockhash.%d\n",nHeight);
} else memset(&hash,0,sizeof(hash));
return(hash);
-}
+}*/
UniValue getblockheader(const UniValue& params, bool fHelp)
{
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
- if(!ReadBlockFromDisk(block, pblockindex))
+ if(!ReadBlockFromDisk(block, pblockindex,1))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
if (!fVerbose)
return ret;
}
+#include "komodo_defs.h"
+#include "komodo_structs.h"
+
#define IGUANA_MAXSCRIPTSIZE 10001
#define KOMODO_KVDURATION 1440
#define KOMODO_KVBINARY 2
-extern char ASSETCHAINS_SYMBOL[16];
-uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
-uint32_t komodo_txtime(uint256 hash);
+extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume);
int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel);
-int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height);
+int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
-//uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n);
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width);
int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
-/*uint64_t conv_NXTpassword(unsigned char *mysecret,unsigned char *mypublic,uint8_t *pass,int32_t passlen);
-
-
-UniValue passphrasewif(const UniValue& params, bool fHelp)
-{
- UniValue ret(UniValue::VOBJ); char *passphrase,wifstr[64],coinaddr[64]; uint8_t tmptype,pubkey33[33]; void *ctx; uint256 privkey,pubkey;
- passphrase = params[0].get_str().c_str();
- conv_NXTpassword((void *)&privkey,(void *)&pubkey,(uint8_t *)passphrase,(int32_t)strlen(passphrase));
- ctx = bitcoin_ctx();
- bitcoin_priv2pub(ctx,pubkey33,coinaddr,privkey,0,60);
- bitcoin_priv2wif(0,wifstr,privkey,188);
- free(ctx);
- ret.push_back(Pair("address",coinaddr));
- ret.push_back(Pair("wif",wifstr));
- return ret;
-}*/
+int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip);
+int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height);
+struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi);
+uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
UniValue kvsearch(const UniValue& params, bool fHelp)
{
UniValue ret(UniValue::VOBJ); uint32_t flags; uint8_t value[IGUANA_MAXSCRIPTSIZE],key[IGUANA_MAXSCRIPTSIZE]; int32_t duration,j,height,valuesize,keylen; uint256 refpubkey; static uint256 zeroes;
if (fHelp || params.size() != 1 )
- throw runtime_error("kvsearch key");
+ throw runtime_error(
+ "kvsearch key\n"
+ "\nSearch for a key stored via the kvupdate command. This feature is only available for asset chains.\n"
+ "\nArguments:\n"
+ "1. key (string, required) search the chain for this key\n"
+ "\nResult:\n"
+ "{\n"
+ " \"coin\": \"xxxxx\", (string) chain the key is stored on\n"
+ " \"currentheight\": xxxxx, (numeric) current height of the chain\n"
+ " \"key\": \"xxxxx\", (string) key\n"
+ " \"keylen\": xxxxx, (string) length of the key \n"
+ " \"owner\": \"xxxx\" (string) hex string representing the owner of the key \n"
+ " \"height\": xxxxx, (numeric) height the key was stored at\n"
+ " \"expiration\": xxxxx, (numeric) height the key will expire\n"
+ " \"flags\": x (numeric) 1 if the key was created with a password; 0 otherwise.\n"
+ " \"value\": \"xxxxx\", (string) stored value\n"
+ " \"valuesize\": xxxxx (string) amount of characters stored\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("kvsearch", "examplekey")
+ + HelpExampleRpc("kvsearch", "examplekey")
+ );
LOCK(cs_main);
if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
{
return ret;
}
+UniValue allMoMs(const UniValue& params, bool fHelp)
+{
+ struct komodo_ccdata_entry *allMoMs; uint256 MoMoM; int32_t num,i,kmdstarti,kmdendi; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
+ if ( fHelp || params.size() != 2 )
+ throw runtime_error("allMoMs kmdstarti kmdendi\n");
+ LOCK(cs_main);
+ kmdstarti = atoi(params[0].get_str().c_str());
+ kmdendi = atoi(params[1].get_str().c_str());
+ ret.push_back(Pair("kmdstarti",kmdstarti));
+ ret.push_back(Pair("kmdendi",kmdendi));
+ if ( (allMoMs= komodo_allMoMs(&num,&MoMoM,kmdstarti,kmdendi)) != 0 )
+ {
+ for (i=0; i<num; i++)
+ {
+ UniValue item(UniValue::VOBJ);
+ item.push_back(Pair("MoM",allMoMs[i].MoM.ToString()));
+ item.push_back(Pair("coin",allMoMs[i].symbol));
+ item.push_back(Pair("notarized_height",allMoMs[i].notarized_height));
+ item.push_back(Pair("kmdheight",allMoMs[i].kmdheight));
+ item.push_back(Pair("txi",allMoMs[i].txi));
+ a.push_back(item);
+ }
+ ret.push_back(Pair("MoMs",a));
+ ret.push_back(Pair("MoMoM",MoMoM.ToString()));
+ ret.push_back(Pair("MoMoMdepth",(int)num));
+ free(allMoMs);
+ }
+ return(ret);
+}
+
+UniValue MoMoMdata(const UniValue& params, bool fHelp)
+{
+ char *symbol,hexstr[16384+1]; struct komodo_ccdataMoMoM mdata; int32_t i,kmdheight,notarized_height; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
+ if ( fHelp || params.size() != 3 )
+ throw runtime_error("MoMoMdata symbol kmdheight notarized_height\n");
+ LOCK(cs_main);
+ symbol = (char *)params[0].get_str().c_str();
+ kmdheight = atoi(params[1].get_str().c_str());
+ notarized_height = atoi(params[2].get_str().c_str());
+ ret.push_back(Pair("coin",symbol));
+ ret.push_back(Pair("kmdheight",kmdheight));
+ ret.push_back(Pair("notarized_height",notarized_height));
+ memset(&mdata,0,sizeof(mdata));
+ if ( komodo_MoMoMdata(hexstr,sizeof(hexstr),&mdata,symbol,kmdheight,notarized_height) == 0 )
+ {
+ ret.push_back(Pair("kmdstarti",mdata.kmdstarti));
+ ret.push_back(Pair("kmdendi",mdata.kmdendi));
+ ret.push_back(Pair("MoMoM",mdata.MoMoM.ToString()));
+ ret.push_back(Pair("MoMoMdepth",mdata.MoMoMdepth));
+ ret.push_back(Pair("numnotarizations",mdata.numpairs));
+ if ( mdata.pairs != 0 )
+ {
+ //fprintf(stderr,"mdata.pairs free %p, numpairs.%d\n",mdata.pairs,mdata.numpairs);
+ for (i=0; i<mdata.numpairs; i++)
+ {
+ UniValue item(UniValue::VOBJ);
+ item.push_back(Pair("height",(int)mdata.pairs[i].notarized_height));
+ item.push_back(Pair("MoMoMoffset",(int)mdata.pairs[i].MoMoMoffset));
+ a.push_back(item);
+ }
+ free(mdata.pairs);
+ }
+ ret.push_back(Pair("notarizations",a));
+ ret.push_back(Pair("data",hexstr));
+ } else ret.push_back(Pair("error","cant calculate MoMoM"));
+ return(ret);
+}
+
+UniValue calc_MoM(const UniValue& params, bool fHelp)
+{
+ int32_t height,MoMdepth; uint256 MoM; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
+ if ( fHelp || params.size() != 2 )
+ throw runtime_error("calc_MoM height MoMdepth\n");
+ LOCK(cs_main);
+ height = atoi(params[0].get_str().c_str());
+ MoMdepth = atoi(params[1].get_str().c_str());
+ if ( height <= 0 || MoMdepth <= 0 || MoMdepth >= height )
+ throw runtime_error("calc_MoM illegal height or MoMdepth\n");
+ //fprintf(stderr,"height_MoM height.%d\n",height);
+ MoM = komodo_calcMoM(height,MoMdepth);
+ ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
+ ret.push_back(Pair("height",height));
+ ret.push_back(Pair("MoMdepth",MoMdepth));
+ ret.push_back(Pair("MoM",MoM.GetHex()));
+ return ret;
+}
+
+UniValue height_MoM(const UniValue& params, bool fHelp)
+{
+ int32_t height,depth,notarized_height,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; uint256 MoM,MoMoM,kmdtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
+ if ( fHelp || params.size() != 1 )
+ throw runtime_error("height_MoM height\n");
+ LOCK(cs_main);
+ height = atoi(params[0].get_str().c_str());
+ if ( height <= 0 )
+ {
+ if ( chainActive.Tip() == 0 )
+ {
+ ret.push_back(Pair("error",(char *)"no active chain yet"));
+ return(ret);
+ }
+ height = chainActive.Tip()->nHeight;
+ }
+ //fprintf(stderr,"height_MoM height.%d\n",height);
+ depth = komodo_MoM(¬arized_height,&MoM,&kmdtxid,height,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
+ ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
+ ret.push_back(Pair("height",height));
+ ret.push_back(Pair("timestamp",(uint64_t)timestamp));
+ if ( depth > 0 )
+ {
+ ret.push_back(Pair("depth",depth));
+ ret.push_back(Pair("notarized_height",notarized_height));
+ ret.push_back(Pair("MoM",MoM.GetHex()));
+ ret.push_back(Pair("kmdtxid",kmdtxid.GetHex()));
+ if ( ASSETCHAINS_SYMBOL[0] != 0 )
+ {
+ ret.push_back(Pair("MoMoM",MoMoM.GetHex()));
+ ret.push_back(Pair("MoMoMoffset",MoMoMoffset));
+ ret.push_back(Pair("MoMoMdepth",MoMoMdepth));
+ ret.push_back(Pair("kmdstarti",kmdstarti));
+ ret.push_back(Pair("kmdendi",kmdendi));
+ }
+ } else ret.push_back(Pair("error",(char *)"no MoM for height"));
+
+ return ret;
+}
+
+UniValue txMoMproof(const UniValue& params, bool fHelp)
+{
+ uint256 hash, notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex;
+ std::vector<uint256> branch;
+ int nIndex,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi;
+
+ // parse params and get notarisation data for tx
+ {
+ if ( fHelp || params.size() != 1)
+ throw runtime_error("txMoMproof needs a txid");
+
+ hash = uint256S(params[0].get_str());
+
+ uint256 blockHash;
+ CTransaction tx;
+ if (!GetTransaction(hash, tx, blockHash, true))
+ throw runtime_error("cannot find transaction");
+
+ blockIndex = mapBlockIndex[blockHash];
+
+ depth = komodo_MoM(¬arisedHeight, &MoM, ¬arisationHash, blockIndex->nHeight,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
+
+ if (!depth)
+ throw runtime_error("notarisation not found");
+
+ // index of block in MoM leaves
+ nIndex = notarisedHeight - blockIndex->nHeight;
+ }
+
+ // build merkle chain from blocks to MoM
+ {
+ // since the merkle branch code is tied up in a block class
+ // and we want to make a merkle branch for something that isnt transactions
+ CBlock fakeBlock;
+ for (int i=0; i<depth; i++) {
+ uint256 mRoot = chainActive[notarisedHeight - i]->hashMerkleRoot;
+ CTransaction fakeTx;
+ // first value in CTransaction memory is it's hash
+ memcpy((void*)&fakeTx, mRoot.begin(), 32);
+ fakeBlock.vtx.push_back(fakeTx);
+ }
+ branch = fakeBlock.GetMerkleBranch(nIndex);
+
+ // Check branch
+ if (MoM != CBlock::CheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed merkle block->MoM");
+ }
+
+ // Now get the tx merkle branch
+ {
+ CBlock block;
+
+ if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0)
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
+
+ if(!ReadBlockFromDisk(block, blockIndex,1))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+
+ // Locate the transaction in the block
+ int nTxIndex;
+ for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++)
+ if (block.vtx[nTxIndex].GetHash() == hash)
+ break;
+
+ if (nTxIndex == (int)block.vtx.size())
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Error locating tx in block");
+
+ std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex);
+
+ // Check branch
+ if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed merkle tx->block");
+
+ // concatenate branches
+ nIndex = (nIndex << txBranch.size()) + nTxIndex;
+ branch.insert(branch.begin(), txBranch.begin(), txBranch.end());
+ }
+
+ // Check the proof
+ if (MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed validating MoM");
+
+ // Encode and return
+ CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION);
+ ssProof << MoMProof(nIndex, branch, notarisationHash);
+ return HexStr(ssProof.begin(), ssProof.end());
+}
+
UniValue minerids(const UniValue& params, bool fHelp)
{
- UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); uint8_t minerids[2000],pubkeys[65][33]; int32_t i,j,n,numnotaries,tally[129];
+ uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); uint8_t minerids[2000],pubkeys[65][33]; int32_t i,j,n,numnotaries,tally[129];
if ( fHelp || params.size() != 1 )
throw runtime_error("minerids needs height\n");
LOCK(cs_main);
int32_t height = atoi(params[0].get_str().c_str());
if ( height <= 0 )
height = chainActive.Tip()->nHeight;
+ else
+ {
+ CBlockIndex *pblockindex = chainActive[height];
+ if ( pblockindex != 0 )
+ timestamp = pblockindex->GetBlockTime();
+ }
if ( (n= komodo_minerids(minerids,height,(int32_t)(sizeof(minerids)/sizeof(*minerids)))) > 0 )
{
memset(tally,0,sizeof(tally));
- numnotaries = komodo_notaries(pubkeys,height);
+ numnotaries = komodo_notaries(pubkeys,height,timestamp);
if ( numnotaries > 0 )
{
for (i=0; i<n; i++)
for (j=0; j<33; j++)
sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]);
item.push_back(Pair("notaryid", i));
-
+
bitcoin_address(kmdaddr,60,pubkeys[i],33);
m = (int32_t)strlen(kmdaddr);
kmdaddress.resize(m);
ptr = (char *)kmdaddress.data();
memcpy(ptr,kmdaddr,m);
item.push_back(Pair("KMDaddress", kmdaddress));
-
+
item.push_back(Pair("pubkey", hex));
item.push_back(Pair("blocks", tally[i]));
a.push_back(item);
a.push_back(item);
}
ret.push_back(Pair("mined", a));
+ ret.push_back(Pair("numnotaries", numnotaries));
} else ret.push_back(Pair("error", (char *)"couldnt extract minerids"));
return ret;
}
UniValue notaries(const UniValue& params, bool fHelp)
{
- UniValue a(UniValue::VARR); UniValue ret(UniValue::VOBJ); int32_t i,j,n,m; char *hexstr; uint8_t pubkeys[64][33]; char btcaddr[64],kmdaddr[64],*ptr;
- if ( fHelp || params.size() != 1 )
- throw runtime_error("notaries height\n");
+ UniValue a(UniValue::VARR); uint32_t timestamp=0; UniValue ret(UniValue::VOBJ); int32_t i,j,n,m; char *hexstr; uint8_t pubkeys[64][33]; char btcaddr[64],kmdaddr[64],*ptr;
+ if ( fHelp || (params.size() != 1 && params.size() != 2) )
+ throw runtime_error("notaries height timestamp\n");
LOCK(cs_main);
int32_t height = atoi(params[0].get_str().c_str());
+ if ( params.size() == 2 )
+ timestamp = (uint32_t)atol(params[1].get_str().c_str());
+ else timestamp = (uint32_t)time(NULL);
if ( height < 0 )
+ {
height = chainActive.Tip()->nHeight;
- //fprintf(stderr,"notaries as of height.%d\n",height);
- //if ( height > chainActive.Height()+20000 )
- // throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
- //else
+ timestamp = chainActive.Tip()->GetBlockTime();
+ }
+ else if ( params.size() < 2 )
+ {
+ CBlockIndex *pblockindex = chainActive[height];
+ if ( pblockindex != 0 )
+ timestamp = pblockindex->GetBlockTime();
+ }
+ if ( (n= komodo_notaries(pubkeys,height,timestamp)) > 0 )
{
- if ( (n= komodo_notaries(pubkeys,height)) > 0 )
+ for (i=0; i<n; i++)
{
- for (i=0; i<n; i++)
- {
- UniValue item(UniValue::VOBJ);
- std::string btcaddress,kmdaddress,hex;
- hex.resize(66);
- hexstr = (char *)hex.data();
- for (j=0; j<33; j++)
- sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]);
- item.push_back(Pair("pubkey", hex));
-
- bitcoin_address(btcaddr,0,pubkeys[i],33);
- m = (int32_t)strlen(btcaddr);
- btcaddress.resize(m);
- ptr = (char *)btcaddress.data();
- memcpy(ptr,btcaddr,m);
- item.push_back(Pair("BTCaddress", btcaddress));
-
- bitcoin_address(kmdaddr,60,pubkeys[i],33);
- m = (int32_t)strlen(kmdaddr);
- kmdaddress.resize(m);
- ptr = (char *)kmdaddress.data();
- memcpy(ptr,kmdaddr,m);
- item.push_back(Pair("KMDaddress", kmdaddress));
- a.push_back(item);
- }
+ UniValue item(UniValue::VOBJ);
+ std::string btcaddress,kmdaddress,hex;
+ hex.resize(66);
+ hexstr = (char *)hex.data();
+ for (j=0; j<33; j++)
+ sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]);
+ item.push_back(Pair("pubkey", hex));
+
+ bitcoin_address(btcaddr,0,pubkeys[i],33);
+ m = (int32_t)strlen(btcaddr);
+ btcaddress.resize(m);
+ ptr = (char *)btcaddress.data();
+ memcpy(ptr,btcaddr,m);
+ item.push_back(Pair("BTCaddress", btcaddress));
+
+ bitcoin_address(kmdaddr,60,pubkeys[i],33);
+ m = (int32_t)strlen(kmdaddr);
+ kmdaddress.resize(m);
+ ptr = (char *)kmdaddress.data();
+ memcpy(ptr,kmdaddr,m);
+ item.push_back(Pair("KMDaddress", kmdaddress));
+ a.push_back(item);
}
- ret.push_back(Pair("notaries", a));
- ret.push_back(Pair("numnotaries", n));
}
+ ret.push_back(Pair("notaries", a));
+ ret.push_back(Pair("numnotaries", n));
+ ret.push_back(Pair("height", height));
+ ret.push_back(Pair("timestamp", (uint64_t)timestamp));
return ret;
}
else
{
CBlockIndex *pblockindex = chainActive[heights[i]];
-
+
item.push_back(Pair("t", (int64_t)pblockindex->nTime));
item.push_back(Pair("p", (double)prices[i] / COIN));
a.push_back(item);
return ret;
}
-uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
+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 gettxout(const UniValue& params, bool fHelp)
{
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"2. n (numeric, required) vout value\n"
- "3. includemempool (boolean, optional) Whether to included the mem pool\n"
+ "3. includemempool (boolean, optional) Whether to include the mempool\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
- " \"value\" : x.xxx, (numeric) The transaction value in btc\n"
+ " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"code\", (string) \n"
" \"hex\" : \"hex\", (string) \n"
" \"reqSigs\" : n, (numeric) Number of required signatures\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
- " \"addresses\" : [ (array of string) array of bitcoin addresses\n"
- " \"bitcoinaddress\" (string) bitcoin address\n"
+ " \"addresses\" : [ (array of string) array of Komodo addresses\n"
+ " \"komodoaddress\" (string) Komodo address\n"
" ,...\n"
" ]\n"
" },\n"
- " \"version\" : n, (numeric) The version\n"
- " \"coinbase\" : true|false (boolean) Coinbase or not\n"
+ " \"version\" : n, (numeric) The version\n"
+ " \"coinbase\" : true|false (boolean) Coinbase or not\n"
"}\n"
"\nExamples:\n"
else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
uint64_t interest; int32_t txheight; uint32_t locktime;
- if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue)) != 0 )
+ if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue,(int32_t)pindex->nHeight)) != 0 )
ret.push_back(Pair("interest", ValueFromAmount(interest)));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
return rv;
}
+static UniValue NetworkUpgradeDesc(const Consensus::Params& consensusParams, Consensus::UpgradeIndex idx, int height)
+{
+ UniValue rv(UniValue::VOBJ);
+ auto upgrade = NetworkUpgradeInfo[idx];
+ rv.push_back(Pair("name", upgrade.strName));
+ rv.push_back(Pair("activationheight", consensusParams.vUpgrades[idx].nActivationHeight));
+ switch (NetworkUpgradeState(height, consensusParams, idx)) {
+ case UPGRADE_DISABLED: rv.push_back(Pair("status", "disabled")); break;
+ case UPGRADE_PENDING: rv.push_back(Pair("status", "pending")); break;
+ case UPGRADE_ACTIVE: rv.push_back(Pair("status", "active")); break;
+ }
+ rv.push_back(Pair("info", upgrade.strInfo));
+ return rv;
+}
+
+void NetworkUpgradeDescPushBack(
+ UniValue& networkUpgrades,
+ const Consensus::Params& consensusParams,
+ Consensus::UpgradeIndex idx,
+ int height)
+{
+ // Network upgrades with an activation height of NO_ACTIVATION_HEIGHT are
+ // hidden. This is used when network upgrade implementations are merged
+ // without specifying the activation height.
+ if (consensusParams.vUpgrades[idx].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) {
+ networkUpgrades.push_back(Pair(
+ HexInt(NetworkUpgradeInfo[idx].nBranchId),
+ NetworkUpgradeDesc(consensusParams, idx, height)));
+ }
+}
+
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockchaininfo\n"
"Returns an object containing various state info regarding block chain processing.\n"
+ "\nNote that when the chain tip is at the last block before a network upgrade activation,\n"
+ "consensus.chaintip != consensus.nextblock.\n"
"\nResult:\n"
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" },\n"
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
- " ]\n"
+ " ],\n"
+ " \"upgrades\": { (object) status of network upgrades\n"
+ " \"xxxx\" : { (string) branch ID of the upgrade\n"
+ " \"name\": \"xxxx\", (string) name of upgrade\n"
+ " \"activationheight\": xxxxxx, (numeric) block height of activation\n"
+ " \"status\": \"xxxx\", (string) status of upgrade\n"
+ " \"info\": \"xxxx\", (string) additional information about upgrade\n"
+ " }, ...\n"
+ " },\n"
+ " \"consensus\": { (object) branch IDs of the current and upcoming consensus rules\n"
+ " \"chaintip\": \"xxxxxxxx\", (string) branch ID used to validate the current chain tip\n"
+ " \"nextblock\": \"xxxxxxxx\" (string) branch ID that the next block will be validated under\n"
+ " }\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
ZCIncrementalMerkleTree tree;
pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree);
+ #ifdef __APPLE__
+ obj.push_back(Pair("commitments", (uint64_t)tree.size()));
+ #else
obj.push_back(Pair("commitments", tree.size()));
+ #endif
- const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
+ UniValue valuePools(UniValue::VARR);
+ valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none));
+ obj.push_back(Pair("valuePools", valuePools));
+
+ const Consensus::Params& consensusParams = Params().GetConsensus();
UniValue softforks(UniValue::VARR);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
obj.push_back(Pair("softforks", softforks));
+ UniValue upgrades(UniValue::VOBJ);
+ for (int i = Consensus::UPGRADE_OVERWINTER; i < Consensus::MAX_NETWORK_UPGRADES; i++) {
+ NetworkUpgradeDescPushBack(upgrades, consensusParams, Consensus::UpgradeIndex(i), tip->nHeight);
+ }
+ obj.push_back(Pair("upgrades", upgrades));
+
+ UniValue consensus(UniValue::VOBJ);
+ consensus.push_back(Pair("chaintip", HexInt(CurrentEpochBranchId(tip->nHeight, consensusParams))));
+ consensus.push_back(Pair("nextblock", HexInt(CurrentEpochBranchId(tip->nHeight + 1, consensusParams))));
+ obj.push_back(Pair("consensus", consensus));
+
if (fPruneMode)
{
CBlockIndex *block = chainActive.Tip();
/* Construct the output array. */
UniValue res(UniValue::VARR); const CBlockIndex *forked;
BOOST_FOREACH(const CBlockIndex* block, setTips)
- {
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("height", block->nHeight));
- obj.push_back(Pair("hash", block->phashBlock->GetHex()));
- forked = chainActive.FindFork(block);
- if ( forked != 0 )
+ BOOST_FOREACH(const CBlockIndex* block, setTips)
{
- const int branchLen = block->nHeight - forked->nHeight;
- obj.push_back(Pair("branchlen", branchLen));
-
- string status;
- if (chainActive.Contains(block)) {
- // This block is part of the currently active chain.
- status = "active";
- } else if (block->nStatus & BLOCK_FAILED_MASK) {
- // This block or one of its ancestors is invalid.
- status = "invalid";
- } else if (block->nChainTx == 0) {
- // This block cannot be connected because full block data for it or one of its parents is missing.
- status = "headers-only";
- } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
- // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
- status = "valid-fork";
- } else if (block->IsValid(BLOCK_VALID_TREE)) {
- // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
- status = "valid-headers";
- } else {
- // No clue.
- status = "unknown";
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("height", block->nHeight));
+ obj.push_back(Pair("hash", block->phashBlock->GetHex()));
+ forked = chainActive.FindFork(block);
+ if ( forked != 0 )
+ {
+ const int branchLen = block->nHeight - forked->nHeight;
+ obj.push_back(Pair("branchlen", branchLen));
+
+ string status;
+ if (chainActive.Contains(block)) {
+ // This block is part of the currently active chain.
+ status = "active";
+ } else if (block->nStatus & BLOCK_FAILED_MASK) {
+ // This block or one of its ancestors is invalid.
+ status = "invalid";
+ } else if (block->nChainTx == 0) {
+ // This block cannot be connected because full block data for it or one of its parents is missing.
+ status = "headers-only";
+ } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
+ // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
+ status = "valid-fork";
+ } else if (block->IsValid(BLOCK_VALID_TREE)) {
+ // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
+ status = "valid-headers";
+ } else {
+ // No clue.
+ status = "unknown";
+ }
+ obj.push_back(Pair("status", status));
}
- obj.push_back(Pair("status", status));
+ res.push_back(obj);
}
- res.push_back(obj);
- }
return res;
}