Browse Source

Ccactivate

pull/4/head
jl777 6 years ago
parent
commit
e0f78699ce
  1. 3
      src/cc/CCinclude.h
  2. 3
      src/cc/CClotto.h
  3. 2
      src/cc/CCutils.cpp
  4. 172
      src/cc/lotto.cpp
  5. 1
      src/komodo_gateway.h
  6. 2
      src/komodo_globals.h
  7. 3
      src/komodo_utils.h
  8. 4
      src/main.h
  9. 6
      src/script/standard.cpp

3
src/cc/CCinclude.h

@ -28,7 +28,8 @@
#include <univalue.h>
#include <exception>
extern int32_t KOMODO_CONNECTING;
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE;
extern uint32_t ASSETCHAINS_CC;
#define SMALLVAL 0.000000000000001
union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; };

3
src/cc/CClotto.h

@ -20,9 +20,12 @@
#include "CCinclude.h"
#define EVAL_LOTTO 0xe9
uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv);
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
UniValue LottoInfo(uint256 lottoid);
UniValue LottoList();
std::string LottoTicket(uint64_t txfee,int64_t numtickets);
std::string LottoWinner(uint64_t txfee);

2
src/cc/CCutils.cpp

@ -256,6 +256,8 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
{
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
if ( ASSETCHAINS_CC == 0 || height < KOMODO_CCACTIVATE )
return(false);
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
return(true);
height = KOMODO_CONNECTING;

172
src/cc/lotto.cpp

@ -17,6 +17,48 @@
#include "../txmempool.h"
/*
A blockchain lotto has the problem of generating the deterministic random numbers needed to get a winner in a way that doesnt allow cheating. If we save the entropy for later publishing and display the hash of the entropy, it is true that the players wont know what the entropy value is, however the creator of the lotto funds will be able to know and simply create a winning ticket when the jackpot is large enough.
We also need to avoid chain reorgs from disclosing the entropy and then allowing people to submit a winning ticket calculated based on the disclosed entropy (see attack vector in dice.cpp)
As usual it needs to be provably fair and random
The solution is for everybody to post the hash of their entropy when purchasing tickets. Then at the time of the drawing, nodes would post their entropy over an N block period to avoid censorship attack. After the N block period, then we have valid entropy that we know was locked in prior to the start of the N blocks and that nobody would have been able to know ahead of time the final entropy value.
As long as one node submits a high entropy value, then just by combining all the submissions together, we get the drawing's entropy value. Given that, the usual process can determine if there was a winner at the specified odds. In fact, all the nodes are able to determine exactly how many winners there were and whether to validate 1/w payouts to the w winners or rollover the jackpot to the next drawing.
To remove the need for an autopayout, the winning node(s) would need to submit a 1/w payout tx, this would be able to be done at any time and the winner does not have to have submitted proof of hentropy. In order to prevent a player from opportunistically withholding their entropy, the lotto creator will post the original proof of hentropy after the N block player submission period. This masks to all the players the final value of entropy.
Attack vector: the lotto creator can have many player tickets in reserve all with their entropy ready to submit, but based on the actual submissions, find the one which gives him the best outcome. since all the player submissions will be known via mempool, along with the original hentropy. However the lotto creator would have to mine the final block in order to know the order of the player tickets.
Thinking about this evil miner attack, it seems pretty bad, so a totally new approach is needed. Preferably with a simple enough protocol. Let us remove any special knowledge by the lotto creator, so like the faucet, it seems just that there is a single lotto for a chain.
>>>>>>>>>>>> second iteration
What we need is something that gives each ticket an equal chance at the jackpot, without allowing miner or relayer to gain an advantage. ultimately the jackpot payout tx needs to be confirmed, so there needs to be some number of blocks to make a claim to avoid censorship attack. If onchain entropy is needed, then it should be reduced to 1 bit per block to reduce the grinding that is possible. This does mean a block miner for the last bit of entropy can double their chances at winning, but the alternative is to have an external source of entropy, which creates its own set of issues like what prevents the nodes getting the external entropy from cheating?
Conveniently the lotto mechanics are similar to a PoS staking, so it can be based on everybody trying to stake a single lotto jackpot.
The calculation would need to be based on the payout address and utxosize, so relayers cant intercept it to steal the jackpot.
each jackpot would effectively restart the lotto
the funds from new lotto tickets can be spent by the jackpot, but those tickets can still win the new jackpot
each set of tickets (utxo) would become eligible to claim the jackpot after some time is elapsed so the entropy for that utxo can be obtained. [6 bits * 32 + 1 bit * 16] 48 blocks
It is possible to have a jackpot but miss out on it due to not claiming it. To minimize the effect from this, each ticket would have one chance to win, which can be calculated and a jackpot claim submitted just once.
in order to randomize the timing of claim, a txid PoW similar to faucetget will maximize the chance of only a single jackpot txid that can propagate throughout the mempools, which will prevent the second one broadcast. Granted the mining node can override this if they also have a winning ticket, but assuming the PoS lottery makes it unlikely for two winners in a single block, this is not a big issue.
In order to adapt the difficulty of winning the lotto, but not requiring recalculating all past tickets, as new lotto tickets are sold without a jackpot, it needs to become easier to win. Basically as the lotto jackpot gets bigger and bigger, it keeps getting easier to win! This convergence will avoid having unwinnable jackpots.
rpc calls
lottoinfo
lottotickets <numtickets>
lottostatus
lottowinner tickethash ticketid
*/
// start of consensus code
@ -62,10 +104,10 @@ bool LottoExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
if ( (assetoshis= IsLottovout(cp,tx,i)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+COIN+txfee )
if ( inputs != outputs+txfee )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
return eval->Invalid("mismatched inputs != outputs + COIN + txfee");
return eval->Invalid("mismatched inputs != outputs + txfee");
}
else return(true);
}
@ -128,7 +170,7 @@ int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
{
txid = it->first.txhash;
// prevent dup
if ( it->second.satoshis < 1000000 )
if ( it->second.satoshis < COIN )
continue;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
@ -147,20 +189,128 @@ int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
return(totalinputs);
}
std::string LottoTicket(uint64_t txfee,int64_t numtickets)
uint8_t DecodeLottoFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int32_t ticketsize,int32_t odds,int32_t firstheight,int32_t period,uint256 hentropy)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> ticketsize; ss >> odds; ss >> firstheight; ss >> period; ss >> hentropy) != 0 )
{
if ( e == EVAL_LOTTO && f == 'F' )
return(f);
}
return(0);
}
int64_t LottoPlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
{
char coinaddr[64]; uint64_t sbits; int64_t nValue; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; uint8_t funcid;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
lockedfunds = 0;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( (funcid= DecodeLottoOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'F' || funcid == 'T' )
{
if ( refsbits == sbits && (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
{
if ( (nValue= IsLottovout(cp,tx,vout)) > 0 )
lockedfunds += nValue;
else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN);
} //else fprintf(stderr,"else case\n");
} else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
}
}
return(lockedfunds);
}
UniValue LottoInfo(uint256 lottoid)
{
UniValue result(UniValue::VOBJ); uint256 hashBlock,hentropy; CTransaction vintx; uint64_t lockedfunds,sbits; int32_t ticketsize,odds,firstheight,period; CPubKey lottopk; struct CCcontract_info *cp,C; char str[67],numstr[65];
if ( GetTransaction(lottoid,vintx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find lottoid\n");
result.push_back(Pair("result","error"));
result.push_back(Pair("error","cant find lottoid"));
return(result);
}
if ( vintx.vout.size() > 0 && DecodeLottoFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,ticketsize,odds,firstheight,period,hentropy) == 0 )
{
fprintf(stderr,"lottoid isnt lotto creation txid\n");
result.push_back(Pair("result","error"));
result.push_back(Pair("error","lottoid isnt lotto creation txid"));
return(result);
}
result.push_back(Pair("result","success"));
result.push_back(Pair("lottoid",uint256_str(str,lottoid)));
unstringbits(str,sbits);
result.push_back(Pair("name",str));
result.push_back(Pair("sbits",sbits));
result.push_back(Pair("ticketsize",ticketsize));
result.push_back(Pair("odds",odds));
cp = CCinit(&C,EVAL_LOTTO);
lottopk = GetUnspendable(cp,0);
lockedfunds = LottoPlanFunds(sbits,cp,lottopk,lottoid);
sprintf(numstr,"%.8f",(double)lockedfunds/COIN);
result.push_back(Pair("jackpot",numstr));
return(result);
}
UniValue LottoList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,hentropy; CTransaction vintx; uint64_t sbits; int32_t ticketsize,odds,firstheight,period; char str[65];
cp = CCinit(&C,EVAL_LOTTO);
SetCCtxids(addressIndex,cp->normaladdr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodeLottoFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,ticketsize,odds,firstheight,period,hentropy) == 'F' )
{
result.push_back(uint256_str(str,txid));
}
}
}
return(result);
}
std::string LottoCreate(uint64_t txfee,char *planstr,int64_t funding,int32_t ticketsize,int32_t odds,int32_t firstheight,int32_t period)
{
CMutableTransaction mtx; uint256 entropy,hentropy; CPubKey mypk,lottopk; uint64_t sbits,int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_LOTTO);
if ( txfee == 0 )
txfee = 10000;
lottopk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
sbits = stringbits(planstr);
if ( AddNormalinputs(mtx,mypk,funding+txfee,60) > 0 )
{
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,funding,lottopk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_LOTTO << (uint8_t)'F' << sbits << ticketsize << odds << firstheight << period << hentropy)));
}
}
std::string LottoTicket(uint64_t txfee,uint256 lottoid,int64_t numtickets)
{
CMutableTransaction mtx; CPubKey mypk,Lottopk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
CMutableTransaction mtx; CPubKey mypk,lottopk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_LOTTO);
if ( txfee == 0 )
txfee = 10000;
Lottopk = GetUnspendable(cp,0);
lottopk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddLottoInputs(cp,mtx,Lottopk,nValue+txfee,60)) > 0 )
if ( (inputs= AddLottoInputs(cp,mtx,lottopk,nValue+txfee,60)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,CCchange,Lottopk));
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,CCchange,lottopk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
} else fprintf(stderr,"cant find Lotto inputs\n");
@ -169,15 +319,15 @@ std::string LottoTicket(uint64_t txfee,int64_t numtickets)
std::string LottoWinner(uint64_t txfee)
{
CMutableTransaction mtx; CPubKey mypk,Lottopk; int64_t winnings = 0; CScript opret; struct CCcontract_info *cp,C;
CMutableTransaction mtx; CPubKey mypk,lottopk; int64_t winnings = 0; CScript opret; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_LOTTO);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
Lottopk = GetUnspendable(cp,0);
lottopk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,txfee,64) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,winnings,Lottopk));
mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,winnings,lottopk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
return("");

1
src/komodo_gateway.h

@ -755,6 +755,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim
if ( height > 1 && checktoshis == 0 )
{
checktoshis = ((uint64_t)GetBlockSubsidy(height, Params().GetConsensus()) - block.vtx[0].vout[0].nValue);
// some pools will need to change their pool fee to be (poolfee % - txfees)
//checktoshis += txn_count * 0.001; // rely on higher level validations to prevent emitting more coins than actual txfees
}
if ( height >= 2 && (overflow != 0 || total > checktoshis || strangeout != 0) )

2
src/komodo_globals.h

@ -46,7 +46,7 @@ struct komodo_state KOMODO_STATES[34];
int COINBASE_MATURITY = _COINBASE_MATURITY;//100;
int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1;
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,JUMBLR_PAUSE = 1;
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY;
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE;

3
src/komodo_utils.h

@ -1544,6 +1544,7 @@ void komodo_args(char *argv0)
}
KOMODO_STOPAT = GetArg("-stopat",0);
ASSETCHAINS_CC = GetArg("-ac_cc",0);
KOMODO_CCACTIVATE = GetArg("-ac_ccactivate",0);
ASSETCHAINS_PUBLIC = GetArg("-ac_public",0);
ASSETCHAINS_PRIVATE = GetArg("-ac_private",0);
if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 )
@ -1650,6 +1651,8 @@ void komodo_args(char *argv0)
//printf("created (%s)\n",fname);
} else printf("error creating (%s)\n",fname);
#endif
if ( KOMODO_CCACTIVATE != 0 && ASSETCHAINS_CC == 0 )
ASSETCHAINS_CC = 2;
}
else
{

4
src/main.h

@ -104,8 +104,8 @@ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
//static const bool DEFAULT_ADDRESSINDEX = false;
//static const bool DEFAULT_SPENTINDEX = false;
#define DEFAULT_ADDRESSINDEX (GetArg("-ac_cc",0) != 0)
#define DEFAULT_SPENTINDEX (GetArg("-ac_cc",0) != 0)
#define DEFAULT_ADDRESSINDEX (GetArg("-ac_cc",0) != 0 || GetArg("-ac_ccactivate",0) != 0)
#define DEFAULT_SPENTINDEX (GetArg("-ac_cc",0) != 0 || GetArg("-ac_ccactivate",0) != 0)
static const bool DEFAULT_TIMESTAMPINDEX = false;
static const unsigned int DEFAULT_DB_MAX_OPEN_FILES = 1000;
static const bool DEFAULT_DB_COMPRESSION = true;

6
src/script/standard.cpp

@ -73,8 +73,10 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
if (IsCryptoConditionsEnabled()) {
// Shortcut for pay-to-crypto-condition
if (scriptPubKey.IsPayToCryptoCondition()) {
if (scriptPubKey.MayAcceptCryptoCondition()) {
if (scriptPubKey.IsPayToCryptoCondition())
{
if (scriptPubKey.MayAcceptCryptoCondition())
{
typeRet = TX_CRYPTOCONDITION;
vector<unsigned char> hashBytes; uint160 x; int32_t i; uint8_t hash20[20],*ptr;;
x = Hash160(scriptPubKey);

Loading…
Cancel
Save