#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 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);
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"
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 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)
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[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(¬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)
+{
+ 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)
"\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"
" \"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"
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));
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"
" \"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"
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);
}
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();
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);
}
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;
}