diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index 187d9c9ad..247a0f2ec 100644 --- a/src/cc/CCPayments.h +++ b/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 diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index f5877c711..13d7236d4 100644 --- a/src/cc/CCinclude.h +++ b/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 payload); +int32_t payments_parsehexdata(std::vector &hexdata,cJSON *item,int32_t len); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, vscript_t vopretNonfungible); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector> oprets); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 8aa5e88f7..a81a69b1f 100644 --- a/src/cc/CCtokens.cpp +++ b/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 >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 3e93b3462..2713dd9ed 100644 --- a/src/cc/CCtx.cpp +++ b/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 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 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 > 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; } } diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index c783eb4d0..65c706862 100644 --- a/src/cc/cclib.cpp +++ b/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 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 *)"", 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,7 +505,11 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK std::vector > 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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -673,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" diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index 4f2b421aa..ca1ad7b53 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -1052,9 +1052,11 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK std::vector > 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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/dilithium.c b/src/cc/dilithium.c index 0854236ec..7ba522f0f 100644 --- a/src/cc/dilithium.c +++ b/src/cc/dilithium.c @@ -3340,7 +3340,11 @@ int64_t dilithium_inputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu std::vector > 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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/faucet.cpp b/src/cc/faucet.cpp index b794d9b1c..81a2c2933 100644 --- a/src/cc/faucet.cpp +++ b/src/cc/faucet.cpp @@ -146,7 +146,11 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub std::vector > 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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp new file mode 100644 index 000000000..29df990b5 --- /dev/null +++ b/src/cc/gamescc.cpp @@ -0,0 +1,194 @@ + +/* +./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 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); +} + +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 payload; int32_t n; + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + { + if ( payments_parsehexdata(payload,jitem(params,0),0) == 0 ) + { + komodo_sendmessage(4,8,"events",payload); + result.push_back(Pair("result","success")); + } + 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); +} + +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); +} + +void komodo_netevent(std::vector payload) +{ + int32_t i; + for (i=0; ievalcode == 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); \ + } \ +} diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index f0c8735e2..18fc43004 100644 --- a/src/cc/gateways.cpp +++ b/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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { diff --git a/src/cc/makegames b/src/cc/makegames new file mode 100755 index 000000000..b4b8cb803 --- /dev/null +++ b/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 + diff --git a/src/cc/marmara.cpp b/src/cc/marmara.cpp index 3c35632c8..60afbc7fd 100644 --- a/src/cc/marmara.cpp +++ b/src/cc/marmara.cpp @@ -388,7 +388,11 @@ int64_t AddMarmarainputs(CMutableTransaction &mtx,std::vector &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 vals; std::vector > 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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index c4f476cfb..97b56ff59 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -15,203 +15,692 @@ #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(int32_t allocation,std::vector scriptPubKey,std::vector 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,int32_t &allocation,std::vector &destscriptPubKey,std::vector &destopret) +{ + std::vector 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 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,int32_t totalallocations,std::vector 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,int32_t &totalallocations,std::vector &txidoprets) +{ + std::vector 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) -{ - 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; iismyvin)(tx.vin[i].scriptSig) != 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 - { - //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; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + txfee"); - } - else return(true); -} - bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { - 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 > txids; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - for (i=0; iInvalid("illegal normal vini"); - } - } - //fprintf(stderr,"check amounts\n"); - if ( PaymentsExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"Paymentsget invalid amount\n"); - return false; - } - 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); - } - } + // one of two addresses + // change must go to 1of2 txidaddr + // only 'F' or 1of2 txidaddr can be spent + // all vouts must match exactly + return(true); } // end of consensus code // helper functions for rpc calls in rpcwallet.cpp -int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) +int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey txidpk,int64_t total,int32_t maxinputs,uint256 createtxid,int32_t latestheight) { - // add threshold check - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector origpubkey; CTransaction vintx,tx; int32_t iter,vout,ht,n = 0; std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + 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++) { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - // no need to prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + if ( iter == 0 ) + GetCCaddress(cp,coinaddr,Paymentspk); + else GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - if ( (nValue= IsPaymentsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + 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 ( 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; + 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 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); } } } return(totalinputs); } -std::string PaymentsGet(uint64_t txfee,int64_t nValue) +UniValue payments_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag) { - 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 ) + CTransaction tx; + if ( rawtx.size() > 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++) + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) { - 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 ) - { - 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 ) - { - fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL)); - return(rawhex); - } - //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(""); -} - -std::string PaymentsFund(uint64_t txfee,int64_t funds) -{ - 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()); - Paymentspk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,funds,Paymentspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } - 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)); + 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 ) + { + 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); + } + return(params); +} + +uint256 payments_juint256(cJSON *obj) +{ + uint256 tmp; bits256 t = jbits256(obj,0); + memcpy(&tmp,&t,sizeof(tmp)); + return(revuint256(tmp)); +} + +int32_t payments_parsehexdata(std::vector &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,totalallocations,checkallocations=0,allocation; int64_t newamount,inputsum,amount,CCchange=0; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; + cJSON *params = payments_reparse(&n,jsonstr); + mypk = pubkey2pk(Mypubkey()); + Paymentspk = GetUnspendable(cp,0); + if ( params != 0 && n == 2 ) + { + createtxid = payments_juint256(jitem(params,0)); + amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; + if ( myGetTransaction(createtxid,tx,hashBlock) != 0 ) + { + if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) + { + 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 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= 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,0)); + } + 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")); + } + } + 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; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,lockedblocks,minrelease,totalallocations; std::vector 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 ) + { + 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 + { + 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); +} + +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 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); +} + +UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::vector txidoprets; uint256 hashBlock; int32_t i,n,numoprets=0,lockedblocks,minrelease,totalallocations=0; std::string rawtx; + cJSON *params = payments_reparse(&n,jsonstr); + if ( params != 0 && n >= 4 ) + { + lockedblocks = juint(jitem(params,0),0); + minrelease = juint(jitem(params,1),0); + if ( lockedblocks < 0 || minrelease < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); + } + for (i=0; i scriptPubKey,opret; int32_t allocation; + if ( myGetTransaction(txidoprets[i],tx,hashBlock) != 0 && tx.vout.size() > 1 && DecodePaymentsTxidOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) + { + totalallocations += allocation; + if ( opret.size() > 0 ) + numoprets++; + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid txidopret")); + result.push_back(Pair("txid",txidoprets[i].GetHex())); + result.push_back(Pair("txi",(int64_t)i)); + if ( params != 0 ) + free_json(params); + return(result); + } + } + if ( numoprets > 1 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","too many opreturns")); + result.push_back(Pair("numoprets",(int64_t)numoprets)); + if ( params != 0 ) + free_json(params); + return(result); + } + mypk = pubkey2pk(Mypubkey()); + Paymentspk = GetUnspendable(cp,0); + if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 ) + { + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsOpRet(lockedblocks,minrelease,totalallocations,txidoprets)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough normal funds")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + } + if ( params != 0 ) + free_json(params); + return(result); +} + +UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,allocation,numoprets=0,lockedblocks,minrelease,totalallocations; std::vector txidoprets; int64_t funds,fundsopret; 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 ) + { + 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); + } + 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 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 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")); + } + } + } + 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); +} + +UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) +{ + std::vector > addressIndex; uint256 txid,hashBlock; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease,totalallocations; std::vector txidoprets; + Paymentspk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk); + SetCCtxids(addressIndex,markeraddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + 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)); + } + } + } + result.push_back(Pair("result","success")); + result.push_back(Pair("createtxids",a)); + return(result); +} diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index c201869b0..1351bbaeb 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -333,7 +333,11 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont std::vector > 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 >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; diff --git a/src/cc/rogue/things.c b/src/cc/rogue/things.c index 39c7b94b7..e0cf48454 100644 --- a/src/cc/rogue/things.c +++ b/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')) diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 2d1a45d33..495fa8774 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1281,8 +1281,9 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } if ( cashout > 0 ) { - if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,cashout,16,cp->unspendableCCaddr)) > cashout ) + if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,cashout,60,cp->unspendableCCaddr)) > cashout ) CCchange = (inputsum - cashout); + else fprintf(stderr,"couldnt find enough utxos\n"); } mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); } diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 4f004aac2..663e2e937 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -20,6 +20,7 @@ #include "clientversion.h" #include "tinyformat.h" +#include "util.h" #include @@ -34,7 +35,7 @@ * for both bitcoind and bitcoin-core, to make it harder for attackers to * target servers or GUI users specifically. */ -const std::string CLIENT_NAME("MagicBean"); +const std::string CLIENT_NAME = GetArg("-ac_clientname", "MagicBean"); /** * Client version number diff --git a/src/init.cpp b/src/init.cpp index 2a612634e..d2546347d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -571,6 +571,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-ac_cclib", _("Cryptoconditions dynamicly loadable library")); strUsage += HelpMessageOpt("-ac_ccenable", _("Cryptoconditions to enable")); strUsage += HelpMessageOpt("-ac_ccactivate", _("Block height to enable Cryptoconditions")); + strUsage += HelpMessageOpt("-ac_clientname", _("Full node client name, default 'MagicBean'")); strUsage += HelpMessageOpt("-ac_decay", _("Percentage of block reward decrease at each halving")); strUsage += HelpMessageOpt("-ac_end", _("Block height at which block rewards will end")); strUsage += HelpMessageOpt("-ac_eras", _("Block reward eras")); diff --git a/src/komodo_defs.h b/src/komodo_defs.h index cbf84b7f0..23f291a20 100644 --- a/src/komodo_defs.h +++ b/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 payload); #endif diff --git a/src/main.cpp b/src/main.cpp index ce0760cf5..e520ad83f 100644 --- a/src/main.cpp +++ b/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 payload; + vRecv >> payload; + komodo_netevent(payload); + return(true); + } else if (strCommand == "verack") { pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); diff --git a/src/miner.cpp b/src/miner.cpp index 2069e5a8c..eaba96ee1 100644 --- a/src/miner.cpp +++ b/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 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()) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 46eb95a25..a44304ff0 100644 --- a/src/rpc/server.cpp +++ b/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 }, diff --git a/src/rpc/server.h b/src/rpc/server.h index abd0ea6a8..4eee49da3 100644 --- a/src/rpc/server.h +++ b/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); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 38c21d2bd..f20a63664 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3031,7 +3031,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) "\nExamples\n" + HelpExampleCli("z_listunspent", "") + HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\",\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\"]\"") - + HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\",\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\"]\"") + + HelpExampleRpc("z_listunspent", "6,9999999,false,[\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\",\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"]") ); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR)); @@ -5327,6 +5327,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) { @@ -5577,6 +5578,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 pubkey;