]> Git Repo - VerusCoin.git/blobdiff - src/rpcblockchain.cpp
add help doc for KV
[VerusCoin.git] / src / rpcblockchain.cpp
index ebd4a733a1ee63f4daf10e4d96c442b7f5e5a057..8e13fb6662cc692fe1ee06a59407d47cf5e2522f 100644 (file)
@@ -7,12 +7,18 @@
 #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>
 
@@ -50,7 +56,7 @@ double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficul
     int nShiftAmount = (powLimit >> 24) & 0xff;
 
     double dDiff =
-        (double)(powLimit & 0x00ffffff) / 
+        (double)(powLimit & 0x00ffffff) /
         (double)(bits & 0x00ffffff);
 
     while (nShift < nShiftAmount)
@@ -123,6 +129,112 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
     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);
@@ -174,7 +286,7 @@ UniValue getblockcount(const UniValue& params, bool fHelp)
     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"
@@ -309,6 +421,102 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
     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)
@@ -334,6 +542,22 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
     return pblockindex->GetBlockHash().GetHex();
 }
 
+/*uint256 _komodo_getblockhash(int32_t nHeight)
+{
+    uint256 hash;
+    LOCK(cs_main);
+    if ( nHeight >= 0 && nHeight <= chainActive.Height() )
+    {
+        CBlockIndex* pblockindex = chainActive[nHeight];
+        hash = pblockindex->GetBlockHash();
+        int32_t i;
+        for (i=0; i<32; i++)
+            printf("%02x",((uint8_t *)&hash)[i]);
+        printf(" blockhash.%d\n",nHeight);
+    } else memset(&hash,0,sizeof(hash));
+    return(hash);
+}*/
+
 UniValue getblockheader(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
@@ -469,7 +693,7 @@ UniValue getblock(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)
@@ -521,6 +745,520 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
     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[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,uint32_t timestamp);
+char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
+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);
+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\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 )
+    {
+        ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
+        ret.push_back(Pair("currentheight", (int64_t)chainActive.Tip()->nHeight));
+        ret.push_back(Pair("key",params[0].get_str()));
+        ret.push_back(Pair("keylen",keylen));
+        if ( keylen < sizeof(key) )
+        {
+            memcpy(key,params[0].get_str().c_str(),keylen);
+            if ( (valuesize= komodo_kvsearch(&refpubkey,chainActive.Tip()->nHeight,&flags,&height,value,key,keylen)) >= 0 )
+            {
+                std::string val; char *valuestr;
+                val.resize(valuesize);
+                valuestr = (char *)val.data();
+                memcpy(valuestr,value,valuesize);
+                if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
+                    ret.push_back(Pair("owner",refpubkey.GetHex()));
+                ret.push_back(Pair("height",height));
+                duration = ((flags >> 2) + 1) * KOMODO_KVDURATION;
+                ret.push_back(Pair("expiration", (int64_t)(height+duration)));
+                ret.push_back(Pair("flags",(int64_t)flags));
+                ret.push_back(Pair("value",val));
+                ret.push_back(Pair("valuesize",valuesize));
+            } else ret.push_back(Pair("error",(char *)"cant find key"));
+        } else ret.push_back(Pair("error",(char *)"key too big"));
+    } else ret.push_back(Pair("error",(char *)"null key"));
+    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(&notarized_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(&notarisedHeight, &MoM, &notarisationHash, 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)
+{
+    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,timestamp);
+        if ( numnotaries > 0 )
+        {
+            for (i=0; i<n; i++)
+            {
+                if ( minerids[i] >= numnotaries )
+                    tally[128]++;
+                else tally[minerids[i]]++;
+            }
+            for (i=0; i<64; i++)
+            {
+                UniValue item(UniValue::VOBJ); std::string hex,kmdaddress; char *hexstr,kmdaddr[64],*ptr; int32_t m;
+                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("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);
+            }
+            UniValue item(UniValue::VOBJ);
+            item.push_back(Pair("pubkey", (char *)"external miners"));
+            item.push_back(Pair("blocks", tally[128]));
+            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); 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;
+        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 )
+    {
+        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);
+        }
+    }
+    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;
+}
+
+int32_t komodo_pending_withdraws(char *opretstr);
+int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
+extern char CURRENCIES[][8];
+
+UniValue paxpending(const UniValue& params, bool fHelp)
+{
+    UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); char opretbuf[10000*2]; int32_t opretlen,baseid; uint64_t available,deposited,issued,withdrawn,approved,redeemed;
+    if ( fHelp || params.size() != 0 )
+        throw runtime_error("paxpending needs no args\n");
+    LOCK(cs_main);
+    if ( (opretlen= komodo_pending_withdraws(opretbuf)) > 0 )
+        ret.push_back(Pair("withdraws", opretbuf));
+    else ret.push_back(Pair("withdraws", (char *)""));
+    for (baseid=0; baseid<32; baseid++)
+    {
+        UniValue item(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
+        if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,CURRENCIES[baseid]) == 0 )
+        {
+            if ( deposited != 0 || issued != 0 || withdrawn != 0 || approved != 0 || redeemed != 0 )
+            {
+                item.push_back(Pair("available", ValueFromAmount(available)));
+                item.push_back(Pair("deposited", ValueFromAmount(deposited)));
+                item.push_back(Pair("issued", ValueFromAmount(issued)));
+                item.push_back(Pair("withdrawn", ValueFromAmount(withdrawn)));
+                item.push_back(Pair("approved", ValueFromAmount(approved)));
+                item.push_back(Pair("redeemed", ValueFromAmount(redeemed)));
+                obj.push_back(Pair(CURRENCIES[baseid],item));
+                a.push_back(obj);
+            }
+        }
+    }
+    ret.push_back(Pair("fiatstatus", a));
+    return ret;
+}
+
+UniValue paxprice(const UniValue& params, bool fHelp)
+{
+    if ( fHelp || params.size() > 4 || params.size() < 2 )
+        throw runtime_error("paxprice \"base\" \"rel\" height\n");
+    LOCK(cs_main);
+    UniValue ret(UniValue::VOBJ); uint64_t basevolume=0,relvolume,seed;
+    std::string base = params[0].get_str();
+    std::string rel = params[1].get_str();
+    int32_t height;
+    if ( params.size() == 2 )
+        height = chainActive.Tip()->nHeight;
+    else height = atoi(params[2].get_str().c_str());
+    //if ( params.size() == 3 || (basevolume= COIN * atof(params[3].get_str().c_str())) == 0 )
+        basevolume = 100000;
+    relvolume = komodo_paxprice(&seed,height,(char *)base.c_str(),(char *)rel.c_str(),basevolume);
+    ret.push_back(Pair("base", base));
+    ret.push_back(Pair("rel", rel));
+    ret.push_back(Pair("height", height));
+    char seedstr[32];
+    sprintf(seedstr,"%llu",(long long)seed);
+    ret.push_back(Pair("seed", seedstr));
+    if ( height < 0 || height > chainActive.Height() )
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
+    else
+    {
+        CBlockIndex *pblockindex = chainActive[height];
+        if ( pblockindex != 0 )
+            ret.push_back(Pair("timestamp", (int64_t)pblockindex->nTime));
+        if ( basevolume != 0 && relvolume != 0 )
+        {
+            ret.push_back(Pair("price",((double)relvolume / (double)basevolume)));
+            ret.push_back(Pair("invprice",((double)basevolume / (double)relvolume)));
+            ret.push_back(Pair("basevolume",ValueFromAmount(basevolume)));
+            ret.push_back(Pair("relvolume",ValueFromAmount(relvolume)));
+        } else ret.push_back(Pair("error", "overflow or error in one or more of parameters"));
+    }
+    return ret;
+}
+
+UniValue paxprices(const UniValue& params, bool fHelp)
+{
+    if ( fHelp || params.size() != 3 )
+        throw runtime_error("paxprices \"base\" \"rel\" maxsamples\n");
+    LOCK(cs_main);
+    UniValue ret(UniValue::VOBJ); uint64_t relvolume,prices[4096]; uint32_t i,n; int32_t heights[sizeof(prices)/sizeof(*prices)];
+    std::string base = params[0].get_str();
+    std::string rel = params[1].get_str();
+    int32_t maxsamples = atoi(params[2].get_str().c_str());
+    if ( maxsamples < 1 )
+        maxsamples = 1;
+    else if ( maxsamples > sizeof(heights)/sizeof(*heights) )
+        maxsamples = sizeof(heights)/sizeof(*heights);
+    ret.push_back(Pair("base", base));
+    ret.push_back(Pair("rel", rel));
+    n = komodo_paxprices(heights,prices,maxsamples,(char *)base.c_str(),(char *)rel.c_str());
+    UniValue a(UniValue::VARR);
+    for (i=0; i<n; i++)
+    {
+        UniValue item(UniValue::VOBJ);
+        if ( heights[i] < 0 || heights[i] > chainActive.Height() )
+            throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
+        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);
+        }
+    }
+    ret.push_back(Pair("array", a));
+    return ret;
+}
+
+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)
 {
     if (fHelp || params.size() < 2 || params.size() > 3)
@@ -530,7 +1268,7 @@ 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"
@@ -541,8 +1279,8 @@ UniValue gettxout(const UniValue& params, bool fHelp)
             "     \"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 Zcash addresses\n"
-            "        \"zcashaddress\"        (string) Zcash address\n"
+            "     \"addresses\" : [          (array of string) array of Komodo addresses\n"
+            "        \"komodoaddress\"        (string) Komodo address\n"
             "        ,...\n"
             "     ]\n"
             "  },\n"
@@ -589,9 +1327,11 @@ UniValue gettxout(const UniValue& params, bool fHelp)
     ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
     if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
         ret.push_back(Pair("confirmations", 0));
-    else
-        ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
+    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,(int32_t)pindex->nHeight)) != 0 )
+        ret.push_back(Pair("interest", ValueFromAmount(interest)));
     UniValue o(UniValue::VOBJ);
     ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
     ret.push_back(Pair("scriptPubKey", o));
@@ -696,6 +1436,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
         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"
@@ -721,11 +1463,15 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
             "  ],\n"
             "  \"upgrades\": {                (object) status of network upgrades\n"
             "     \"xxxx\" : {                (string) branch ID of the upgrade\n"
-            "        \"name\": \"xxxx\",         (string) name of 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"
+            "        \"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"
@@ -747,7 +1493,11 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
 
     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
 
     CBlockIndex* tip = chainActive.Tip();
     UniValue valuePools(UniValue::VARR);
@@ -767,6 +1517,11 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
     }
     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();
@@ -836,7 +1591,9 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
         setTips.insert(item.second);
     BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
     {
-        const CBlockIndex* pprev = item.second->pprev;
+        const CBlockIndex* pprev=0;
+        if ( item.second != 0 )
+            pprev = item.second->pprev;
         if (pprev)
             setTips.erase(pprev);
     }
@@ -845,40 +1602,43 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
     setTips.insert(chainActive.Tip());
 
     /* Construct the output array.  */
-    UniValue res(UniValue::VARR);
+    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()));
-
-        const int branchLen = block->nHeight - chainActive.FindFork(block)->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";
+    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 )
+            {
+                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));
+            }
+            res.push_back(obj);
         }
-        obj.push_back(Pair("status", status));
-
-        res.push_back(obj);
-    }
 
     return res;
 }
This page took 0.073486 seconds and 4 git commands to generate.