Merge pull request #1390 from jl777/jl777

sync with jl777
This commit is contained in:
jl777
2019-04-10 19:46:40 -11:00
committed by GitHub
20 changed files with 547 additions and 380 deletions

View File

@@ -16,19 +16,72 @@
#include "CCPegs.h"
/*
Pegs CC builds on top of CCOPRET modes which will create pricefeeds in the coinbase.
pegs CC is able to create a coin backed (by any supported coin with gateways CC deposits) and pegged to any synthetic price that is able to be calculated based on prices CC
flag&1: BTC/USD 4966.1400, BTC/GBP 3770.0402, BTC/EUR 4416.8452 GBPUSD 1.317264, EURUSD 1.124364 EURGBP 0.853560
flag&2: (BGN 1.7462) (NZD 1.4771) (ILS 3.6258) (RUB 65.3700) (CAD 1.3320) (PHP 52.4160) (CHF 0.9995) (AUD 1.4122) (JPY 111.3660) (TRY 5.5483) (HKD 7.8498) (MYR 4.0816) (HRK 6.6337) (CZK 22.9937) (IDR 14220.0000) (DKK 6.6648) (NOK 8.6111) (HUF 287.2142) (GBP 0.7678) (MXN 19.1046) (THB 31.7500) (ISK 122.4107) (ZAR 14.1300) (BRL 3.8604) (SGD 1.3551) (PLN 3.8350) (INR 68.7531) (KRW 1136.3839) (RON 4.2516) (CNY 6.7200) (SEK 9.3230) (EUR 0.8928) (2019-04-02)
flag&4: (KMD 0.00025110) (ETH 0.03357500) (LTC 0.01642400) (BCHABC 0.05167400) (XMR 0.01398800) (IOTA 0.00007217) (DASH 0.02552600) (XEM 0.00001459) (ZEC 0.01440500) (WAVES 0.00062170) (RVN 0.00001215) (LSK 0.00041130) (DCR 0.00496000) (BTS 0.00001444) (ICX 0.00008750) (HOT 0.00000027) (STEEM 0.00010070) (ENJ 0.00003221) (STRAT 0.00022790) errs.0
First, the prices CC needs to be understood, so the extensive comments at the top of ~/src/cc/prices.cpp needs to be understood.
The second aspect is the ability to import coins, as used by the crosschain burn/import and the -ac_import chains.
<one hour later...>
OK, now we are ready to describe the pegs CC. Let us imagine an -ac_import sidechain with KMD gateways CC. Now we have each native coin fungible with the real KMD via the gateways deposit/withdraw mechanism. Let us start with that and make a pegged and backed USD chain.
<alternatively we can start from a CC enabled chain with external value>
Here the native coin is KMD, but we want USD, so there needs to be a way to convert the KMD amounts into USD amounts. Something like "KMDBTC, BTCUSD, *, 1" which is the prices CC syntax to calculate KMD/USD, which is exactly what we need. So now we can assume that we have a block by block usable KMD/USD price. implementationwise, there can be an -ac option like -ac_peg="KMDBTC, BTCUSD, *, 1" and in conjunction with -ac_import=KMD gateways CC sidechain, we now have a chain where deposit of KMD issues the correct USD coins and redeem of USD coins releases the correct number of KMD coins.
Are we done yet?
Not quite, as the prices of KMD will be quite volatile relative to USD, which is good during bull markets, not so happy during bear markets. There are 2 halves to this problem, how to deal with massive price increase (easy to solve), how to solve 90% price drop (a lot harder).
In order to solve both, what is needed is an "account" based tracking which updates based on both price change, coins issued, payments made. So let us create an account that is based on a specific pubkey, where all relevant deposits, issuances, withdraws are tracked via appropriate vin/vout markers.
Let us modify the USD chain above so that only 80% of the possible USD is issued and 20% held in reserve. This 80% should be at least some easily changeable #define, or even an -ac parameter. We want the issued coins to be released without any encumberances, but the residual 20% value is still controlled (owned) but the depositor. This account has the amount of KMD deposited and USD issued. At the moment of deposit, there will still be 20% equity left. Let us start with 1000 KMD deposit, $1.5 per KMD -> 800 KMD converted to 1200 USD into depositor pubkey and the account of (1000 KMD, -1200 USD) = 200 KMD or $300 equity.
Now it becomes easy for the bull market case, which is to allow (for a fee like 1%) issuance of more USD as the equity increases, so let us imagine KMD at $10:
(1000 KMD, -1200 USD, 200KMD reserve) -> $2000 equity, issue 80% -> $1600 using 160 KMD
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve)
we have $2800 USD in circulation, 40 KMD reserve left against $10000 marketcap of the original deposit. It it easy to see that there are never any problems with lack of KMD to redeem the issued USD in a world where prices only go up. Total USD issuance can be limited by using a decentralized account tracking based on each deposit.
What is evident though is that with the constantly changing price and the various times that all the various deposits issue USD, the global reserves are something that will be hard to predict and in fact needs to be specifically tracked. Let us combine all accounts exposure in to a global reserves factor. This factor will control various max/min/ allowed and fee percentages.
Now we are prepared to handle the price goes down scenario. We can rely on the global equity/reserve ratio to be changing relatively slowly as the reference price is the smooted trustless oracles price. This means there will be enough blocks to adjust the global reserves percentage. What we need to do is liquidate specific positions that have the least reserves.
What does liquidation mean? It means a specific account will be purchased at below its current value and the KMD withdrawn. Let us assume the price drops to $5:
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve) 1000 KMD with 2800 USD issued so $2200 reserves. Let us assume it can be liquidated at a 10% discount, so for $2000 in addition to the $2800, the 5000 KMD is able to be withdrawn. This removes 4800 USD coins for 1000 KMD, which is a very low reserve amount of 4%. If a low reserve amount is removed from the system, then the global reserve amount must be improved.
In addition to the global reserves calculation, there needs to be a trigger percentage that enables positions to be liquidated. We also want to liquidate the worst positions, so in addition to the trigger percentage, there should be a liquidation threshold, and the liquidator would need to find 3 or more better positions that are beyond the liquidation threshold, to be able to liquidate. This will get us to at most 3 accounts that could be liquidated but are not able to, so some method to allow those to also be liquidated. The liquidating nodes are making instant profits, so they should be expected to do whatever blockchain scanning and proving to make things easy for the rest of the nodes.
One last issue is the normal redemption case where we are not liquidating. In this case, it should be done at the current marketprice, should improve the global reserves metrics and not cause anybody whose position was modified to have cause for complaint. Ideally, there would be an account that has the identical to the global reserve percentage and also at the same price as current marketprice, but this is not realistic, so we need to identify classes of accounts and consider which ones can be fully or partially liquidated to satisfy the constraints.
looking at our example account:
(1000 KMD, -1200 USD, 200KMD reserve, -160KMD, issue $1600 USD, 40 KMD reserve)
Funds deposited into CC address for a specific peg would then be used to fund the bid/ask as the pricefeed changes the price. Profits/losses would accumulate in the associated address.
what sort of non-liquidation withdraw would be acceptable? if the base amount 1000 KMD is reduced along with USD owed, then the reserve status will go up for the account. but that would seem to allow extra USD to be able to be issued. there should be no disadvantage from funding a withdraw, but also not any large advantage. it needs to be a neutral event....
In the event funds exceed a specified level, it can be spent into a collection address. The idea is that the collection address can further be used for revshares.
One solution is to allow for the chance for any account to be liquidated, but the equity compensated for with a premium based on the account reserves. So in the above case, a premium of 5% on the 40KMD reserve is paid to liquidate its account. Instead of 5% premium, a lower 1% can be done if based on the MAX(correlated[daywindow],smoothed) so we get something that is close to the current marketprice. To prevent people taking advantage of the slowness of the smoothed price to adjust, there would need to be a one day delay in the withdraw.
From a practical sense, it seems a day is a long time, so maybe having a way to pay a premium like 10%, or wait a day to get the MAX(correlated[daywindow],smoothed) price. This price "jumping" might also be taken advantage of in the deposit side, so similar to prices CC it seems good to have the MAX(correlated[daywindow],smoothed) method.
Now, we have a decentralized mechanism to handle the price going lower! Combined with the fully decentralized method new USD coins are issued, makes this argubably the first decentralized blockchain that is both backed and pegged. There is the reliance on the gateways CC multisig signers, so there is a fundamental federated trust for chains without intrinsic value.
*/
Also, notice that the flexibly syntax of prices CC allows to define pegs easily for virtually any type of synthetic, and all the ECB fiats can easily get a backed and pegged coin.
Let us now consider how to enforce a peg onto a specific gateways CC token. If this can also be achieved, then a full DEX for all the different gateways CC supported coins can be created onto a single fiat denominated chain.
I think just having a pegscreate rpc call that binds an existing gateways create to a price CC syntax price will be almost enough to support this. Let us assume a USD stablechain and we have a BTC token, then pegscreate <btc gateways txid> "BTCUSD, 1"
that will specify using the BTCUSD price, so now we need to create a <txid> based way to do tokenbid/tokenask. For a <txid> based price, the smoothed price is substituted.
There is the issue of the one day delay, so it might make sense to allow specific bid/ask to be based on some simple combinations of the three possible prices. it might even be possible to go a bit overboard and make a forth like syntax to define the dynamic price for a bid, which maybe at times wont be valid, like it is only valid if the three prices are within 1% of each other. But all that seems over complex and for initial release it can just use the mined, correlated or smoothed price, with some specified percentage offset
Implementation notes:
make sure that fees and markers that can be sent to an unspendable address are sent to: RNdqHx26GWy9bk8MtmH1UiXjQcXE4RKK2P, this is the address for BOTS
*/
// start of consensus code

View File

@@ -22,25 +22,127 @@ CBOPRET creates trustless oracles, which can be used for making a synthetic cash
0.5% fee based on betamount, NOT leveraged betamount!!
0.1% collected by price basis determinant
0.2% collected by rekt tx
At the simplest, prices CC allows to make leveraged cash settled bets on long and short BTCUSD:
BTCUSD, 1 with positive leverage parameter up to 777
BTCUSD, 1 with negative leverage parameter up to -777
PricesBet -> +/-leverage, amount, synthetic -> opreturn includes current price
funds are locked into 1of2 global CC address
for first day, long basis is MAX(correlated,smoothed), short is MIN()
reference price is the smoothed of the previous block
if synthetic value + amount goes negative, then anybody can rekt it to collect a rektfee, proof of rekt must be included to show cost basis, rekt price
original creator can liquidate at anytime and collect (synthetic value + amount) from globalfund
0.5% of bet -> globalfund
PricesStatus -> bettxid maxsamples returns initial params, cost basis, amount left, rekt:true/false, rektheight, initial synthetic price, current synthetic price, net gain
These specific limits of 0.5%, 0.1%, 0.2%, 777 should be able to be changed based on #define
PricesRekt -> bettxid height -> 0.1% to miner, rest to global CC
Another configuration is to send the 0.4% (or 0.2%) fees to a fee collection address (this is not currently implemented, but would be needed for systems that dont use -ac_perc to collect a global override)
PricesClose -> bettxid returns (synthetic value + amount)
The definition of the synthetic instrument that is being tracked is actually defined with a forth type of syntax and is quite flexible to allow unlimited combinations and weights, but that is an independent aspect and will be covered later.
PricesList -> all bettxid -> list [bettxid, netgain]
Let us discuss the simplest synthetic case of a long or short of BTCUSD (or any other direct pricepoint from the trustless oracle). If you look at the charts, you will see the blue line that is direct from the miners (and therefore cant be directly used). The orange line is the 51% correlated price that is deterministically random selected from the prior 24 hours. And finally the green line which is simply the average value from the priot 24 hours.
We will assume that the orange and green prices are able to be deterministically calculated from the raw coinbase data (blue). The prices rpc is currently working reasonably well and appears to return deterministic prices, however for use in the prices CC, it is often needed to find just a single data point. To that effect there is the temporary function prices_syntheticprice, which uses a bruteforce and totally inefficient way to calculate the correlated and smoothed prices. This inefficient process will need to be changed to a permanent storage of correlated and smoothed prices for each trustless oracle that is updated each block. This will then allow to directly lookup each value for any of the trustless prices. Such speed will indeed be needed to scale up usage of a REKT chain.
Since the mined prices can be manipulated by any miner, combined with the +/-1% tolerance, it would be possible for an external miner to obtain a large hashrate and skew the price +1%, then to -1% to create a 2% price difference, which under high leverage might be able to generate a large profit.
To avoid this precisely controllable biasing, the 51% correlation of past day is used (orange), which makes the price jump around a lot. The green line that sums the prior day is needed to remove this jitter back to the average value. However, this creates a 1.5 day delay to the price movement of the smoothed price compared to the current price. What this means is that if we want to use the green line to settle prices automatically, a trivial way to make money is to bet in the direct that the mined prices are relative to the smoothed prices. Given 1.5 day head start, it wont be any mystery which direction the smoothed line will move in the next 24 hours.
So this makes the smoothed price unusable for settling the bets with. However, we cant use the correlated price either, as it would also allow to make bets when the correlated price picked a significantly lower/higher price than the raw price. The solution is to have a floating basis for the costbasis of the bet. In order to allow finding the right costbasis, for long bets the maximum price between the correlated and smoothed price is needed over the first day after the bet. For short bets, the minimum price is needed.
What this means is that the actual starting price for a bet wont be known for sure when the bet is made, but if the price is relatively stable, there wont be much of a change. If there is a lot of recent volatility, then the starting price will have a high variability. In order to calculate the costbasis, it currently requires many calculations to find the MAX (or MIN) for the first day. Even when this is made to be a lookup, it still requires to issue a transaction to change the state of a bet from a "starting" state to a "in effect" state and this state change is indicated by whether the bettx vout that contains the costbasis utxo is spent or not.
Once a bet goes into effect, then block by block, it is checked by the decentralized set of rekt scanners if it is rekt or not, in this case for double the reward for calculating the cost basis. This fully decentralized mechanism ensures that some node will decide to collect the free money and ensures that the bankroll is growing. To miss a rekt bet and not close it out when it can be is to allow it to survive for another block, which can change it profitability from negative to positive.
Which comes to how profits are calculated. Once the costbasis is locked, then the profit calculation can be made based on the ratio between the costbasis and the current price, multiplied by the leverage. So, if a long position gains 10% at a 10x leverage, then approximately the entire bet amount will be made, ie. a double. Similarily with a short position, a 10% drop in price at 10x leverage will double the bet amount. Since it takes a full day to establish the costbasis, it is not possible to allow changing the costbasis for an existing bet, however it is possible to add funds so that it is less likely to be rekt. The sum of the initial bet and all added funds must be greater than the loss at every block to prevent a position from being rekt. To make it simple to calculate the amount of funds added, another bettx vout is used as a baton. Techniques similar to rogue CC to find where the bettx vout was spent and looking at each such transaction to find the total funds added can be used.
The once that makes the bet is able to add funds or cashout at any block, as long as it isnt rekt. If it is rekt, the bettor is able to collect the rekt fee, so at least that is some consolation, but it is advised to increase the total funding to avoid being rekt. On a cashout all the funds that were bet adjusted by the profits can be collected.
Hopefully the above description makes it clear what the following rpc calls should be doing:
UniValue PricesBet(uint64_t txfee,int64_t amount,int16_t leverage,std::vector<std::string> synthetic)
funds are locked into 1of2 global CC address
for first day, long basis is MAX(correlated,smoothed), short is MIN()
reference price is the smoothed of the previous block
if synthetic value + amount goes negative, then anybody can rekt it to collect a rektfee, proof of rekt must be included to show cost basis, rekt price
original creator can liquidate at anytime and collect (synthetic value + amount) from globalfund
0.5% of bet -> globalfund
UniValue PricesAddFunding(uint64_t txfee,uint256 bettxid,int64_t amount)
add funding to an existing bet, doesnt change the profit calcs but does make the bet less likely to be rekt
UniValue PricesSetcostbasis(uint64_t txfee,uint256 bettxid)
in the first day from the bet, the costbasis can (and usually does) change based on the MAX(correlated,smoothed) for long and MIN() for shorts
to calculate this requires a bit of work, so whatever node is first to get the proper calculation confirmed, gets a 0.1% costbasis fee
UniValue PricesRekt(uint64_t txfee,uint256 bettxid,int32_t rektheight)
similarily, any node can submit a rekt tx and cash in on 0.2% fee if their claim is confirmed
UniValue PricesCashout(uint64_t txfee,uint256 bettxid)
only the actually creator of bet is able to cashout and only if it isnt rekt at that moment
UniValue PricesInfo(uint256 bettxid,int32_t refheight)
all relevant info about a bet
UniValue PricesList()
a list of all pending and completed bets in different lists
*/
Appendix Synthetic position definition language:
Let us start from the familiar BTCUSD nomenclature. this is similar (identical) to forex EURUSD and the equivalent. Notice the price needs two things as it is actually a ratio, ie. BTCUSD is how many USD does 1 BTC get converted to. It can be thought of as the value of BTC/USD, in other words a ratio.
The value of BTC alone, or USD alone, it is actually quite an abstract issue and it can only be approximated. Specific ways of how to do this can be discussed later, for now it is only important to understand that all prices are actually ratios.
And these ratios work as normal algebra does. So a/b * b/c == a/c! You can try this out with BTCUSD and USDJPY -> BTC/USD * USD/JPY -> BTC/JPY or the BTCJPY price
division is the reciprocal, so BTCUSD reciprocated is USDBTC
Without getting into all the possible combinations of things, let us first understand what the language allows. It uses a stack based language, where individual tokens update the state. The final state needs to have an empty stack and it will have a calculated price.
The most important is pushing a specific price onto the stack. All the correlated and smoothed prices are normalized so it has each integer unit equal to 0.00000001, amounts above 100 million are above one, amounts less are below one. 100 million is the unit constant.
In the prices CC synthetic definition language, the symbol that is returned pushes the adjusted price to the stack. The adjustment is selecting between the correlated and smoothed if within a day from the bet creation, or just the smoothed if after a day. You can have a maximum depth of 3, any more than that and it should return an error.
This means there are operations that are possible on 1, 2 and 3 symbols. For 1 symbol, it is easy, the only direct operation is the inverse, which is represented by "!". All items in the language are separated by ","
"BTCUSD, !"
The above is the inverse or USD/BTC, which is another way to short BTCUSD. It is also possible to short the entire synthetic with a negative leverage. The exact results of a -1 leverage and inverse, might not be exact due to the math involved with calculating the profit, but it should generally be similar.
For two symbols, there is a bit more we can do, namely multiply and divide, combined with inverting, however to simplify the language any inverting is required to be done by the ordering of the symbols and usage of multiply or divide. multiply is "*" and divide is "/" the top of the stack (last to be pushed) is the divisor, the one right before the divisor is the numerator.
"BTCUSD, USDJPY, *" <- That will create a BTCJPY synthetic
"BTCEUR, BTCUSD, /" <- That will create a USDEUR synthetic
If you experiment around with this, you will see that given two symbols and the proper order and * or /, you can always create the synthetic that you want, assuming what you want is the cancelling out of the term in common with the two symbols and the resulting ratio is between the two unique terms.
*/
// Now we get to the three symbol operations, which there are 4 of *//, **/, *** and ///
/*
these four operators work on the top of the stack in left to right order as the syntax of the definition lists it, though it is even possible to have the value from an earlier computation on the top of the stack. Ultimately all three will be multiplied together, so a * in a spot means it us used without changing. A / means its inverse will be used.
"KMDBTC, BTCUSD, USDJPY, ***" <- this would create a KMDJPY synthetic. The various location of the / to make an inverse is to orient the raw symbol into the right orientation as the pricefeed is only getting one orientation of the ratio.
So now we have covered all ways to map 1, 2 and 3 values on the top of the stack. A value can be on the top of the stack directly from a symbol, or as the result of some 1, 2 or 3 symbol operation. With a maximum stack depth of 3, it might require some experimentation to get a very complex synthetic to compile. Alternately, a stack deeper than 3 might be the acceptable solution if there are a family of synthetics that need it.
At this point, it is time to describe the weights. It turns out that all above examples are incomplete and the synthetic descriptions are all insufficient and should generate an error. The reason is that the actual synthetic price is the value of the accumulator, which adds up all the weighted prices. In order to assign a weight to a price value on the stack, you simply use a number that is less than 2048.
What such a weight number does, is consume the top of the stack, which also must be at depth of 1 and adds it to the accumulator. This allows combining multiple different synthetics into a meta synthetic, like for an aggregated index that is weighted by marketcap, or whatever other type of ratio trade that is desired.
"BTCUSD, 1000, ETHBTC, BTCUSD, *, 300" -> that creates a dual index of BTCUSD and ETHUSD with a 30% ETH weight
all weight operations consumes the one and only stack element and adds its weight to the accumulator, using this a very large number of terms can be all added together. Using inverses, allows to get the short direction into the equation mixed with longs, but all terms must be positive. If you want to create a spread between two synthetics, you need to create two different synthetics and go long with one and short with another.
"BTCUSD, 1" with leverage -2 and "KMDBTC, BTCUSD, *, 1" with leverage 1 this will setup a +KMDUSD -2 BTCUSD spread when the two are combined, and would be at breakeven when KMDUSD gains 2x more percentage wise than BTC does. anytime KMD gains more, will be positive, if the gains are less, would be negative.
Believe it or not, the string to binary compiler for synthetic description and interpretation of it is less than 200 lines of code.
todo: complete all the above, bet tokens, cross chain prices within cluster These specific limits of 0.5%, 0.1%, 0.2%, 777 should be able to be changed based on #define
Another configuration is to send the 0.4% (or 0.2%) fees to a fee collection scriptPubKey (this is not currently implemented, but would be needed for systems that dont use -ac_perc to collect a global override) this requires adding new vouts
Modification: in the event there is one price in the accumulator and one price on the stack at the end, then it is a (A - B) spread
Monetizations should be sent to: RGsWqwFviaNJSbmgWi6338NL2tKkY7ZqKL
*/
// start of consensus code

View File

@@ -836,16 +836,6 @@ int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block)
int8_t numSN = numStakedNotaries(tmp_pubkeys,staked_era);
UpdateNotaryAddrs(tmp_pubkeys,numSN);
STAKED_ERA = staked_era;
if ( NOTARYADDRS[0][0] != 0 && NOTARY_PUBKEY33[0] != 0 )
{
if ( (IS_STAKED_NOTARY= updateStakedNotary()) > -1 )
{
IS_KOMODO_NOTARY = 0;
if ( MIN_RECV_SATS == -1 )
MIN_RECV_SATS = 100000000;
fprintf(stderr, "Staked Notary Protection Active! NotaryID.%d RADD.%s ERA.%d MIN_TX_VALUE.%lu \n",IS_STAKED_NOTARY,NOTARY_ADDRESS.c_str(),staked_era,MIN_RECV_SATS);
}
}
lastStakedEra = staked_era;
}
}

View File

@@ -1917,33 +1917,37 @@ uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector<int8_t> &Notar
return(total);
}
uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height)
bool GetNotarisationNotaries(uint8_t notarypubkeys[64][33], int8_t &numNN, const std::vector<CTxIn> &vin, std::vector<int8_t> &NotarisationNotaries)
{
std::vector<int8_t> NotarisationNotaries;
uint32_t timestamp = pblock->nTime;
int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0};
numSN = komodo_notaries(notarypubkeys, height, timestamp);
// No point going further, no notaries can be paid.
if ( notarypubkeys[0][0] == 0 )
return(0);
uint8_t *script; int32_t scriptlen;
// Loop over the notarisation and extract the position of the participating notaries in the array of pukeys for this era.
BOOST_FOREACH(const CTxIn& txin, pblock->vtx[1].vin)
if ( notarypubkeys[0][0] == 0 )
return false;
BOOST_FOREACH(const CTxIn& txin, vin)
{
uint256 hash; CTransaction tx1;
if ( GetTransaction(txin.prevout.hash,tx1,hash,false) )
{
for (int8_t i = 0; i < numSN; i++)
for (int8_t i = 0; i < numNN; i++)
{
script = (uint8_t *)&tx1.vout[txin.prevout.n].scriptPubKey[0];
scriptlen = (int32_t)tx1.vout[txin.prevout.n].scriptPubKey.size();
if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,notarypubkeys[i],33) == 0 )
NotarisationNotaries.push_back(i);
}
}
} else return false;
}
return true;
}
uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height)
{
std::vector<int8_t> NotarisationNotaries; uint8_t *script; int32_t scriptlen;
uint64_t timestamp = pblock->nTime;
int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0};
numSN = komodo_notaries(notarypubkeys, height, timestamp);
if ( !GetNotarisationNotaries(notarypubkeys, numSN, pblock->vtx[1].vin, NotarisationNotaries) )
return(0);
// check a notary didnt sign twice (this would be an invalid notarisation later on and cause problems)
std::set<int> checkdupes( NotarisationNotaries.begin(), NotarisationNotaries.end() );
if ( checkdupes.size() != NotarisationNotaries.size() ) {

View File

@@ -80,9 +80,9 @@ extern int32_t VERUS_MIN_STAKEAGE;
extern std::string DONATION_PUBKEY;
extern uint8_t ASSETCHAINS_PRIVATE;
extern int32_t USE_EXTERNAL_PUBKEY;
extern char NOTARYADDRS[64][64];
int tx_height( const uint256 &hash );
extern char NOTARYADDRS[64][36];
extern uint8_t NUM_NOTARIES;
extern std::vector<std::string> vWhiteListAddress;
void komodo_netevent(std::vector<uint8_t> payload);
int32_t komodo_priceind(char *symbol);

View File

@@ -1551,7 +1551,7 @@ void komodo_passport_iteration()
extern std::vector<uint8_t> Mineropret; // opreturn data set by the data gathering code
#define PRICES_MAXCHANGE (COIN / 100) // maximum acceptable change, set at 1%
#define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) // 4 uint32_t unixtimestamp, BTCUSD, BTCGBP and BTCEUR
#define KOMODO_LOCALPRICE_CACHESIZE 7
#define KOMODO_LOCALPRICE_CACHESIZE 13
#define KOMODO_MAXPRICES 2048
#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0)
@@ -1720,18 +1720,33 @@ CScript komodo_mineropret(int32_t nHeight)
The only way komodo_opretvalidate() doesnt return an error is if maxflag is set or it is within tolerance of both the prior block and the local data. The local data validation only happens if it is a recent block and not a block from the past as the local node is only getting the current price data.
*/
// for PRICES: reconsiderblock 002aca768b09dfcf36bd934ab34b23983148b116e12cb0b6e1a3f895d1db63aa
// and
// reconsiderblock 0034cf582018eacc0b4ae001491ce460113514cb1a3f217567ef4a2207de361a
// reconsiderbloc 000abf51c023b64af327c50c1b060797b8cb281c696d30ab92fd002a8b8c9aea
// are needed to sync past initial blocks with different data set
struct komodo_extremeprice
{
uint256 blockhash;
uint32_t pricebits,timestamp;
int32_t height;
int16_t dir,ind;
} ExtremePrice;
void komodo_queuelocalprice(int32_t dir,int32_t height,uint32_t timestamp,uint256 blockhash,int32_t ind,uint32_t pricebits)
{
ExtremePrice.dir = dir;
ExtremePrice.height = height;
ExtremePrice.blockhash = blockhash;
ExtremePrice.ind = ind;
ExtremePrice.timestamp = timestamp;
ExtremePrice.pricebits = pricebits;
}
int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,int32_t nHeight,CScript scriptPubKey)
{
int32_t testchain_exemption = 350;
std::vector<uint8_t> vopret; char maxflags[KOMODO_MAXPRICES]; double btcusd,btcgbp,btceur; uint32_t localbits[KOMODO_MAXPRICES],pricebits[KOMODO_MAXPRICES],prevbits[KOMODO_MAXPRICES],newprice; int32_t i,j,prevtime,maxflag,lag,lag2,lag3,n,errflag,iter; uint32_t now = (uint32_t)time(NULL);
int32_t testchain_exemption = 0;
std::vector<uint8_t> vopret; char maxflags[KOMODO_MAXPRICES]; uint256 bhash; double btcusd,btcgbp,btceur; uint32_t localbits[KOMODO_MAXPRICES],pricebits[KOMODO_MAXPRICES],prevbits[KOMODO_MAXPRICES],newprice; int32_t i,j,prevtime,maxflag,lag,lag2,lag3,n,errflag,iter; uint32_t now;
now = (uint32_t)time(NULL);
if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 )
{
bhash = block->GetHash();
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() >= PRICES_SIZEBIT0 )
{
@@ -1815,7 +1830,10 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i
break;
}
if ( j == KOMODO_LOCALPRICE_CACHESIZE )
{
komodo_queuelocalprice(1,nHeight,block->nTime,bhash,i,prevbits[i]);
break;
}
}
else if ( maxflag < 0 && localbits[i] > prevbits[i] )
{
@@ -1828,7 +1846,10 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i
break;
}
if ( j == KOMODO_LOCALPRICE_CACHESIZE )
{
komodo_queuelocalprice(-1,nHeight,block->nTime,bhash,i,prevbits[i]);
break;
}
}
}
}
@@ -1844,6 +1865,11 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i
}
}
}
if ( bhash == ExtremePrice.blockhash )
{
fprintf(stderr,"approved a previously extreme price based on new data ht.%d vs %u vs %u\n",ExtremePrice.height,ExtremePrice.timestamp,(uint32_t)block->nTime);
memset(&ExtremePrice,0,sizeof(ExtremePrice));
}
return(0);
} else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)Mineropret.size(),(int32_t)scriptPubKey.size(),scriptPubKey[0]);
return(-1);
@@ -2124,7 +2150,7 @@ void komodo_cbopretupdate(int32_t forceflag)
{
static uint32_t lasttime,lastcrypto,lastbtc,pending;
static uint32_t pricebits[4],cryptoprices[KOMODO_MAXPRICES],forexprices[sizeof(Forex)/sizeof(*Forex)];
int32_t size; uint32_t flags=0,now;
int32_t size; uint32_t flags=0,now; CBlockIndex *pindex;
if ( forceflag != 0 && pending != 0 )
{
while ( pending != 0 )
@@ -2135,8 +2161,8 @@ void komodo_cbopretupdate(int32_t forceflag)
now = (uint32_t)time(NULL);
if ( (ASSETCHAINS_CBOPRET & 1) != 0 )
{
if ( komodo_nextheight() > 333 ) // for debug only!
ASSETCHAINS_CBOPRET = 7;
//if ( komodo_nextheight() > 333 ) // for debug only!
// ASSETCHAINS_CBOPRET = 7;
size = komodo_cbopretsize(ASSETCHAINS_CBOPRET);
if ( Mineropret.size() < size )
Mineropret.resize(size);
@@ -2182,6 +2208,16 @@ if ( komodo_nextheight() > 333 ) // for debug only!
if ( (flags & 4) != 0 )
lastcrypto = now;
memcpy(Mineropret.data(),PriceCache[0],size);
if ( ExtremePrice.dir != 0 && ExtremePrice.ind > 0 && ExtremePrice.ind < size/sizeof(uint32_t) && now < ExtremePrice.timestamp+3600 )
{
if ( (ExtremePrice.dir > 0 && PriceCache[0][ExtremePrice.ind] >= ExtremePrice.pricebits) || (ExtremePrice.dir < 0 && PriceCache[0][ExtremePrice.ind] <= ExtremePrice.pricebits) )
{
fprintf(stderr,"future price is close enough to allow approving previously rejected block ind.%d %u vs %u\n",ExtremePrice.ind,PriceCache[0][ExtremePrice.ind],ExtremePrice.pricebits);
if ( (pindex= komodo_blockindex(ExtremePrice.blockhash)) != 0 )
pindex->nStatus &= ~BLOCK_FAILED_MASK;
else fprintf(stderr,"couldnt find block.%s\n",ExtremePrice.blockhash.GetHex().c_str());
}
}
// high volatility still strands nodes so we need to check new prices to approve a stuck block
// scan list of stuck blocks (one?) and auto reconsiderblock if it changed state

View File

@@ -47,12 +47,14 @@ unsigned int WITNESS_CACHE_SIZE = _COINBASE_MATURITY+10;
int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,IS_STAKED_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,STAKED_ERA,KOMODO_CONNECTING = -1,KOMODO_DEALERNODE,KOMODO_EXTRASATOSHI,ASSETCHAINS_FOUNDERS;
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,WHITELIST_ADDRESS,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB;
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,NUM_NOTARIES,ASSETCHAINS_MARMARA;
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB;
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,ASSETCHAINS_MARMARA;
bool VERUS_MINTBLOCKS;
std::vector<uint8_t> Mineropret;
std::vector<std::string> vWhiteListAddress;
char NOTARYADDRS[64][64];
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096],NOTARYADDRS[64][36];
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096];
uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_BEAMPORT,ASSETCHAINS_CODAPORT;
uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT,KOMODO_DPOWCONFS = 1,STAKING_MIN_DIFF;
uint32_t ASSETCHAINS_MAGIC = 2387029918;
@@ -99,7 +101,7 @@ int32_t ASSETCHAINS_OVERWINTER = -1;
uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
int32_t ASSETCHAINS_STAKED;
uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY = 10,MIN_RECV_SATS,ASSETCHAINS_FOUNDERS_REWARD;
uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY = 10,ASSETCHAINS_FOUNDERS_REWARD;
uint32_t KOMODO_INITDONE;
char KMDUSERPASS[8192+512+1],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771;

View File

@@ -1677,8 +1677,6 @@ void komodo_args(char *argv0)
fprintf(stderr, "Cannot be STAKED and KMD notary at the same time!\n");
exit(0);
}
MIN_RECV_SATS = GetArg("-mintxvalue",-1);
WHITELIST_ADDRESS = GetArg("-whitelistaddress","");
memset(ccenables,0,sizeof(ccenables));
memset(disablebits,0,sizeof(disablebits));
if ( GetBoolArg("-gen", false) != 0 )

View File

@@ -1270,9 +1270,6 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState
}
}
extern char NOTARYADDRS[64][36];
extern uint8_t NUM_NOTARIES;
int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only
{
static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64];
@@ -2967,6 +2964,33 @@ void DisconnectNotarisations(const CBlock &block)
}
}
int8_t GetAddressType(const CScript &scriptPubKey, CTxDestination &vDest, txnouttype &txType, vector<vector<unsigned char>> &vSols)
{
int8_t keyType = 0;
// some non-standard types, like time lock coinbases, don't solve, but do extract
if ( (Solver(scriptPubKey, txType, vSols) || ExtractDestination(scriptPubKey, vDest)) )
{
keyType = 1;
if (vDest.which())
{
// if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned
CKeyID kid;
if (CBitcoinAddress(vDest).GetKeyID(kid))
{
vSols.push_back(vector<unsigned char>(kid.begin(), kid.end()));
}
}
else if (txType == TX_SCRIPTHASH)
{
keyType = 2;
}
else if (txType == TX_CRYPTOCONDITION )
{
keyType = 3;
}
}
return keyType;
}
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
@@ -3002,20 +3026,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
vector<vector<unsigned char>> vSols;
CTxDestination vDest;
txnouttype txType = TX_PUBKEYHASH;
int keyType = 1;
if ((Solver(out.scriptPubKey, txType, vSols) || ExtractDestination(out.scriptPubKey, vDest)) && txType != TX_MULTISIG) {
if (vDest.which())
{
CKeyID kid;
if (CBitcoinAddress(vDest).GetKeyID(kid))
{
vSols.push_back(vector<unsigned char>(kid.begin(), kid.end()));
}
}
else if (txType == TX_SCRIPTHASH)
{
keyType = 2;
}
int keyType = GetAddressType(out.scriptPubKey, vDest, txType, vSols);
if ( keyType != 0 )
{
for (auto addr : vSols)
{
uint160 addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr);
@@ -3072,23 +3085,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
vector<vector<unsigned char>> vSols;
CTxDestination vDest;
txnouttype txType = TX_PUBKEYHASH;
int keyType = 1;
// some non-standard types, like time lock coinbases, don't solve, but do extract
if ((Solver(prevout.scriptPubKey, txType, vSols) || ExtractDestination(prevout.scriptPubKey, vDest)))
int keyType = GetAddressType(prevout.scriptPubKey, vDest, txType, vSols);
if ( keyType != 0 )
{
// if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned
if (vDest.which())
{
CKeyID kid;
if (CBitcoinAddress(vDest).GetKeyID(kid))
{
vSols.push_back(vector<unsigned char>(kid.begin(), kid.end()));
}
}
else if (txType == TX_SCRIPTHASH)
{
keyType = 2;
}
for (auto addr : vSols)
{
uint160 addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr);
@@ -3448,8 +3447,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (fAddressIndex || fSpentIndex)
{
for (size_t j = 0; j < tx.vin.size(); j++) {
for (size_t j = 0; j < tx.vin.size(); j++)
{
const CTxIn input = tx.vin[j];
const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
@@ -3457,25 +3456,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CTxDestination vDest;
txnouttype txType = TX_PUBKEYHASH;
uint160 addrHash;
int keyType = 0;
// some non-standard types, like time lock coinbases, don't solve, but do extract
if ((Solver(prevout.scriptPubKey, txType, vSols) || ExtractDestination(prevout.scriptPubKey, vDest)))
int keyType = GetAddressType(prevout.scriptPubKey, vDest, txType, vSols);
if ( keyType != 0 )
{
keyType = 1;
// if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned
if (vDest.which())
{
CKeyID kid;
if (CBitcoinAddress(vDest).GetKeyID(kid))
{
vSols.push_back(vector<unsigned char>(kid.begin(), kid.end()));
}
}
else if (txType == TX_SCRIPTHASH)
{
keyType = 2;
}
for (auto addr : vSols)
{
addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr);
@@ -3485,12 +3468,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// remove address from unspent index
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(keyType, addrHash, input.prevout.hash, input.prevout.n), CAddressUnspentValue()));
}
}
if (fSpentIndex) {
// add the spent index to determine the txid and input that spent an output
// and to find the amount and address from an input
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->GetHeight(), prevout.nValue, keyType, addrHash)));
if (fSpentIndex) {
// add the spent index to determine the txid and input that spent an output
// and to find the amount and address from an input
spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->GetHeight(), prevout.nValue, keyType, addrHash)));
}
}
}
}
@@ -3541,23 +3524,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
vector<vector<unsigned char>> vSols;
CTxDestination vDest;
txnouttype txType = TX_PUBKEYHASH;
int keyType = 1;
// some non-standard types, like time lock coinbases, don't solve, but do extract
if ((Solver(out.scriptPubKey, txType, vSols) || ExtractDestination(out.scriptPubKey, vDest)) && txType != TX_MULTISIG)
int keyType = GetAddressType(out.scriptPubKey, vDest, txType, vSols);
if ( keyType != 0 )
{
// if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned
if (vDest.which())
{
CKeyID kid;
if (CBitcoinAddress(vDest).GetKeyID(kid))
{
vSols.push_back(vector<unsigned char>(kid.begin(), kid.end()));
}
}
else if (txType == TX_SCRIPTHASH)
{
keyType = 2;
}
for (auto addr : vSols)
{
addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr);

View File

@@ -224,8 +224,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
CBlockIndex* pindexPrev = 0;
{
ENTER_CRITICAL_SECTION(cs_main);
ENTER_CRITICAL_SECTION(mempool.cs);
LOCK2(cs_main,mempool.cs);
pindexPrev = chainActive.LastTip();
const int nHeight = pindexPrev->GetHeight() + 1;
const Consensus::Params &consensusParams = chainparams.GetConsensus();
@@ -564,11 +563,10 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
//LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x stake.%i\n", nBlockSize,blocktime,pblock->nBits,isStake);
if ( ASSETCHAINS_SYMBOL[0] != 0 && isStake )
{
LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs);
uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[512],*ptr;
CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), stakeHeight);
LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs);
if (ASSETCHAINS_LWMAPOS != 0)
{
uint32_t nBitsPOS;
@@ -593,7 +591,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
{
sleep(1);
if ( (rand() % 100) < 1 )
fprintf(stderr, "%u seconds until elegible, waiting.\n", blocktime-((uint32_t)GetAdjustedTime()+57));
fprintf(stderr, "%u seconds until elegible, waiting...\n", blocktime-((uint32_t)GetAdjustedTime()+57));
if ( chainActive.LastTip()->GetHeight() >= stakeHeight )
{
fprintf(stderr, "Block Arrived, reset staking loop.\n");
@@ -603,7 +601,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
return(0);
}
}
ENTER_CRITICAL_SECTION(cs_main);
ENTER_CRITICAL_SECTION(mempool.cs);
if ( siglen > 0 )
{
CAmount txfees;
@@ -616,7 +615,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
nFees += txfees;
pblock->nTime = blocktime;
//printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13)));
} else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
} else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
}
// Create coinbase tx
@@ -688,11 +687,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
if (scriptPubKeyIn.IsPayToScriptHash() || scriptPubKeyIn.IsPayToCryptoCondition())
{
fprintf(stderr,"CreateNewBlock: attempt to add timelock to pay2sh or pay2cc\n");
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
{
LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs);
}
return 0;
}
@@ -714,11 +708,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
if ( totalsats == 0 )
{
fprintf(stderr, "Could not create notary payment, trying again.\n");
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
{
LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs);
}
return(0);
}
fprintf(stderr, "Created notary payment coinbase totalsat.%lu\n",totalsats);
@@ -789,11 +778,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
else
{
fprintf(stderr,"error adding notaryvin, need to create 0.0001 utxos\n");
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
{
LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs);
}
return(0);
}
}
@@ -808,11 +792,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
//fprintf(stderr,"valid\n");
}
}
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
{
LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs);
}
//fprintf(stderr,"done new block\n");
return pblocktemplate.release();
}

View File

@@ -4,11 +4,11 @@
#include "cc/CCinclude.h"
#include <cstring>
extern char NOTARYADDRS[64][36];
extern char NOTARYADDRS[64][64];
extern std::string NOTARY_ADDRESS,NOTARY_PUBKEY;
extern int32_t STAKED_ERA,IS_STAKED_NOTARY,IS_KOMODO_NOTARY;
extern pthread_mutex_t staked_mutex;
extern uint8_t NOTARY_PUBKEY33[33],NUM_NOTARIES;
extern uint8_t NOTARY_PUBKEY33[33];
int8_t is_STAKED(const char *chain_name)
{
@@ -46,16 +46,6 @@ int32_t STAKED_era(int timestamp)
return(0);
};
int8_t updateStakedNotary() {
std::string notaryname;
char Raddress[18]; uint8_t pubkey33[33];
decode_hex(pubkey33,33,(char *)NOTARY_PUBKEY.c_str());
pubkey2addr((char *)Raddress,(uint8_t *)pubkey33);
NOTARY_ADDRESS.clear();
NOTARY_ADDRESS.assign(Raddress);
return(StakedNotaryID(notaryname,Raddress));
}
int8_t StakedNotaryID(std::string &notaryname, char *Raddress) {
if ( STAKED_ERA != 0 )
{
@@ -116,7 +106,6 @@ void UpdateNotaryAddrs(uint8_t pubkeys[64][33],int8_t numNotaries) {
// null pubkeys, era 0.
pthread_mutex_lock(&staked_mutex);
memset(NOTARYADDRS,0,sizeof(NOTARYADDRS));
NUM_NOTARIES = 0;
pthread_mutex_unlock(&staked_mutex);
}
else
@@ -125,7 +114,6 @@ void UpdateNotaryAddrs(uint8_t pubkeys[64][33],int8_t numNotaries) {
pthread_mutex_lock(&staked_mutex);
for (int i = 0; i<numNotaries; i++)
pubkey2addr((char *)NOTARYADDRS[i],(uint8_t *)pubkeys[i]);
NUM_NOTARIES = numNotaries;
pthread_mutex_unlock(&staked_mutex);
}
}

View File

@@ -119,7 +119,6 @@ static const char *notaries_STAKED[NUM_STAKED_ERAS][64][2] =
int8_t is_STAKED(const char *chain_name);
int32_t STAKED_era(int timestamp);
int8_t updateStakedNotary();
int8_t numStakedNotaries(uint8_t pubkeys[64][33],int8_t era);
int8_t StakedNotaryID(std::string &notaryname, char *Raddress);
void UpdateNotaryAddrs(uint8_t pubkeys[64][33],int8_t numNotaries);

98
src/notarystats.py Executable file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""
sudo apt-get install python3-dev
sudo apt-get install python3 libgnutls28-dev libssl-dev
sudo apt-get install python3-pip
pip3 install setuptools
pip3 install wheel
pip3 install base58 slick-bitcoinrpc
./notarystats.py
------------------------------------------------
"""
import platform
import os
import re
import sys
import time
import pprint
from slickrpc import Proxy
# fucntion to define rpc_connection
def def_credentials(chain):
rpcport = '';
operating_system = platform.system()
if operating_system == 'Darwin':
ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo'
elif operating_system == 'Linux':
ac_dir = os.environ['HOME'] + '/.komodo'
elif operating_system == 'Windows':
ac_dir = '%s/komodo/' % os.environ['APPDATA']
if chain == 'KMD':
coin_config_file = str(ac_dir + '/komodo.conf')
else:
coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf')
with open(coin_config_file, 'r') as f:
for line in f:
l = line.rstrip()
if re.search('rpcuser', l):
rpcuser = l.replace('rpcuser=', '')
elif re.search('rpcpassword', l):
rpcpassword = l.replace('rpcpassword=', '')
elif re.search('rpcport', l):
rpcport = l.replace('rpcport=', '')
if len(rpcport) == 0:
if chain == 'KMD':
rpcport = 7771
else:
print("rpcport not in conf file, exiting")
print("check " + coin_config_file)
exit(1)
return (Proxy("http://%s:%s@127.0.0.1:%d" % (rpcuser, rpcpassword, int(rpcport))))
rpc = def_credentials('KMD')
pp = pprint.PrettyPrinter(indent=2)
notarynames = [ "0dev1_jl777", "0dev2_kolo", "0dev3_kolo", "0dev4_decker_AR", "a-team_SH", "artik_AR", "artik_EU", "artik_NA", "artik_SH", "badass_EU", "badass_NA", "batman_AR", "batman_SH", "ca333", "chainmakers_EU", "chainmakers_NA", "chainstrike_SH", "cipi_AR", "cipi_NA", "crackers_EU", "crackers_NA", "dwy_EU", "emmanux_SH", "etszombi_EU", "fullmoon_AR", "fullmoon_NA", "fullmoon_SH", "goldenman_EU", "indenodes_AR", "indenodes_EU", "indenodes_NA", "indenodes_SH", "jackson_AR", "jeezy_EU", "karasugoi_NA", "komodoninja_EU", "komodoninja_SH", "komodopioneers_SH", "libscott_SH", "lukechilds_AR", "madmax_AR", "meshbits_AR", "meshbits_SH", "metaphilibert_AR", "metaphilibert_SH", "patchkez_SH", "pbca26_NA", "peer2cloud_AR", "peer2cloud_SH", "polycryptoblog_NA", "hyper_AR", "hyper_EU", "hyper_SH", "hyper_NA", "popcornbag_AR", "popcornbag_NA", "alien_AR", "alien_EU", "thegaltmines_NA", "titomane_AR", "titomane_EU", "titomane_SH", "webworker01_NA", "xrobesx_NA" ]
notaries = 64 * [0]
startheight = 821657 #Second time filter for assetchains (block 821657) for KMD its 814000
stopheight = 1307200
for i in range(startheight,stopheight):
ret = rpc.getNotarisationsForBlock(i)
KMD = ret['KMD']
if len(KMD) > 0:
for obj in KMD:
#for now skip KMD for this. As official stats are from BTC chain
# this can be reversed to !== to count KMD numbers :)
if obj['chain'] == 'KMD':
continue;
for notary in obj['notaries']:
notaries[notary] = notaries[notary] + 1
i = 0
SH = []
AR = []
EU = []
NA = []
for notary in notaries:
tmpnotary = {}
tmpnotary['node'] = notarynames[i]
tmpnotary['ac_count'] = notary
if notarynames[i].endswith('SH'):
SH.append(tmpnotary)
elif notarynames[i].endswith('AR'):
AR.append(tmpnotary)
elif notarynames[i].endswith('EU'):
EU.append(tmpnotary)
elif notarynames[i].endswith('NA'):
NA.append(tmpnotary)
i = i + 1
regions = {}
regions['SH'] = sorted(SH, key=lambda k: k['ac_count'], reverse=True)
regions['AR'] = sorted(AR, key=lambda k: k['ac_count'], reverse=True)
regions['EU'] = sorted(EU, key=lambda k: k['ac_count'], reverse=True)
regions["NA"] = sorted(NA, key=lambda k: k['ac_count'], reverse=True)
pp.pprint(regions)

View File

@@ -171,6 +171,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "assetchainproof", 1},
{ "crosschainproof", 1},
{ "getproofroot", 2},
{ "getNotarisationsForBlock", 0},
{ "height_MoM", 1},
{ "calc_MoM", 2},
};

View File

@@ -34,6 +34,7 @@
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
#include "notaries_staked.h"
#include "key_io.h"
#include "cc/CCImportGateway.h"
@@ -56,6 +57,7 @@ int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_
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);
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
extern std::string ASSETCHAINS_SELFIMPORT;
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx);
@@ -411,6 +413,9 @@ UniValue selfimport(const UniValue& params, bool fHelp)
return result;
}
bool GetNotarisationNotaries(uint8_t notarypubkeys[64][33], int8_t &numNN, const std::vector<CTxIn> &vin, std::vector<int8_t> &NotarisationNotaries);
UniValue importdual(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ);
@@ -746,6 +751,60 @@ UniValue importgatewaydumpprivkey(const UniValue& params, bool fHelp)
}
UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp)
{
// TODO take timestamp as param, and loop blockindex to get starting/finish height.
if (fHelp || params.size() != 1)
throw runtime_error("getNotarisationsForBlock height\n\n"
"Takes a block height and returns notarisation information "
"within the block");
LOCK(cs_main);
int32_t height = params[0].get_int();
if ( height < 0 || height > chainActive.Height() )
throw runtime_error("height out of range.\n");
uint256 blockHash = chainActive[height]->GetBlockHash();
NotarisationsInBlock nibs;
GetBlockNotarisations(blockHash, nibs);
UniValue out(UniValue::VOBJ);
//out.push_back(make_pair("blocktime",(int)));
UniValue labs(UniValue::VARR);
UniValue kmd(UniValue::VARR);
// Gets KMD notaries on KMD... but LABS notaries on labs chains needs to be fixed so LABS are identified on KMD.
int8_t numNN = 0; uint8_t notarypubkeys[64][33] = {0};
numNN = komodo_notaries(notarypubkeys, height, chainActive[height]->nTime);
BOOST_FOREACH(const Notarisation& n, nibs)
{
UniValue item(UniValue::VOBJ); UniValue notaryarr(UniValue::VARR); std::vector<int8_t> NotarisationNotaries;
if ( is_STAKED(n.second.symbol) != 0 )
continue; // for now just skip this... need to fetch diff pubkeys for these chains. labs.push_back(item);
uint256 hash; CTransaction tx;
if ( GetTransaction(n.first,tx,hash,false) )
{
if ( !GetNotarisationNotaries(notarypubkeys, numNN, tx.vin, NotarisationNotaries) )
continue;
if ( NotarisationNotaries.size() < numNN/5 )
continue;
}
item.push_back(make_pair("txid", n.first.GetHex()));
item.push_back(make_pair("chain", n.second.symbol));
item.push_back(make_pair("height", (int)n.second.height));
item.push_back(make_pair("blockhash", n.second.blockHash.GetHex()));
item.push_back(make_pair("KMD_height", height)); // for when timstamp input is used.
for ( auto notary : NotarisationNotaries )
notaryarr.push_back(notary);
item.push_back(make_pair("notaries",notaryarr));
kmd.push_back(item);
}
out.push_back(make_pair("KMD", kmd));
//out.push_back(make_pair("LABS", labs));
return out;
}
/*UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error("getNotarisationsForBlock blockHash\n\n"
@@ -765,7 +824,7 @@ UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp)
out.push_back(item);
}
return out;
}
}*/
UniValue scanNotarisationsDB(const UniValue& params, bool fHelp)

View File

@@ -853,8 +853,9 @@ bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &addr
address = CBitcoinAddress(CScriptID(hash)).ToString();
} else if (type == 1) {
address = CBitcoinAddress(CKeyID(hash)).ToString();
}
else {
} else if (type == 3) {
address = CBitcoinAddress(CKeyID(hash)).ToString();
} else {
return false;
}
return true;

View File

@@ -458,10 +458,10 @@ 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)
int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector <std::pair<CAmount, std::string>> &vaddr, UniValue *ret)
{
int64_t total = 0; int64_t totalAddresses = 0; std::string address;
int64_t utxos = 0; int64_t ignoredAddresses = 0;
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;
@@ -482,6 +482,12 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <s
CAmount nValue;
iter->GetValue(nValue);
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address);
if ( indexKey.type == 3 )
{
cryptoConditionsUTXOs++;
cryptoConditionsTotals += nValue;
continue;
}
if ( nValue > dustthreshold )
{
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
@@ -508,7 +514,7 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <s
//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());
} //else fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str());
}
catch (const std::exception& e)
{
@@ -523,166 +529,71 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <s
break;
}
}
fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);
//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)
{
//obj.push_back( make_pair("addr", it->second.c_str() ) );
//char amount[32];
//sprintf(amount, "%.8f", (double) it->first / COIN);
//obj.push_back( make_pair("amount", amount) );
//obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) );
//addressesSorted.push_back(obj);
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 ));
// 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 ));
// Total number of ignored addresses in this snaphot
ret->push_back(make_pair("ignored_addresses", ignoredAddresses));
// Total number of crypto condition utxos we skipped
ret->push_back(make_pair("skipped_cc_utxos", cryptoConditionsUTXOs));
// 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 ));
// The snapshot finished at this block height
ret->push_back(make_pair("ending_height", chainActive.Height()));
}
return(topN);
}
UniValue CBlockTreeDB::Snapshot(int top)
{
int64_t total = 0; int64_t totalAddresses = 0; std::string address;
int64_t utxos = 0; int64_t ignoredAddresses = 0;
DECLARE_IGNORELIST
boost::scoped_ptr<CDBIterator> iter(NewIterator());
std::map <std::string, CAmount> addressAmounts;
int topN = 0;
std::vector <std::pair<CAmount, std::string>> vaddr;
UniValue result(UniValue::VOBJ);
result.push_back(Pair("start_time", (int) time(NULL)));
/* std::map <std::string,int> ignoredMap = {
{"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1},
{"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1},
{"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1},
{"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1},
{"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1},
{"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1},
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1},
{"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1},
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1},
{"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1},
{"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1},
{"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1},
{"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1},
{"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1},
{"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1},
{"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1},
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey
};*/
int64_t startingHeight = chainActive.Height();
//fprintf(stderr, "Starting snapshot at height %lli\n", startingHeight);
for (iter->SeekToLast(); iter->Valid(); iter->Prev())
{
boost::this_thread::interruption_point();
try
{
std::vector<unsigned char> slKey = std::vector<unsigned char>();
pair<char, CAddressIndexIteratorKey> keyObj;
iter->GetKey(keyObj);
char chType = keyObj.first;
CAddressIndexIteratorKey indexKey = keyObj.second;
//fprintf(stderr, "chType=%d\n", chType);
if (chType == DB_ADDRESSUNSPENTINDEX)
{
try {
CAmount nValue;
iter->GetValue(nValue);
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address);
if (nValue > 0) {
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());
}
} catch (const std::exception& e) {
fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what());
break;
}
}
} catch (const std::exception& e) {
fprintf(stderr, "DONE reading index entries\n");
break;
}
}
UniValue addresses(UniValue::VARR);
//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());
UniValue obj(UniValue::VOBJ);
UniValue addressesSorted(UniValue::VARR);
int topN = 0;
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it)
result.push_back(Pair("start_time", (int) time(NULL)));
if ( Snapshot2(0,top,vaddr,&result) != 0 )
{
UniValue obj(UniValue::VOBJ);
obj.push_back( make_pair("addr", it->second.c_str() ) );
char amount[32];
sprintf(amount, "%.8f", (double) it->first / COIN);
obj.push_back( make_pair("amount", amount) );
obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) );
total += it->first;
addressesSorted.push_back(obj);
topN++;
// If requested, only show top N addresses in output JSON
if (top == topN)
break;
}
if (top)
totalAddresses = top;
if (totalAddresses > 0) {
// Array of all addreses with balances
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it)
{
UniValue obj(UniValue::VOBJ);
obj.push_back( make_pair("addr", it->second.c_str() ) );
char amount[32];
sprintf(amount, "%.8f", (double) it->first / COIN);
obj.push_back( make_pair("amount", amount) );
obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) );
addressesSorted.push_back(obj);
topN++;
// If requested, only show top N addresses in output JSON
if ( top == topN )
break;
}
// Array of all addreses with balances
result.push_back(make_pair("addresses", addressesSorted));
// Total amount in this snapshot, which is less than circulating supply if top parameter is used
result.push_back(make_pair("total", (double) total / COIN ));
// Average amount in each address of this snapshot
result.push_back(make_pair("average",(double) (total/COIN) / totalAddresses ));
}
// Total number of utxos processed in this snaphot
result.push_back(make_pair("utxos", utxos));
// Total number of addresses in this snaphot
result.push_back(make_pair("total_addresses", totalAddresses));
// Total number of ignored addresses in this snaphot
result.push_back(make_pair("ignored_addresses", ignoredAddresses));
// The snapshot began at this block height
result.push_back(make_pair("start_height", startingHeight));
// The snapshot finished at this block height
result.push_back(make_pair("ending_height", chainActive.Height()));
} else result.push_back(make_pair("error", "problem doing snapshot"));
return(result);
}

View File

@@ -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);
int32_t Snapshot2(int64_t dustthreshold, int32_t top,std::vector <std::pair<CAmount, std::string>> &vaddr, UniValue *ret);
};
#endif // BITCOIN_TXDB_H

View File

@@ -5151,7 +5151,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
boost::optional<TransactionBuilder> builder;
if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
}
} else
contextualTx.nExpiryHeight = 0; // set non z-tx to have no expiry height.
// Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation(

View File

@@ -38,6 +38,7 @@
#include "crypter.h"
#include "coins.h"
#include "zcash/zip32.h"
#include "cc/CCinclude.h"
#include <assert.h>
@@ -1747,10 +1748,6 @@ bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx)
* pblock is optional, but should be provided if the transaction is known to be in a block.
* If fUpdate is true, existing transactions will be updated.
*/
extern uint8_t NOTARY_PUBKEY33[33];
extern std::string NOTARY_ADDRESS,WHITELIST_ADDRESS;
extern int32_t IS_STAKED_NOTARY;
extern uint64_t MIN_RECV_SATS;
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
@@ -1769,71 +1766,49 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
return false;
}
}
static std::string NotaryAddress; static bool didinit;
if ( !didinit && NotaryAddress.empty() && NOTARY_PUBKEY33[0] != 0 )
{
didinit = true;
char Raddress[64];
pubkey2addr((char *)Raddress,(uint8_t *)NOTARY_PUBKEY33);
NotaryAddress.assign(Raddress);
vWhiteListAddress = mapMultiArgs["-whitelistaddress"];
if ( !vWhiteListAddress.empty() )
{
fprintf(stderr, "Activated Wallet Filter \n Notary Address: %s \n Adding whitelist address's:\n", NotaryAddress.c_str());
for ( auto wladdr : vWhiteListAddress )
fprintf(stderr, " %s\n", wladdr.c_str());
}
}
if (fExisted || IsMine(tx) || IsFromMe(tx) || sproutNoteData.size() > 0 || saplingNoteData.size() > 0)
{
// wallet filter for notary nodes. Disabled! Can be reenabled or customised for any specific use, pools could also use this to prevent wallet dwy attack.
if ( 0 && !tx.IsCoinBase() && !NOTARY_ADDRESS.empty() && IS_STAKED_NOTARY > -1 )
// wallet filter for notary nodes. Enables by setting -whitelistaddress= as startup param or in conf file (works same as -addnode byut with R-address's)
if ( !tx.IsCoinBase() && !vWhiteListAddress.empty() && !NotaryAddress.empty() )
{
int numvinIsOurs = 0, numvoutIsOurs = 0, numvinIsWhiteList = 0; int64_t totalvoutvalue = 0;
int numvinIsOurs = 0, numvinIsWhiteList = 0;
for (size_t i = 0; i < tx.vin.size(); i++)
{
uint256 hash; CTransaction txin; CTxDestination address;
if (GetTransaction(tx.vin[i].prevout.hash,txin,hash,false))
if ( GetTransaction(tx.vin[i].prevout.hash,txin,hash,false) && ExtractDestination(txin.vout[tx.vin[i].prevout.n].scriptPubKey, address) )
{
if (ExtractDestination(txin.vout[tx.vin[i].prevout.n].scriptPubKey, address))
if ( CBitcoinAddress(address).ToString() == NotaryAddress )
numvinIsOurs++;
for ( auto wladdr : vWhiteListAddress )
{
if ( CBitcoinAddress(address).ToString() == NOTARY_ADDRESS )
numvinIsOurs++;
if ( !WHITELIST_ADDRESS.empty() )
if ( CBitcoinAddress(address).ToString() == wladdr )
{
//fprintf(stderr, "white list address: %s recv address: %s\n", WHITELIST_ADDRESS.c_str(),CBitcoinAddress(address).ToString().c_str());
if ( CBitcoinAddress(address).ToString() == WHITELIST_ADDRESS ) {
//fprintf(stderr, "whitlisted is set to true here.\n");
numvinIsWhiteList++;
}
//fprintf(stderr, "We received from whitelisted address.%s\n", wladdr.c_str());
numvinIsWhiteList++;
}
}
}
}
// Now we know if it was a tx sent to us, that wasnt from ourself or the whitelist address if set..
// Now we know if it was a tx sent to us, by either a whitelisted address, or ourself.
if ( numvinIsOurs != 0 )
fprintf(stderr, "We sent from address: %s vins: %d\n",NOTARY_ADDRESS.c_str(),numvinIsOurs);
if ( numvinIsWhiteList != 0 )
fprintf(stderr, "We received from whitelisted address: %s\n",WHITELIST_ADDRESS.c_str());
// Count vouts, check if OUR notary address is the receiver.
fprintf(stderr, "We sent from address: %s vins: %d\n",NotaryAddress.c_str(),numvinIsOurs);
if ( numvinIsOurs == 0 && numvinIsWhiteList == 0 )
{
for (size_t i = 0; i < tx.vout.size() ; i++)
{
CTxDestination address2;
if ( ExtractDestination(tx.vout[i].scriptPubKey, address2))
{
if ( CBitcoinAddress(address2).ToString() == NOTARY_ADDRESS )
{
numvoutIsOurs++;
totalvoutvalue += tx.vout[i].nValue;
}
}
}
// if MIN_RECV_SATS is 0, we are on full lock down mode, accept NO transactions.
if ( MIN_RECV_SATS == 0 ) {
fprintf(stderr, "This node is on full lock down all txs are ignored! \n");
return false;
}
// If no vouts are to the notary address we will ignore them.
if ( numvoutIsOurs == 0 ) {
fprintf(stderr, "Received transaction to address other than notary address, ignored! \n");
return false;
}
fprintf(stderr, "address: %s received %ld sats from %d vouts.\n",NOTARY_ADDRESS.c_str(),totalvoutvalue,(int32_t)numvoutIsOurs);
// here we add calculation for number if vouts received, average size and determine if we accept them to wallet or not.
int64_t avgVoutSize = totalvoutvalue / numvoutIsOurs;
if ( avgVoutSize < MIN_RECV_SATS ) {
// average vout size is less than set minimum, default is 1 coin, we will ignore it
fprintf(stderr, "ignored: %d vouts average size of %ld sats.\n",numvoutIsOurs, (long)avgVoutSize);
return false;
}
}
return false;
}
CWalletTx wtx(this,tx);