Browse Source

attempt at daily snapshot

jl777
blackjok3r 5 years ago
parent
commit
ed6fd7e8c6
  1. 2
      src/cc/CCPayments.h
  2. 2
      src/cc/hempcoin_notes.txt
  3. 86
      src/cc/payments.cpp
  4. 1
      src/komodo_defs.h
  5. 107
      src/main.cpp
  6. 13
      src/rpc/server.cpp
  7. 1
      src/rpc/server.h
  8. 89
      src/txdb.cpp
  9. 2
      src/txdb.h
  10. 13
      src/wallet/rpcwallet.cpp

2
src/cc/CCPayments.h

@ -20,6 +20,7 @@
#include "CCinclude.h"
#define PAYMENTS_TXFEE 10000
bool komodo_snapshot2(std::map <std::string, CAmount> &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);

2
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

86
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<uint256> 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<n-2; i++)
txidoprets.push_back(payments_juint256(jitem(params,2+i)));
for (i=0; i<txidoprets.size(); i++)
{
std::vector<uint8_t> 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)

1
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

107
src/main.cpp

@ -642,6 +642,96 @@ UniValue komodo_snapshot(int top)
return(result);
}
bool komodo_snapshot2(std::map <std::string, CAmount> &addressAmounts)
{
if ( fAddressIndex && pblocktree != 0 )
{
return pblocktree->Snapshot2(addressAmounts, 0);
}
else return false;
}
int32_t lastSnapShotHeight = 0;
std::vector <std::pair<CAmount, CTxDestination>> 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,&notarized_hash,&notarized_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 <std::string, int64_t> 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;
}

13
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 },

1
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);

89
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 <std::pair<CAmount, std::string>> &vaddr, UniValue *ret)
bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &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<CDBIterator> iter(NewIterator());
std::map <std::string, CAmount> addressAmounts;
//std::map <std::string, CAmount> 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;
}
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
if (ignored != ignoredMap.end())
{
fprintf(stderr,"ignoring %s\n", address.c_str());
ignoredAddresses++;
continue;
}
if ( nValue > dustthreshold )
std::map <std::string, CAmount>::iterator pos = addressAmounts.find(address);
if ( pos == addressAmounts.end() )
{
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
if (ignored != ignoredMap.end())
{
fprintf(stderr,"ignoring %s\n", address.c_str());
ignoredAddresses++;
continue;
}
std::map <std::string, CAmount>::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());
// 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<std::string, CAmount> element : addressAmounts)
vaddr.push_back( make_pair(element.second, element.first) );
std::sort(vaddr.rbegin(), vaddr.rend());
int topN = 0;
for (std::vector<std::pair<CAmount, std::string>>::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 <std::pair<CAmount, std::string>> vaddr;
//std::vector <std::vector <std::pair<CAmount, CScript>>> tokenids;
std::map <std::string, CAmount> 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<std::string, CAmount> element : addressAmounts)
vaddr.push_back( make_pair(element.second, element.first) );
std::sort(vaddr.rbegin(), vaddr.rend());
int topN = 0;
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it)
{
UniValue obj(UniValue::VOBJ);

2
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 <std::pair<CAmount, std::string>> &vaddr, UniValue *ret);
bool Snapshot2(std::map <std::string, CAmount> &addressAmounts, UniValue *ret);
};
#endif // BITCOIN_TXDB_H

13
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;

Loading…
Cancel
Save