Browse Source

Merge pull request #1351 from jl777/jl777

Jl777
jl777
jl777 5 years ago
committed by GitHub
parent
commit
aac1223757
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      src/cc/CCPayments.h
  2. 2
      src/cc/CCinclude.h
  3. 3
      src/cc/CCtokens.cpp
  4. 35
      src/cc/CCtx.cpp
  5. 18
      src/cc/cclib.cpp
  6. 4
      src/cc/dice.cpp
  7. 6
      src/cc/dilithium.c
  8. 6
      src/cc/faucet.cpp
  9. 352
      src/cc/gamescc.cpp
  10. 61
      src/cc/gamescc.h
  11. 6
      src/cc/gateways.cpp
  12. 7
      src/cc/makegames
  13. 6
      src/cc/marmara.cpp
  14. 897
      src/cc/payments.cpp
  15. 6
      src/cc/rewards.cpp
  16. 20
      src/cc/rogue/things.c
  17. 4
      src/cc/rogue_rpc.cpp
  18. 1
      src/komodo_defs.h
  19. 2
      src/komodo_utils.h
  20. 15
      src/main.cpp
  21. 17
      src/miner.cpp
  22. 6
      src/rpc/server.cpp
  23. 7
      src/rpc/server.h
  24. 79
      src/wallet/rpcwallet.cpp

9
src/cc/CCPayments.h

@ -19,9 +19,16 @@
#include "CCinclude.h"
#define PAYMENTS_TXFEE 10000
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PaymentsInfo();
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 PaymentsInfo(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr);
#endif

2
src/cc/CCinclude.h

@ -195,6 +195,8 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid);
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector<uint8_t> payload);
int32_t payments_parsehexdata(std::vector<uint8_t> &hexdata,cJSON *item,int32_t len);
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, vscript_t vopretNonfungible);
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> oprets);

3
src/cc/CCtokens.cpp

@ -586,8 +586,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() no utxos for token dual/three eval addr=" << tokenaddr << " evalcode=" << (int)cp->evalcode << " additionalTokensEvalcode2=" << (int)cp->additionalTokensEvalcode2 << std::endl);
}
threshold = total / (maxinputs != 0 ? maxinputs : 64); // TODO: maxinputs really could not be over 64? what if i want to calc total balance for all available uxtos?
// maybe it is better to add all uxtos if maxinputs == 0
threshold = total / (maxinputs != 0 ? maxinputs : CC_MAXVINS);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++)
{

35
src/cc/CCtx.cpp

@ -48,7 +48,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
int32_t i,flag,utxovout,n,err = 0;
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], unspendabletokensaddr[64],CC1of2CCaddr[64];
uint8_t *privkey, myprivkey[32], unspendablepriv[32], /*tokensunspendablepriv[32],*/ *msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *condCC2=0,*mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond=0, *condCC2=0,*mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
CPubKey unspendablepk /*, tokensunspendablepk*/;
struct CCcontract_info *cpTokens, tokensC;
globalpk = GetUnspendable(cp,0);
@ -75,7 +75,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
othercond = MakeCCcond1(cp->evalcode, unspendablepk);
GetCCaddress1of2(cp,CC1of2CCaddr,unspendablepk,unspendablepk);
//printf("evalcode.%d (%s)\n",cp->evalcode,unspendable);
//fprintf(stderr,"evalcode.%d (%s)\n",cp->evalcode,unspendable);
// tokens support:
// to spend from dual/three-eval mypk vout
@ -277,7 +277,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
}
}
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
}
}
if ( mycond != 0 )
cc_free(mycond);
if ( condCC2 != 0 )
@ -509,16 +509,18 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=CC_MAXVINS; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
int32_t abovei,belowi,ind,vout,i,n = 0; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
#ifdef ENABLE_WALLET
assert(pwalletMain != NULL);
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
threshold = total/(maxinputs+1);
if ( maxinputs > maxutxos )
maxutxos = maxinputs;
utxos = (struct CC_utxo *)calloc(CC_MAXVINS,sizeof(*utxos));
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
sum = 0;
BOOST_FOREACH(const COutput& out, vecOutputs)
{
@ -553,7 +555,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
up->vout = vout;
sum += up->nValue;
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
if ( n >= maxutxos || sum >= total )
if ( n >= maxinputs || sum >= total )
break;
}
}
@ -599,15 +601,16 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
return(0);
}
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=CC_MAXVINS; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
int32_t abovei,belowi,ind,vout,i,n = 0; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
threshold = total/(maxinputs+1);
if ( maxinputs > maxutxos )
maxutxos = maxinputs;
utxos = (struct CC_utxo *)calloc(CC_MAXVINS,sizeof(*utxos));
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
sum = 0;
Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG);
SetCCunspents(unspentOutputs,coinaddr);
@ -644,7 +647,7 @@ int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinput
up->vout = vout;
sum += up->nValue;
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
if ( n >= maxutxos || sum >= total )
if ( n >= maxinputs || sum >= total )
break;
}
}

18
src/cc/cclib.cpp

@ -38,6 +38,9 @@ std::string MYCCLIBNAME = (char *)"rogue";
#elif BUILD_CUSTOMCC
#include "customcc.h"
#elif BUILD_GAMESCC
#include "gamescc.h"
#else
#define EVAL_SUDOKU 17
#define EVAL_MUSIG 18
@ -45,6 +48,10 @@ std::string MYCCLIBNAME = (char *)"rogue";
std::string MYCCLIBNAME = (char *)"sudoku";
#endif
#ifndef BUILD_GAMESCC
void komodo_netevent(std::vector<uint8_t> payload) {}
#endif
char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); }
struct CClib_rpcinfo
@ -73,6 +80,8 @@ CClib_methods[] =
{ (char *)"rogue", (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, 'X', EVAL_ROGUE },
#elif BUILD_CUSTOMCC
RPC_FUNCS
#elif BUILD_GAMESCC
RPC_FUNCS
#else
{ (char *)"sudoku", (char *)"gen", (char *)"<no args>", 0, 0, 'G', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU },
@ -222,6 +231,8 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr)
}
#elif BUILD_CUSTOMCC
CUSTOM_DISPATCH
#elif BUILD_GAMESCC
CUSTOM_DISPATCH
#else
if ( cp->evalcode == EVAL_SUDOKU )
{
@ -420,6 +431,8 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
return(rogue_validate(cp,height,eval,tx));
#elif BUILD_CUSTOMCC
return(custom_validate(cp,height,eval,tx));
#elif BUILD_GAMESCC
return(games_validate(cp,height,eval,tx));
#else
if ( cp->evalcode == EVAL_SUDOKU )
return(sudoku_validate(cp,height,eval,tx));
@ -492,6 +505,8 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs != 0 )
threshold = total/maxinputs;
else threshold = total;
@ -675,6 +690,9 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len)
#elif BUILD_CUSTOMCC
#include "customcc.cpp"
#elif BUILD_GAMESCC
#include "gamescc.cpp"
#else
#include "sudoku.cpp"
#include "musig.cpp"

4
src/cc/dice.cpp

@ -1052,9 +1052,11 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total / maxinputs;
else threshold = total / 64;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

6
src/cc/dilithium.c

@ -3340,7 +3340,11 @@ int64_t dilithium_inputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

6
src/cc/faucet.cpp

@ -146,7 +146,11 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

352
src/cc/gamescc.cpp

@ -0,0 +1,352 @@
#include "gamescc.h"
/*
./c cclib rng 17 \"[%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,250]\"
{
"playerid": 250,
"seed": 1398876319979341887,
"rng": 14565767519458298868,
"lastrng": 15075236803740723044,
"maxrngs": 10000,
"result": "success"
}
./c cclib rngnext 17 \"[14565767519458298868]\"
{
"seed": 14565767519458297856,
"rng": 4253087318999719449,
"result": "success"
}
The idea is for a game to start with a near future blockhash, so the lobby gets players signed up until just prior to the designated height. then that blockhash can be used to create a stream of rngs.
the same initial rng can be used for all players, if the identical starting condition is required. up to 255 different initial rng can be derived from a single blockhash. (Actually any number is possible, for simplicity rng rpc limits to 255).
you will notice maxrngs and lastrng, the lastrng is the rng value that will happen after maxrng iterations of calling rngnext with the current rng. This allows making time based multiplayer games where all the nodes can validate all the other nodes rng, even without realtime synchronization of all user input events.
Every time period, all players would set their rng value to the lastrng value. The only thing to be careful of is it not exceed the maxrng calls to rngnext in a single time period. otherwise the same set of rng numbers will be repeated.
*/
CScript games_opret(uint8_t funcid,CPubKey pk)
{
CScript opret; uint8_t evalcode = EVAL_GAMES;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
return(opret);
}
uint8_t games_opretdecode(CPubKey &pk,CScript scriptPubKey)
{
std::vector<uint8_t> vopret; uint8_t e,f;
GetOpReturnData(scriptPubKey,vopret);
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_GAMES )
{
return(f);
}
return(0);
}
CScript games_eventopret(uint32_t timestamp,CPubKey pk,std::vector<uint8_t> sig,std::vector<uint8_t> payload)
{
CScript opret; uint8_t evalcode = EVAL_GAMES;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'E' << timestamp << pk << sig << payload);
return(opret);
}
uint8_t games_eventdecode(uint32_t &timestamp,CPubKey &pk,std::vector<uint8_t> &sig,std::vector<uint8_t> &payload,std::vector<uint8_t> vopret)
{
uint8_t e,f;
timestamp = 0;
if ( vopret.size() > 6 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> timestamp; ss >> pk; ss >> sig; ss >> payload) != 0 && e == EVAL_GAMES )
{
return(f);
}
fprintf(stderr,"ERROR e.%d f.%d pk.%d sig.%d payload.%d\n",e,f,(int32_t)pk.size(),(int32_t)sig.size(),(int32_t)payload.size());
return(0);
}
UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag)
{
CTransaction tx;
if ( rawtx.size() > 0 )
{
result.push_back(Pair("hex",rawtx));
if ( DecodeHexTx(tx,rawtx) != 0 )
{
if ( broadcastflag != 0 && myAddtomempool(tx) != 0 )
RelayTransaction(tx);
result.push_back(Pair("txid",tx.GetHash().ToString()));
result.push_back(Pair("result","success"));
} else result.push_back(Pair("error","decode hex"));
} else result.push_back(Pair("error","couldnt finalize CCtx"));
return(result);
}
uint64_t _games_rngnext(uint64_t initseed)
{
uint16_t seeds[4]; int32_t i;
seeds[0] = initseed;
seeds[1] = (initseed >> 16);
seeds[2] = (initseed >> 32);
seeds[3] = (initseed >> 48);
seeds[0] = (seeds[0]*GAMES_RNGMULT + GAMES_RNGOFFSET);
seeds[1] = ((seeds[0] ^ seeds[1])*GAMES_RNGMULT + GAMES_RNGOFFSET);
seeds[2] = ((seeds[0] ^ seeds[1] ^ seeds[2])*GAMES_RNGMULT + GAMES_RNGOFFSET);
seeds[3] = ((seeds[0] ^ seeds[1] ^ seeds[2] ^ seeds[3])*GAMES_RNGMULT + GAMES_RNGOFFSET);
return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]);
}
UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ); int32_t n; uint64_t seed;
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 )
{
seed = jdouble(jitem(params,0),0);
result.push_back(Pair("seed",seed));
seed = _games_rngnext(seed);
result.push_back(Pair("rng",seed));
result.push_back(Pair("result","success"));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","not enough params"));
}
return(result);
}
UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ); int32_t i,n,playerid=0; uint64_t seed=0,initseed; bits256 hash;
if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) )
{
hash = jbits256(jitem(params,0),0);
if ( n == 2 )
{
playerid = juint(jitem(params,1),0);
if ( playerid >= 0xff )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","playerid too big"));
return(result);
}
}
playerid++;
for (i=0; i<8; i++)
{
if ( ((1 << i) & playerid) != 0 )
seed ^= (uint64_t)hash.uints[i] << ((i&1)*32);
}
initseed = seed;
seed = _games_rngnext(initseed);
result.push_back(Pair("playerid",(int64_t)(playerid - 1)));
result.push_back(Pair("seed",initseed));
result.push_back(Pair("rng",seed));
for (i=0; i<GAMES_MAXRNGS; i++)
seed = _games_rngnext(seed);
result.push_back(Pair("lastrng",seed));
result.push_back(Pair("maxrngs",GAMES_MAXRNGS));
result.push_back(Pair("result","success"));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","not enough params"));
}
return(result);
}
UniValue games_create(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ);
return(result);
}
UniValue games_info(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ);
return(result);
}
UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
UniValue result(UniValue::VOBJ);
return(result);
}
int32_t games_eventsign(uint32_t &timestamp,std::vector<uint8_t> &sig,std::vector<uint8_t> payload,CPubKey pk)
{
static secp256k1_context *ctx;
size_t siglen = 74; secp256k1_pubkey pubkey; secp256k1_ecdsa_signature signature; int32_t len,verifyflag = 1; uint8_t privkey[32]; uint256 hash; uint32_t t;
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if ( ctx != 0 )
{
Myprivkey(privkey);
len = payload.size();
payload.resize(len + 4);
if ( timestamp == 0 )
{
timestamp = (uint32_t)time(NULL);
verifyflag = 0;
}
t = timestamp;
payload[len++] = t, t >>= 8;
payload[len++] = t, t >>= 8;
payload[len++] = t, t >>= 8;
payload[len++] = t;
vcalc_sha256(0,(uint8_t *)&hash,&payload[0],len);
if ( verifyflag == 0 )
{
if ( secp256k1_ecdsa_sign(ctx,&signature,(uint8_t *)&hash,privkey,NULL,NULL) > 0 )
{
sig.resize(siglen);
if ( secp256k1_ecdsa_signature_serialize_der(ctx,&sig[0],&siglen,&signature) > 0 )
{
if ( siglen != sig.size() )
sig.resize(siglen);
return(0);
}
else return(-3);
} else return(-2);
}
else
{
if ( secp256k1_ec_pubkey_parse(ctx,&pubkey,pk.begin(),33) > 0 )
{
if ( secp256k1_ecdsa_signature_parse_der(ctx,&signature,&sig[0],sig.size()) > 0 )
{
if ( secp256k1_ecdsa_verify(ctx,&signature,(uint8_t *)&hash,&pubkey) > 0 )
return(0);
else return(-4);
} else return(-3);
} else return(-2);
}
} else return(-1);
}
int32_t games_payload(CPubKey pk,uint32_t timestamp,std::vector<uint8_t> payload)
{
uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0;
if ( (len= payload.size()) > 36 )
{
len -= 36;
for (i=0; i<32; i++)
((uint8_t *)&gametxid)[i] = payload[len+i];
eventid = (uint32_t)payload[len+32];
eventid |= (uint32_t)payload[len+33] << 8;
eventid |= (uint32_t)payload[len+34] << 16;
eventid |= (uint32_t)payload[len+35] << 24;
for (i=0; i<len; i++)
fprintf(stderr,"%02x",payload[i]);
fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid);
return(0);
} else return(-1);
}
UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
{
static uint256 lastgametxid; static uint32_t numevents;
UniValue result(UniValue::VOBJ); std::vector<uint8_t> sig,payload,vopret; int32_t len,i,n; uint32_t x; CPubKey mypk; char str[67]; uint32_t eventid,timestamp = 0; uint256 gametxid;
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 1 && n <= 3 )
{
if ( payments_parsehexdata(payload,jitem(params,0),0) == 0 )
{
if ( n >= 2 )
gametxid = juint256(jitem(params,1));
else gametxid = zeroid;
if ( gametxid != lastgametxid )
{
lastgametxid = gametxid;
numevents = 1;
eventid = 0;
}
if ( n == 3 )
{
eventid = juint(jitem(params,2),0);
if ( numevents <= eventid )
numevents = eventid+1;
} else eventid = numevents++;
len = payload.size();
payload.resize(len + 4 + 32);
for (i=0; i<32; i++)
payload[len++] = ((uint8_t *)&gametxid)[i];
x = eventid;
payload[len++] = x, x >>= 8;
payload[len++] = x, x >>= 8;
payload[len++] = x, x >>= 8;
payload[len++] = x;
mypk = pubkey2pk(Mypubkey());
if ( games_eventsign(timestamp,sig,payload,mypk) == 0 )
{
GetOpReturnData(games_eventopret(timestamp,mypk,sig,payload),vopret);
games_payload(mypk,timestamp,payload);
komodo_sendmessage(4,8,"events",vopret);
result.push_back(Pair("gametxid",gametxid.GetHex()));
result.push_back(Pair("eventid",(int64_t)eventid));
result.push_back(Pair("timestamp",(int64_t)timestamp));
result.push_back(Pair("result","success"));
result.push_back(Pair("pubkey33",pubkey33_str(str,(uint8_t *)&mypk)));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","signing ereror"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt parsehexdata"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","not enough params"));
}
return(result);
}
void komodo_netevent(std::vector<uint8_t> message)
{
int32_t i,retval,lag,lagerr=0; uint32_t timestamp,now; CPubKey pk; std::vector<uint8_t> sig,payload; char str[67];
if ( games_eventdecode(timestamp,pk,sig,payload,message) == 'E' )
{
now = (uint32_t)time(NULL);
lag = now - timestamp;
if ( lag < -3 || lag > 3 )
{
fprintf(stderr,"LAG ERROR ");
lagerr = lag;
}
if ( (retval= games_eventsign(timestamp,sig,payload,pk)) != 0 )
fprintf(stderr,"SIG ERROR.%d ",retval);
else if ( lagerr == 0 )
{
if ( games_payload(pk,timestamp,payload) == 0 ) // first time this is seen
{
if ( (rand() % 10) == 0 )
{
fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size());
komodo_sendmessage(2,2,"events",message);
}
}
}
for (i=0; i<payload.size(); i++)
fprintf(stderr,"%02x",payload[i]);
fprintf(stderr," payload, got pk.%s siglen.%d lag.[%d]\n",pubkey33_str(str,(uint8_t *)&pk),(int32_t)sig.size(),lag);
}
else
{
for (i=0; i<message.size(); i++)
fprintf(stderr,"%02x",message[i]);
fprintf(stderr," got RAW message[%d]\n",(int32_t)message.size());
}
}
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
return(true);
}

61
src/cc/gamescc.h

@ -0,0 +1,61 @@
#ifndef H_GAMESCC_H
#define H_GAMESCC_H
#define ENABLE_WALLET
extern CWallet* pwalletMain;
#include "CCinclude.h"
#include "secp256k1.h"
std::string MYCCLIBNAME = (char *)"gamescc";
#define EVAL_GAMES (EVAL_FAUCET2+1)
#define GAMES_TXFEE 10000
#define GAMES_RNGMULT 11109
#define GAMES_RNGOFFSET 13849
#define GAMES_MAXRNGS 10000
#define MYCCNAME "games"
#define RPC_FUNCS \
{ (char *)MYCCNAME, (char *)"rng", (char *)"hash,playerid", 1, 2, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"rngnext", (char *)"seed", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"create", (char *)"game,minplayers,maxplayers,buyin,numblocks", 5, 5, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"info", (char *)"txid", 1, 1, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \
{ (char *)MYCCNAME, (char *)"register", (char *)"txid", 1, 1, ' ', EVAL_GAMES },
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_create(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_info(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
#define CUSTOM_DISPATCH \
if ( cp->evalcode == EVAL_GAMES ) \
{ \
if ( strcmp(method,"rng") == 0 ) \
return(games_rng(txfee,cp,params)); \
else if ( strcmp(method,"rngnext") == 0 ) \
return(games_rngnext(txfee,cp,params)); \
else if ( strcmp(method,"create") == 0 ) \
return(games_create(txfee,cp,params)); \
else if ( strcmp(method,"info") == 0 ) \
return(games_info(txfee,cp,params)); \
else if ( strcmp(method,"register") == 0 ) \
return(games_register(txfee,cp,params)); \
else if ( strcmp(method,"events") == 0 ) \
return(games_events(txfee,cp,params)); \
else \
{ \
result.push_back(Pair("result","error")); \
result.push_back(Pair("error","invalid gamescc method")); \
result.push_back(Pair("method",method)); \
return(result); \
} \
}
#endif

6
src/cc/gateways.cpp

@ -898,7 +898,11 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
{
GetTokensCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "check " << coinaddr << " for gateway inputs" << std::endl);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{

7
src/cc/makegames

@ -0,0 +1,7 @@
#!/bin/sh
gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp
cp gamescc.so ../libcc.so
cd ..
make
cd cc

6
src/cc/marmara.cpp

@ -388,7 +388,11 @@ int64_t AddMarmarainputs(CMutableTransaction &mtx,std::vector<CPubKey> &pubkeys,
uint64_t threshold,nValue,totalinputs = 0; uint256 txid,hashBlock; CTransaction tx; int32_t numvouts,ht,unlockht,vout,i,n = 0; uint8_t funcid; CPubKey pk; std::vector<int64_t> vals;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

897
src/cc/payments.cpp

@ -15,203 +15,832 @@
#include "CCPayments.h"
/*
Payments CC is a catchall CC, supported invoices, zpayments, automated funds allocation, including token based revshare
/*
0) txidopret <- allocation, scriptPubKey, opret
1) create <- locked_blocks, minrelease, list of txidopret
2) fund createtxid amount opretflag to global CC address with opret or txidaddr without
3) release amount -> vout[i] will be scriptPubKeys[i] and (amount * allocations[i]) / sumallocations[] (only using vins that have been locked for locked_blocks+).
4) info txid -> display parameters, funds
5) list -> all txids
First step is to create txids with the info needed in their opreturns. this info is the weight, scriptPubKey and opret if needed. To do that txidopret is used:
./c is a script that invokes komodo-cli with the correct -ac_name
./c paymentstxidopret \"[9,%222102d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388dac%22]\" -> rawhex with txid 95d9fc8d8a3ef63693c7427e59ff5e177ef63b7345d5f6d6497ac262699a8def
./c paymentstxidopret \"[1,%2221039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775ac%22]\" -> rawhex txid 00469695a08b975ceaf7258896abbf1455eb0f383e8a98fc650deace4cbf02a1
now we have 2 txid with the required info in the opreturn. one of them has a 9 and the other a 1 for a 90%/10% split.
./c paymentscreate \"[0,0,%2295d9fc8d8a3ef63693c7427e59ff5e177ef63b7345d5f6d6497ac262699a8def%22,%2200469695a08b975ceaf7258896abbf1455eb0f383e8a98fc650deace4cbf02a1%22]\" -> created txid 318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a that will be the createtxid that the other rpc calls will use.
lets see if this appears in the list
./c paymentslist ->
{
"result": "success",
"createtxids": [
"318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a"
]
}
It appeared! now lets get more info on it:
./c paymentsinfo \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22]\"
{
"lockedblocks": 0,
"totalallocations": 10,
"minrelease": 0,
"RWRM36sC8jSctyFZtsu7CyDcHYPdZX7nPZ": 0.00000000,
"REpyKi7avsVduqZ3eimncK4uKqSArLTGGK": 0.00000000,
"totalfunds": 0.00000000,
"result": "success"
}
There are 2 possible places the funds for this createtxid can be, the first is the special address that is derived from combining the globalCC address with the txidaddr. txidaddr is a non-spendable markeraddress created by converting the txid into a 33 byte pubkey by prefixing 0x02 to the txid. It is a 1of2 address, so it doesnt matter that nobody knows the privkey for this txidaddr. the second address is the global CC address and only utxo to that address with an opreturn containing the createtxid are funds valid for this payments CC createtxid
next let us add some funds to it. the funds can be to either of the two addresses, controlled by useopret (defaults to 0)
./c paymentsfund \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22,1,0]\" -> txid 28f69b925bb7a21d2a3ba2327e85eb2031b014e976e43f5c2c6fb8a76767b221, which indeed sent funds to RWRM36sC8jSctyFZtsu7CyDcHYPdZX7nPZ without an opreturn and it appears on the payments info.
./c paymentsfund \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22,1,1]\" -> txid cc93330b5c951b724b246b3b138d00519c33f2a600a7c938bc9e51aff6e20e32, which indeed sent funds to REpyKi7avsVduqZ3eimncK4uKqSArLTGGK with an opreturn and it appears on the payments info.
./c paymentsrelease \"[%22318d827cc6d8f25f40517e7fb0982e3f707b4aa749d322483fc336686a87b28a%22,1.5]\" -> a8d5dbbb8ee94c05e75c4f3c5221091f59dcb86e0e9c4e1e3d2cf69e6fce6b81
it used both fund utxos
*/
// start of consensus code
int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
CScript EncodePaymentsTxidOpRet(int64_t allocation,std::vector<uint8_t> scriptPubKey,std::vector<uint8_t> destopret)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'T' << allocation << scriptPubKey << destopret);
return(opret);
}
uint8_t DecodePaymentsTxidOpRet(CScript scriptPubKey,int64_t &allocation,std::vector<uint8_t> &destscriptPubKey,std::vector<uint8_t> &destopret)
{
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 >> allocation; ss >> destscriptPubKey; ss >> destopret) != 0 )
{
if ( e == EVAL_PAYMENTS && f == 'T' )
return(f);
}
return(0);
}
CScript EncodePaymentsFundOpRet(uint256 checktxid)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << checktxid);
return(opret);
}
uint8_t DecodePaymentsFundOpRet(CScript scriptPubKey,uint256 &checktxid)
{
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 >> checktxid) != 0 )
{
if ( e == EVAL_PAYMENTS && f == 'F' )
return(f);
}
return(0);
}
CScript EncodePaymentsOpRet(int32_t lockedblocks,int32_t minrelease,int64_t totalallocations,std::vector<uint256> txidoprets)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'C' << lockedblocks << minrelease << totalallocations << txidoprets);
return(opret);
}
uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int64_t &totalallocations,std::vector<uint256> &txidoprets)
{
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 >> lockedblocks; ss >> minrelease; ss >> totalallocations; ss >> txidoprets) != 0 )
{
if ( e == EVAL_PAYMENTS && f == 'C' )
return(f);
}
return(0);
}
int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr)
{
char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (cmpaddr[0] == 0 || strcmp(destaddr,cmpaddr) == 0) )
return(tx.vout[v].nValue);
}
return(0);
}
bool PaymentsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
void pub2createtxid(char *str)
{
int i,n;
char *rev;
n = (int32_t)strlen(str);
rev = (char *)malloc(n + 1);
for (i=0; i<n; i+=2)
{
rev[n-2-i] = str[i];
rev[n-1-i] = str[i+1];
}
rev[n] = 0;
strcpy(str,rev);
free(rev);
}
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
static uint256 zerohash;
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
numvins = tx.vin.size();
numvouts = tx.vout.size();
for (i=0; i<numvins; i++)
// one of two addresses
// change must go to 1of2 txidaddr
// change is/must be in vout[0]
// only 'F' or 1of2 txidaddr can be spent
// all vouts must match exactly
char temp[128], coinaddr[64], txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash; CTransaction tmptx;
int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector<uint256> txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk;
// user marker vout to get the createtxid
if ( tx.vout.size() < 2 )
return(eval->Invalid("not enough vouts"));
if ( tx.vout.back().scriptPubKey[0] == OP_RETURN )
{
//fprintf(stderr,"vini.%d\n",i);
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
scriptpubkey = HexStr(tx.vout[tx.vout.size()-2].scriptPubKey.begin()+2, tx.vout[tx.vout.size()-2].scriptPubKey.end()-1);
fHasOpret = true;
} else scriptpubkey = HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin()+2,tx.vout[tx.vout.size()-1].scriptPubKey.end()-1);
strcpy(temp, scriptpubkey.c_str());
pub2createtxid(temp);
createtxid = Parseuint256(temp);
//printf("createtxid.%s\n",createtxid.ToString().c_str());
// use the createtxid to fetch the tx and all of the plans info.
if ( myGetTransaction(createtxid,tmptx,blockhash) != 0 )
{
if ( tmptx.vout.size() > 0 && DecodePaymentsOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
{
//fprintf(stderr,"vini.%d check mempool\n",i);
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("cant find vinTx");
else
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
return(eval->Invalid("negative values"));
Paymentspk = GetUnspendable(cp,0);
//fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() );
// Get all the script pubkeys and allocations
std::vector<int64_t> allocations;
std::vector<CScript> scriptPubKeys;
int64_t checkallocations = 0;
i = 0;
BOOST_FOREACH(const uint256& txidopret, txidoprets)
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant Payments from mempool");
if ( (assetoshis= IsPaymentsvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
inputs += assetoshis;
CTransaction tx0; std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
{
scriptPubKeys.push_back(CScript(scriptPubKey.begin(), scriptPubKey.end()));
allocations.push_back(allocation);
//fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation);
checkallocations += allocation;
}
i++;
}
// sanity check to make sure we got all the required info
if ( allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size() )
return(eval->Invalid("missing data cannot validate"));
//fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations);
if ( totalallocations != checkallocations )
return(eval->Invalid("allocation missmatch"));
txidpk = CCtxidaddr(txidaddr,createtxid);
GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk);
//fprintf(stderr, "coinaddr.%s\n", coinaddr);
// make sure change is in vout 0 and is paying to the contract address.
if ( (change= IsPaymentsvout(cp,tx,0,coinaddr)) == 0 )
return(eval->Invalid("change is in wrong vout or is wrong tx type"));
// Check vouts go to the right place and pay the right amounts.
int64_t amount = 0, checkamount; int32_t n = 0;
checkamount = tx.GetValueOut() - change - PAYMENTS_TXFEE;
for (i = 1; i < (fHasOpret ? tx.vout.size()-2 : tx.vout.size()-1); i++)
{
std::string destscriptPubKey = HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end());
std::string voutscriptPubKey = HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end());
if ( destscriptPubKey != voutscriptPubKey )
{
fprintf(stderr, "pays wrong destination destscriptPubKey.%s voutscriptPubKey.%s\n", destscriptPubKey.c_str(), voutscriptPubKey.c_str());
return(eval->Invalid("pays wrong address"));
}
int64_t test = allocations[n];
test *= checkamount;
test /= totalallocations;
if ( test != tx.vout[i].nValue )
{
fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue);
return(eval->Invalid("amounts do not match"));
}
amount += tx.vout[i].nValue;
n++;
}
// This is a backup check to make sure there are no extra vouts paying something else!
if ( checkamount != amount )
return(eval->Invalid("amounts do not match"));
if ( amount < minrelease*COIN )
{
fprintf(stderr, "does not meet minrelease amount.%li minrelease.%li\n",amount, (int64_t)minrelease*COIN );
return(eval->Invalid("amount is too small"));
}
i = 0;
int32_t ht = chainActive.LastTip()->GetHeight();
BOOST_FOREACH(const CTxIn& vin, tx.vin)
{
CTransaction txin;
if ( myGetTransaction(vin.prevout.hash,txin,blockhash) )
{
// check the vin comes from the CC address's
char destaddr[64];
Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey);
if ( strcmp(destaddr,coinaddr) != 0 )
{
std::vector<uint8_t> scriptPubKey,opret; uint256 checktxid;
if ( txin.vout.size() < 2 || DecodePaymentsFundOpRet(txin.vout[txin.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid )
{
fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str());
return(eval->Invalid("vin is not paymentsCC type"));
} //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str());
}
// check the chain depth vs locked blcoks requirement.
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
if ( pblockindex->GetHeight() > ht-lockedblocks )
{
fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex->GetHeight(), ht-lockedblocks);
return(eval->Invalid("vin not elegible"));
}
} else return(eval->Invalid("cant get vin transaction"));
i++;
}
} else return(eval->Invalid("create transaction cannot decode"));
} else return(eval->Invalid("Could not get contract transaction"));
return(true);
}
// end of consensus code
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey txidpk,int64_t total,int32_t maxinputs,uint256 createtxid,int32_t latestheight)
{
char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx,tx; int32_t iter,vout,ht,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
Paymentspk = GetUnspendable(cp,0);
for (iter=0; iter<2; iter++)
{
if ( iter == 0 )
GetCCaddress(cp,coinaddr,Paymentspk);
else GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk);
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;
//fprintf(stderr,"iter.%d %s/v%d %s\n",iter,txid.GetHex().c_str(),vout,coinaddr);
if ( vout == 0 && GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( latestheight != 0 )
{
if ( (ht= komodo_blockheight(hashBlock)) == 0 )
{
fprintf(stderr,"null ht\n");
continue;
}
else if ( ht > latestheight )
{
fprintf(stderr,"ht.%d > lastheight.%d\n",ht,latestheight);
continue;
}
}
if ( iter == 0 )
{
std::vector<uint8_t> scriptPubKey,opret;
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() < 2 || DecodePaymentsFundOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid )
{
fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str());
continue;
}
}
if ( (nValue= IsPaymentsvout(cp,vintx,vout,coinaddr)) > PAYMENTS_TXFEE && nValue >= threshold && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
//fprintf(stderr,"iter.%d %s/v%d %s %.8f\n",iter,txid.GetHex().c_str(),vout,coinaddr,(double)nValue/COIN);
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
} //else fprintf(stderr,"nValue %.8f vs threshold %.8f\n",(double)nValue/COIN,(double)threshold/COIN);
}
}
}
for (i=0; i<numvouts; i++)
return(totalinputs);
}
UniValue payments_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag)
{
CTransaction tx;
if ( rawtx.size() > 0 )
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsPaymentsvout(cp,tx,i)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+txfee )
result.push_back(Pair("hex",rawtx));
if ( DecodeHexTx(tx,rawtx) != 0 )
{
if ( broadcastflag != 0 && myAddtomempool(tx) != 0 )
RelayTransaction(tx);
result.push_back(Pair("txid",tx.GetHash().ToString()));
result.push_back(Pair("result","success"));
} else result.push_back(Pair("error","decode hex"));
} else result.push_back(Pair("error","couldnt finalize payments CCtx"));
return(result);
}
cJSON *payments_reparse(int32_t *nump,char *jsonstr)
{
cJSON *params=0; char *newstr; int32_t i,j;
*nump = 0;
if ( jsonstr != 0 )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
return eval->Invalid("mismatched inputs != outputs + txfee");
if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' )
{
jsonstr[strlen(jsonstr)-1] = 0;
jsonstr++;
}
newstr = (char *)malloc(strlen(jsonstr)+1);
for (i=j=0; jsonstr[i]!=0; i++)
{
if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' )
{
newstr[j++] = '"';
i += 2;
}
else if ( jsonstr[i] == '\'' )
newstr[j++] = '"';
else newstr[j++] = jsonstr[i];
}
newstr[j] = 0;
params = cJSON_Parse(newstr);
if ( 0 && params != 0 )
printf("new.(%s) -> %s\n",newstr,jprint(params,0));
free(newstr);
*nump = cJSON_GetArraySize(params);
}
else return(true);
return(params);
}
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
uint256 payments_juint256(cJSON *obj)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return eval->Invalid("no validation yet");
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
if ( numvouts < 1 )
return eval->Invalid("no vouts");
else
uint256 tmp; bits256 t = jbits256(obj,0);
memcpy(&tmp,&t,sizeof(tmp));
return(revuint256(tmp));
}
int32_t payments_parsehexdata(std::vector<uint8_t> &hexdata,cJSON *item,int32_t len)
{
char *hexstr; int32_t val;
if ( (hexstr= jstr(item,0)) != 0 && ((val= is_hexstr(hexstr,0)) == len*2 || (val > 0 && len == 0)) )
{
val >>= 1;
hexdata.resize(val);
decode_hex(&hexdata[0],val,hexstr);
return(0);
} else return(-1);
}
UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
{
int32_t latestheight,nextheight = komodo_nextheight();
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock;
CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector<uint256> txidoprets;
cJSON *params = payments_reparse(&n,jsonstr);
mypk = pubkey2pk(Mypubkey());
Paymentspk = GetUnspendable(cp,0);
if ( params != 0 && n == 2 )
{
for (i=0; i<numvins; i++)
createtxid = payments_juint256(jitem(params,0));
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049;
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 )
{
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
{
return eval->Invalid("illegal normal vini");
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","negative parameter"));
return(result);
}
latestheight = (nextheight - lockedblocks - 1);
if ( amount < minrelease*COIN )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","amount too smal"));
result.push_back(Pair("amount",ValueFromAmount(amount)));
result.push_back(Pair("minrelease",ValueFromAmount(minrelease*COIN)));
return(result);
}
txidpk = CCtxidaddr(txidaddr,createtxid);
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk));
m = txidoprets.size();
for (i=0; i<m; i++)
{
std::vector<uint8_t> scriptPubKey,opret;
vout.nValue = 0;
if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
{
vout.nValue = allocation;
vout.scriptPubKey.resize(scriptPubKey.size());
memcpy(&vout.scriptPubKey[0],&scriptPubKey[0],scriptPubKey.size());
checkallocations += allocation;
if ( opret.size() > 0 )
{
onlyopret.resize(opret.size());
memcpy(&onlyopret[0],&opret[0],opret.size());
numoprets++;
}
} else break;
mtx.vout.push_back(vout);
}
result.push_back(Pair("numoprets",(int64_t)numoprets));
if ( i != m )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid txidoprets[i]"));
result.push_back(Pair("txi",(int64_t)i));
if ( params != 0 )
free_json(params);
return(result);
}
else if ( checkallocations != totalallocations )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","totalallocations mismatch"));
result.push_back(Pair("checkallocations",(int64_t)checkallocations));
result.push_back(Pair("totalallocations",(int64_t)totalallocations));
if ( params != 0 )
free_json(params);
return(result);
}
else if ( numoprets > 1 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","too many oprets"));
if ( params != 0 )
free_json(params);
return(result);
}
newamount = amount;
for (i=0; i<m; i++)
{
mtx.vout[i+1].nValue *= amount;
mtx.vout[i+1].nValue /= totalallocations;
if ( mtx.vout[i+1].nValue < PAYMENTS_TXFEE )
{
newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue);
mtx.vout[i+1].nValue = PAYMENTS_TXFEE;
}
}
if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE )
{
std::string rawtx;
if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE )
mtx.vout[0].nValue = CCchange;
mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG));
GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk);
CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr);
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret);
if ( params != 0 )
free_json(params);
result.push_back(Pair("amount",ValueFromAmount(amount)));
result.push_back(Pair("newamount",ValueFromAmount(newamount)));
return(payments_rawtxresult(result,rawtx,1));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt find enough locked funds"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt decode paymentscreate txid opret"));
}
}
//fprintf(stderr,"check amounts\n");
if ( PaymentsExactAmounts(cp,eval,tx,1,10000) == false )
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt find paymentscreate txid"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
}
if ( params != 0 )
free_json(params);
return(result);
}
UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ);
CPubKey Paymentspk,mypk,txidpk; uint256 txid,hashBlock; int64_t amount,totalallocations; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,lockedblocks,minrelease; std::vector<uint256> txidoprets;
cJSON *params = payments_reparse(&n,jsonstr);
mypk = pubkey2pk(Mypubkey());
Paymentspk = GetUnspendable(cp,0);
if ( params != 0 && n > 1 && n <= 3 )
{
txid = payments_juint256(jitem(params,0));
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049;
if ( n == 3 )
useopret = jint(jitem(params,2),0) != 0;
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid createtxid"));
}
else if ( AddNormalinputs(mtx,mypk,amount+PAYMENTS_TXFEE,60) > 0 )
{
fprintf(stderr,"Paymentsget invalid amount\n");
return false;
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","negative parameter"));
if ( params != 0 )
free_json(params);
return(result);
}
if ( useopret == 0 )
{
txidpk = CCtxidaddr(txidaddr,txid);
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,amount,Paymentspk,txidpk));
}
else
{
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk));
opret = EncodePaymentsFundOpRet(txid);
}
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret);
if ( params != 0 )
free_json(params);
return(payments_rawtxresult(result,rawtx,1));
}
else
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"Paymentsget validated\n");
else fprintf(stderr,"Paymentsget invalid\n");
return(retval);
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt find enough funds"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
}
if ( params != 0 )
free_json(params);
return(result);
}
// end of consensus code
// helper functions for rpc calls in rpcwallet.cpp
UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx;
std::vector<uint8_t> scriptPubKey,opret; int32_t allocation,n,retval0,retval1=0;
cJSON *params = payments_reparse(&n,jsonstr);
mypk = pubkey2pk(Mypubkey());
if ( params != 0 && n > 1 && n <= 3 )
{
allocation = juint(jitem(params,0),0);
retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0);
if ( n == 3 )
retval1 = payments_parsehexdata(opret,jitem(params,2),0);
if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE,10) > 0 )
{
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret));
if ( params != 0 )
free_json(params);
return(payments_rawtxresult(result,rawtx,1));
}
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid params or cant find txfee"));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
result.push_back(Pair("n",(int64_t)n));
fprintf(stderr,"(%s) %p\n",jsonstr,params);
}
if ( params != 0 )
free_json(params);
return(result);
}
int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr)
{
// add threshold check
char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
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 )
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
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++)
{
if ( (nValue= IsPaymentsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
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' )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
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"));
}
return(totalinputs);
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
}
if ( params != 0 )
free_json(params);
return(result);
}
std::string PaymentsGet(uint64_t txfee,int64_t nValue)
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
{
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk,Paymentspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
cp = CCinit(&C,EVAL_PAYMENTS);
if ( txfee == 0 )
txfee = 10000;
Paymentspk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddPaymentsInputs(cp,mtx,Paymentspk,nValue+txfee,60)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,CCchange,Paymentspk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
fprintf(stderr,"start at %u\n",(uint32_t)time(NULL));
j = rand() & 0xfffffff;
for (i=0; i<1000000; i++,j++)
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_PAYMENTS << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,numoprets=0,lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock;
cJSON *params = payments_reparse(&n,jsonstr);
if ( params != 0 && n == 1 )
{
Paymentspk = GetUnspendable(cp,0);
createtxid = payments_juint256(jitem(params,0));
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 )
{
if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
{
len >>= 1;
decode_hex(buf,len,(char *)rawhex.c_str());
hash = bits256_doublesha256(0,buf,len);
if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 )
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
{
fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL));
return(rawhex);
result.push_back(Pair("result","error"));
result.push_back(Pair("error","negative parameter"));
if ( params != 0 )
free_json(params);
return(result);
}
result.push_back(Pair("lockedblocks",(int64_t)lockedblocks));
result.push_back(Pair("totalallocations",(int64_t)totalallocations));
result.push_back(Pair("minrelease",(int64_t)minrelease));
for (i=0; i<txidoprets.size(); i++)
{
UniValue obj(UniValue::VOBJ); std::vector<uint8_t> scriptPubKey,opret;
obj.push_back(Pair("txid",txidoprets[i].GetHex()));
if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
{
outstr = (char *)malloc(2*(scriptPubKey.size() + opret.size()) + 1);
for (j=0; j<scriptPubKey.size(); j++)
sprintf(&outstr[j<<1],"%02x",scriptPubKey[j]);
outstr[j<<1] = 0;
//fprintf(stderr,"scriptPubKey.(%s)\n",outstr);
obj.push_back(Pair("scriptPubKey",outstr));
if ( opret.size() != 0 )
{
for (j=0; j<opret.size(); j++)
sprintf(&outstr[j<<1],"%02x",opret[j]);
outstr[j<<1] = 0;
//fprintf(stderr,"opret.(%s)\n",outstr);
obj.push_back(Pair("opreturn",outstr));
numoprets++;
}
free(outstr);
} else fprintf(stderr,"error decoding voutsize.%d\n",(int32_t)txO.vout.size());
a.push_back(obj);
}
flag++;
result.push_back(Pair("numoprets",(int64_t)numoprets));
if ( numoprets > 1 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","too many opreturns"));
}
else
{
result.push_back(Pair("txidoprets",a));
txidpk = CCtxidaddr(txidaddr,createtxid);
GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk);
funds = CCaddress_balance(fundsaddr);
result.push_back(Pair(fundsaddr,ValueFromAmount(funds)));
GetCCaddress(cp,fundsopretaddr,Paymentspk);
fundsopret = CCaddress_balance(fundsopretaddr);
result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret)));
result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret)));
result.push_back(Pair("result","success"));
}
//fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]);
}
}
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
return("");
} else fprintf(stderr,"cant find Payments inputs\n");
return("");
if ( flag == 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt find valid payments create txid"));
}
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
}
if ( params != 0 )
free_json(params);
return(result);
}
std::string PaymentsFund(uint64_t txfee,int64_t funds)
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk,Paymentspk; CScript opret; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_PAYMENTS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; uint256 txid,hashBlock;
UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t totalallocations;
Paymentspk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk);
SetCCtxids(addressIndex,markeraddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,funds,Paymentspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
txid = it->first.txhash;
if ( it->first.index == 0 && myGetTransaction(txid,tx,hashBlock) != 0 )
{
if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' )
{
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","negative parameter"));
return(result);
}
a.push_back(uint256_str(str,txid));
}
}
}
return("");
}
UniValue PaymentsInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey Paymentspk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Payments"));
cp = CCinit(&C,EVAL_PAYMENTS);
Paymentspk = GetUnspendable(cp,0);
funding = AddPaymentsInputs(cp,mtx,Paymentspk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
result.push_back(Pair("createtxids",a));
return(result);
}

6
src/cc/rewards.cpp

@ -333,7 +333,11 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
if ( maxinputs > CC_MAXVINS )
maxinputs = CC_MAXVINS;
if ( maxinputs > 0 )
threshold = total/maxinputs;
else threshold = total;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;

20
src/cc/rogue/things.c

@ -527,6 +527,7 @@ add_line(struct rogue_state *rs,char *fmt, char *arg)
touchwin(tw);
wrefresh(tw);
wait_for(rs,' ');
if (md_hasclreol())
{
werase(tw);
@ -543,16 +544,31 @@ add_line(struct rogue_state *rs,char *fmt, char *arg)
}
else
{
char *promptex = "--Wait 5 sec.--";
wmove(hw, LINES - 1, 0);
waddstr(hw, prompt);
waddstr(hw, newpage ? promptex : prompt);
wrefresh(hw);
wait_for(rs,' ');
if (newpage) {
#ifdef _WIN32
#ifdef _MSC_VER
#define sleep(x) Sleep(1000*(x))
#endif
#endif
sleep(5);
} else
wait_for(rs, ' ');
clearok(curscr, TRUE);
wclear(hw);
touchwin(stdscr);
}
newpage = TRUE;
line_cnt = 0;
maxlen = (int) strlen(prompt);
}
if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))

4
src/cc/rogue_rpc.cpp

@ -917,8 +917,8 @@ UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param
int32_t nextheight = komodo_nextheight();
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight);
UniValue result(UniValue::VOBJ); CPubKey roguepk,mypk; uint256 gametxid,playertxid,batontxid; int64_t batonvalue,buyin; std::vector<uint8_t> keystrokes,playerdata; int32_t numplayers,regslot,numkeys,batonht,batonvout,n,elapsed,gameheight,maxplayers; CTransaction tx; CTxOut txout; char *keystrokestr,destaddr[64]; std::string rawtx,symbol,pname; bits256 t; uint8_t mypriv[32];
if ( txfee == 0 )
txfee = 10000;
// if ( txfee == 0 )
txfee = 1000; // smaller than normal on purpose
rogue_univalue(result,"keystrokes",-1,-1);
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 )
{

1
src/komodo_defs.h

@ -81,5 +81,6 @@ extern int32_t USE_EXTERNAL_PUBKEY;
int tx_height( const uint256 &hash );
extern char NOTARYADDRS[64][36];
extern uint8_t NUM_NOTARIES;
void komodo_netevent(std::vector<uint8_t> payload);
#endif

2
src/komodo_utils.h

@ -2079,7 +2079,7 @@ void komodo_args(char *argv0)
while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 )
{
fprintf(stderr,"waiting for datadir\n");
fprintf(stderr,"waiting for datadir (%s)\n",dirname);
#ifndef _WIN32
sleep(3);
#else

15
src/main.cpp

@ -7035,8 +7035,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
Misbehaving(pfrom->GetId(), 1);
return false;
}
else if ( strCommand == "events" )
{
int32_t i;
if ( ASSETCHAINS_CCLIB != "gamescc" )
{
Misbehaving(pfrom->GetId(), 1);
return false;
}
std::vector<uint8_t> payload;
vRecv >> payload;
komodo_netevent(payload);
return(true);
}
else if (strCommand == "verack")
{
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));

17
src/miner.cpp

@ -931,6 +931,23 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
return CreateNewBlock(pubkey, scriptPubKey, gpucount, isStake);
}
void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector<uint8_t> payload)
{
int32_t numsent = 0;
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if ( pnode->hSocket == INVALID_SOCKET )
continue;
if ( numsent < minpeers || (rand() % 10) == 0 )
{
pnode->PushMessage(message,payload);
if ( numsent++ > maxpeers )
break;
}
}
}
void komodo_broadcast(CBlock *pblock,int32_t limit)
{
if (IsInitialBlockDownload())

6
src/rpc/server.cpp

@ -466,6 +466,12 @@ static const CRPCCommand vRPCCommands[] =
// 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", "paymentsrelease", &payments_release, true },
{ "CClib", "cclibaddress", &cclibaddress, true },
{ "CClib", "cclibinfo", &cclibinfo, true },

7
src/rpc/server.h

@ -288,6 +288,13 @@ extern UniValue marmara_creditloop(const UniValue& params, bool fHelp);
extern UniValue marmara_settlement(const UniValue& params, bool fHelp);
extern UniValue marmara_lock(const UniValue& params, bool fHelp);
extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
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_info(const UniValue& params, bool fHelp);
extern UniValue payments_list(const UniValue& params, bool fHelp);
extern UniValue cclibaddress(const UniValue& params, bool fHelp);
extern UniValue cclibinfo(const UniValue& params, bool fHelp);
extern UniValue cclib(const UniValue& params, bool fHelp);

79
src/wallet/rpcwallet.cpp

@ -5323,6 +5323,7 @@ int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits
#include "../cc/CCPrices.h"
#include "../cc/CCHeir.h"
#include "../cc/CCMarmara.h"
#include "../cc/CCPayments.h"
int32_t ensure_CCrequirements(uint8_t evalcode)
{
@ -5573,6 +5574,84 @@ UniValue cclib(const UniValue& params, bool fHelp)
return(CClib(cp,method,jsonstr));
}
UniValue payments_release(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentsrelease \"[%22createtxid%22,amount]\"\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(PaymentsRelease(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_fund(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentsfund \"[%22createtxid%22,amount(,useopret)]\"\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(PaymentsFund(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_txidopret(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentstxidopret \"[allocation,%22scriptPubKey%22(,%22destopret%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(PaymentsTxidopret(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_create(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(PaymentsCreate(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_info(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentsinfo \"[%22createtxid%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(PaymentsInfo(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_list(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 0 )
throw runtime_error("paymentslist\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(PaymentsList(cp,(char *)""));
}
UniValue oraclesaddress(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;

Loading…
Cancel
Save