From ed6fd7e8c611aab49250a1aa95c03a056102342f Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sat, 27 Apr 2019 02:21:40 +0800 Subject: [PATCH] attempt at daily snapshot --- src/cc/CCPayments.h | 2 + src/cc/hempcoin_notes.txt | 2 +- src/cc/payments.cpp | 86 +++++++----------------------- src/komodo_defs.h | 1 + src/main.cpp | 107 +++++++++++++++++++++++++++++++++++++- src/rpc/server.cpp | 13 ++--- src/rpc/server.h | 1 + src/txdb.cpp | 89 +++++++++++++++---------------- src/txdb.h | 2 +- src/wallet/rpcwallet.cpp | 13 +++++ 10 files changed, 190 insertions(+), 126 deletions(-) diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index 247a0f2ec..6eeb7bcb3 100644 --- a/src/cc/CCPayments.h +++ b/src/cc/CCPayments.h @@ -20,6 +20,7 @@ #include "CCinclude.h" #define PAYMENTS_TXFEE 10000 +bool komodo_snapshot2(std::map &addressAmounts); bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); @@ -28,6 +29,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr); +UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr); diff --git a/src/cc/hempcoin_notes.txt b/src/cc/hempcoin_notes.txt index f8003ac95..2fd72c897 100644 --- a/src/cc/hempcoin_notes.txt +++ b/src/cc/hempcoin_notes.txt @@ -56,7 +56,7 @@ get the payment fund scriptpubkey hex from vout 0: (the split it at OP_CHECKCRYP put the second half into an OP_RETURN: (the remaining part of the the above scriptpubkey) eg. ./komodo-cli -ac_name=TESTHC opreturn_burn 1 2a0401f00101246a22f046337db779358deaa69b9af053e27d85cb8e8e48b0b13805c084b04f87be6577ee75 opret_burn takes any burn amount and arbitrary hex string. (RPC works, but may have bugs, likely use this for LABS too with some fixes) - this gives a raw hex. Decode it and check the OP_RETURN is right before sending (using this RPC currently adds 3 extra bytes to the front (6a2d2c), which is truncated later on, this should be fixed if possible before making any real chains as its consensus code. Need to try diffrent methods to decode the hex correctly.) + this gives a raw hex. Decode it and check the OP_RETURN is right before sending. -earlytxid=810bd62fb8353fad20267ff2050684b8829affa3edf6b366633931530791dfce restart the chain with earlytxid param before height 100 on all nodes (if not using -testnode=1) ./komodod -ac_name=TESTHC -ac_supply=1000000 -ac_reward=100000000000 -ac_cc=2 -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 -ac_founders=150 -ac_blocktime=20 -ac_nk=96,5 -earlytxid=810bd62fb8353fad20267ff2050684b8829affa3edf6b366633931530791dfce diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 7dc8cb1b6..6f6ae1a84 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,6 +16,18 @@ #include "CCPayments.h" /* +payments airdrop: + - extra RPC to merge all payments inputs to a single utxo, this must be called first and be confirmed before payments release, + or tx will be too big, we can check add payments inputs is only 1 input, at RPC and in validation very early on. + - do getsnapshot2 every 1440 blocks and save the result into some global sorted vector or DB? + -this allows any address balance to be calculated by only iterating each 1439 blocks maximum. + - calculate scriptpubkey to pay from each address, set allocations from balance of each address. allocation = balance? + +payments airdrop paying a token: ( maybe this is more reasonable speed wise? ) + - tokenid, top number of tokens to pay, list of pubkeys to exclude as optional param + - add vector of tokenids to getsnapshot2 - then sort each tokenid by balance. + put the pubkey to pay to as scriptpubkey in the saved vector. + 0) txidopret <- allocation, scriptPubKey, opret 1) create <- locked_blocks, minrelease, list of txidopret @@ -781,76 +793,14 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr) return(result); } +extern bool komodo_dailysnapshot(int32_t height); + UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) { - // need to code: exclude list of tokenid, dust threshold, maxpayees, excluded pubkeys[] - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::vector txidoprets; uint256 hashBlock; int32_t i,n,numoprets=0,lockedblocks,minrelease; std::string rawtx; int64_t totalallocations = 0; - cJSON *params = payments_reparse(&n,jsonstr); - if ( params != 0 && n >= 4 ) - { - lockedblocks = juint(jitem(params,0),0); - minrelease = juint(jitem(params,1),0); - if ( lockedblocks < 0 || minrelease < 0 ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","negative parameter")); - if ( params != 0 ) - free_json(params); - return(result); - } - for (i=0; i scriptPubKey,opret; int64_t allocation; - if ( myGetTransaction(txidoprets[i],tx,hashBlock) != 0 && tx.vout.size() > 1 && DecodePaymentsTxidOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) - { - totalallocations += allocation; - if ( opret.size() > 0 ) - numoprets++; - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","invalid txidopret")); - result.push_back(Pair("txid",txidoprets[i].GetHex())); - result.push_back(Pair("txi",(int64_t)i)); - if ( params != 0 ) - free_json(params); - return(result); - } - } - if ( numoprets > 1 ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","too many opreturns")); - result.push_back(Pair("numoprets",(int64_t)numoprets)); - if ( params != 0 ) - free_json(params); - return(result); - } - mypk = pubkey2pk(Mypubkey()); - Paymentspk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 ) - { - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsOpRet(lockedblocks,minrelease,totalallocations,txidoprets)); - if ( params != 0 ) - free_json(params); - return(payments_rawtxresult(result,rawtx,1)); - } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","not enough normal funds")); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","parameters error")); - } - if ( params != 0 ) - free_json(params); - return(result); + uint64_t start = time(NULL); + komodo_dailysnapshot(chainActive.Height()); + //CScript scriptPubKey = GetScriptForDestination(dest); + return(time(NULL)-start); } UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 2efe5efa2..a9df99c0e 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -20,6 +20,7 @@ #define ASSETCHAINS_MINHEIGHT 128 #define ASSETCHAINS_MAX_ERAS 3 #define KOMODO_ELECTION_GAP 2000 +#define KOMODO_SNAPSHOT_INTERVAL 1440 // 1440 is approx 1 day. Maybe this can be -ac param to allow for diffrent block times etc.? #define ROUNDROBIN_DELAY 61 #define KOMODO_ASSETCHAIN_MAXLEN 65 #define KOMODO_LIMITED_NETWORKSIZE 4 diff --git a/src/main.cpp b/src/main.cpp index 2e0102b8b..f4511c284 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -642,6 +642,96 @@ UniValue komodo_snapshot(int top) return(result); } +bool komodo_snapshot2(std::map &addressAmounts) +{ + if ( fAddressIndex && pblocktree != 0 ) + { + return pblocktree->Snapshot2(addressAmounts, 0); + } + else return false; +} + +int32_t lastSnapShotHeight = 0; +std::vector > vAddressSnapshot; + +bool komodo_dailysnapshot(int32_t height) +{ + uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,undo_height; + notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); + if ( notarized_height > height-100 ) + { + // notarized height is higher than 100 blocks before this height, so snapshot the notarized height. + undo_height = notarized_height; + } + else + { + //snapshot 100 blocks ago. Could still be reorged but very unlikley and expensive to carry out constantly. + undo_height = height-100; + } + fprintf(stderr, "doing snapshot for height.%i lastSnapShotHeight.%i\n", undo_height, lastSnapShotHeight); + // if we already did this height dont bother doing it again, this is just a reorg. The actual snapshot height cannot be reorged. + if ( undo_height == lastSnapShotHeight ) + return true; + std::map addressAmounts; + if ( !komodo_snapshot2(addressAmounts) ) + return false; + + // undo blocks in reverse order + for (int32_t n = height; n > undo_height; n--) + { + //fprintf(stderr, "undoing block.%i\n",n); + CBlockIndex *pindex; CBlock block; + if ( (pindex= komodo_chainactive(n)) == 0 || komodo_blockload(block, pindex) != 0 ) + return false; + // undo transactions in reverse order + for (int32_t i = block.vtx.size() - 1; i >= 0; i--) + { + const CTransaction &tx = block.vtx[i]; + uint256 hash = tx.GetHash(); + CTxDestination vDest; + //fprintf(stderr, "undong tx.%s\n",hash.GetHex().c_str()); + // loop vouts reverse order + for (unsigned int k = tx.vout.size(); k-- > 0;) + { + const CTxOut &out = tx.vout[k]; + //fprintf(stderr, "scriptpubkey.%s\n",out.scriptPubKey.ToString().c_str() ); + if ( ExtractDestination(out.scriptPubKey, vDest) ) + { + // add outputs to destination + addressAmounts[CBitcoinAddress(vDest).ToString()] += out.nValue; + //fprintf(stderr, "address.%s addcoins.%li\n",CBitcoinAddress(vDest).ToString().c_str(), out.nValue); + } + } + // loop vins in reverse order, get prevout and remove the balance from its destination + for (unsigned int j = tx.vin.size(); j-- > 0;) + { + uint256 blockhash; CTransaction txin; + if ( !tx.IsCoinImport() && !tx.IsCoinBase() && GetTransaction(tx.vin[j].prevout.hash,txin,blockhash,false) ) // myGetTransaction! + { + int vout = tx.vin[j].prevout.n; + if ( ExtractDestination(txin.vout[vout].scriptPubKey, vDest) ) + { + // remove outputs from destination + //fprintf(stderr, "address.%s removecoins.%li\n",CBitcoinAddress(vDest).ToString().c_str(), txin.vout[vout].nValue); + addressAmounts[CBitcoinAddress(vDest).ToString()] -= txin.vout[vout].nValue; + } + } + } + } + } + vAddressSnapshot.clear(); // clear existing snapshot + // convert address string to destination for easier conversion to what ever is required, eg, scriptPubKey. + for ( auto element : addressAmounts) + vAddressSnapshot.push_back(make_pair(element.second, DecodeDestination(element.first))); + // sort the vector by amount, highest at top. + std::sort(vAddressSnapshot.rbegin(), vAddressSnapshot.rend()); + // include only top 5000 address. + if ( vAddressSnapshot.size() > 5000 ) vAddressSnapshot.resize(5000); + lastSnapShotHeight = undo_height; + fprintf(stderr, "vAddressSnapshot.size.%li\n", vAddressSnapshot.size()); + return true; +} + ////////////////////////////////////////////////////////////////////////////// // // mapOrphanTransactions @@ -3096,7 +3186,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex uint160 addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr); // undo spending activity addressIndex.push_back(make_pair(CAddressIndexKey(keyType, addrHash, pindex->GetHeight(), i, hash, j, true), prevout.nValue * -1)); - // restore unspent index addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(keyType, addrHash, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); } @@ -4156,6 +4245,13 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * komodo_pricesupdate(pindexNew->GetHeight(),pblock); if ( ASSETCHAINS_SAPLING <= 0 && pindexNew->nTime > KOMODO_SAPLING_ACTIVATION - 24*3600 ) komodo_activate_sapling(pindexNew); + if ( ASSETCHAINS_CC != 0 && (pindexNew->GetHeight() % KOMODO_SNAPSHOT_INTERVAL) == 0 ) + { + uint64_t start = time(NULL); + if ( !komodo_dailysnapshot(pindexNew->GetHeight()) ) + fprintf(stderr, "daily snapshot failed, please reindex your chain\n"); // maybe force shutdown here? + fprintf(stderr, "snapshot completed in: %lu seconds\n", time(NULL)-start); + } return true; } @@ -6095,7 +6191,14 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth } LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->GetHeight(), nGoodTransactions); - + + if ( ASSETCHAINS_CC != 0 && lastSnapShotHeight == 0 ) + { + int32_t init_SS_height = chainActive.Height() - (chainActive.Height() % KOMODO_SNAPSHOT_INTERVAL); + if ( !komodo_dailysnapshot(init_SS_height) ) + fprintf(stderr, "daily snapshot failed, please reindex your chain\n"); // maybe force shutdown here? + } + return true; } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 79a782c35..7bd5d3419 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -480,12 +480,13 @@ static const CRPCCommand vRPCCommands[] = { "marmara", "marmaralock", &marmara_lock, true }, // Payments - { "payments", "paymentsaddress", &paymentsaddress, true }, - { "payments", "paymentstxidopret", &payments_txidopret, true }, - { "payments", "paymentscreate", &payments_create, true }, - { "payments", "paymentslist", &payments_list, true }, - { "payments", "paymentsinfo", &payments_info, true }, - { "payments", "paymentsfund", &payments_fund, true }, + { "payments", "paymentsaddress", &paymentsaddress, true }, + { "payments", "paymentstxidopret", &payments_txidopret, true }, + { "payments", "paymentscreate", &payments_create, true }, + { "payments", "paymentsairdrop", &payments_airdrop, true }, + { "payments", "paymentslist", &payments_list, true }, + { "payments", "paymentsinfo", &payments_info, true }, + { "payments", "paymentsfund", &payments_fund, true }, { "payments", "paymentsrelease", &payments_release, true }, { "CClib", "cclibaddress", &cclibaddress, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index bcbe644a3..cf6e4c254 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -287,6 +287,7 @@ extern UniValue payments_release(const UniValue& params, bool fHelp); extern UniValue payments_fund(const UniValue& params, bool fHelp); extern UniValue payments_txidopret(const UniValue& params, bool fHelp); extern UniValue payments_create(const UniValue& params, bool fHelp); +extern UniValue payments_airdrop(const UniValue& params, bool fHelp); extern UniValue payments_info(const UniValue& params, bool fHelp); extern UniValue payments_list(const UniValue& params, bool fHelp); diff --git a/src/txdb.cpp b/src/txdb.cpp index 4c9ea31ca..a7415834c 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -458,13 +458,13 @@ uint32_t komodo_segid32(char *coinaddr); {"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} \ }; -int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector > &vaddr, UniValue *ret) +bool CBlockTreeDB::Snapshot2(std::map &addressAmounts, UniValue *ret) { int64_t total = 0; int64_t totalAddresses = 0; std::string address; int64_t utxos = 0; int64_t ignoredAddresses = 0, cryptoConditionsUTXOs = 0, cryptoConditionsTotals = 0; DECLARE_IGNORELIST boost::scoped_ptr iter(NewIterator()); - std::map addressAmounts; + //std::map addressAmounts; for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { boost::this_thread::interruption_point(); @@ -486,40 +486,39 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector { cryptoConditionsUTXOs++; cryptoConditionsTotals += nValue; + total += nValue; continue; } - if ( nValue > dustthreshold ) + std::map ::iterator ignored = ignoredMap.find(address); + if (ignored != ignoredMap.end()) { - std::map ::iterator ignored = ignoredMap.find(address); - if (ignored != ignoredMap.end()) - { - fprintf(stderr,"ignoring %s\n", address.c_str()); - ignoredAddresses++; - continue; - } - std::map ::iterator pos = addressAmounts.find(address); - if ( pos == addressAmounts.end() ) - { - // insert new address + utxo amount - //fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue); - addressAmounts[address] = nValue; - totalAddresses++; - } - else - { - // update unspent tally for this address - //fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue); - addressAmounts[address] += nValue; - } - //fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN); - // total += nValue; - utxos++; - } //else fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str()); + fprintf(stderr,"ignoring %s\n", address.c_str()); + ignoredAddresses++; + continue; + } + std::map ::iterator pos = addressAmounts.find(address); + if ( pos == addressAmounts.end() ) + { + // insert new address + utxo amount + //fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue); + addressAmounts[address] = nValue; + totalAddresses++; + } + else + { + // update unspent tally for this address + //fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue); + addressAmounts[address] += nValue; + } + //fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN); + // total += nValue; + utxos++; + total += nValue; } catch (const std::exception& e) { fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what()); - break; + return false; //break; this means failiure of DB? we need to exit here if so for consensus code! } } } @@ -530,30 +529,18 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector } } //fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses); - for (std::pair element : addressAmounts) - vaddr.push_back( make_pair(element.second, element.first) ); - std::sort(vaddr.rbegin(), vaddr.rend()); - int topN = 0; - for (std::vector>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) - { - total += it->first; - topN++; - // If requested, only show top N addresses in output JSON - if ( top == topN ) - break; - } + // this is for the snapshot RPC, you can skip this by passing a 0 as the last argument. if (ret) { - // Total amount in this snapshot, which is less than circulating supply if top parameter is used - // Use the address_total for a total of all address included when using top parameter. - ret->push_back(make_pair("total", (double) (total+cryptoConditionsTotals)/ COIN )); + // Total circulating supply without CC vouts. + ret->push_back(make_pair("total", (double) (total)/ COIN )); // Average amount in each address of this snapshot ret->push_back(make_pair("average",(double) (total/COIN) / totalAddresses )); // Total number of utxos processed in this snaphot ret->push_back(make_pair("utxos", utxos)); // Total number of addresses in this snaphot - ret->push_back(make_pair("total_addresses", top ? top : totalAddresses )); + ret->push_back(make_pair("total_addresses", totalAddresses )); // Total number of ignored addresses in this snaphot ret->push_back(make_pair("ignored_addresses", ignoredAddresses)); // Total number of crypto condition utxos we skipped @@ -561,22 +548,28 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector // Total value of skipped crypto condition utxos ret->push_back(make_pair("cc_utxo_value", (double) cryptoConditionsTotals / COIN)); // total of all the address's, does not count coins in CC vouts. - ret->push_back(make_pair("address_total", (double) total/ COIN )); + ret->push_back(make_pair("total_includeCCvouts", (double) (total+cryptoConditionsTotals)/ COIN )); // The snapshot finished at this block height ret->push_back(make_pair("ending_height", chainActive.Height())); } - return(topN); + return true; } UniValue CBlockTreeDB::Snapshot(int top) { int topN = 0; std::vector > vaddr; + //std::vector >> tokenids; + std::map addressAmounts; UniValue result(UniValue::VOBJ); UniValue addressesSorted(UniValue::VARR); result.push_back(Pair("start_time", (int) time(NULL))); - if ( Snapshot2(0,top,vaddr,&result) != 0 ) + if ( Snapshot2(addressAmounts,&result) ) { + for (std::pair element : addressAmounts) + vaddr.push_back( make_pair(element.second, element.first) ); + std::sort(vaddr.rbegin(), vaddr.rend()); + int topN = 0; for (std::vector>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) { UniValue obj(UniValue::VOBJ); diff --git a/src/txdb.h b/src/txdb.h index b4c4cd6bd..195f4c183 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -116,7 +116,7 @@ public: bool LoadBlockIndexGuts(); bool blockOnchainActive(const uint256 &hash); UniValue Snapshot(int top); - int32_t Snapshot2(int64_t dustthreshold, int32_t top,std::vector > &vaddr, UniValue *ret); + bool Snapshot2(std::map &addressAmounts, UniValue *ret); }; #endif // BITCOIN_TXDB_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8de0ae773..66c534f11 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5629,6 +5629,19 @@ UniValue payments_create(const UniValue& params, bool fHelp) return(PaymentsCreate(cp,(char *)params[0].get_str().c_str())); } +UniValue payments_airdrop(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; + //if ( fHelp || params.size() != 1 ) + // throw runtime_error("paymentscreate \"[lockedblocks,minamount,%22paytxid0%22,...,%22paytxidN%22]\"\n"); + //if ( ensure_CCrequirements(EVAL_PAYMENTS) < 0 ) + // throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + //const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + //cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsAirdrop(0,(char *)params[0].get_str().c_str())); +} + UniValue payments_info(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C;