diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 91e9467dd..f5877c711 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -201,6 +201,7 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, CScript EncodeTokenImportOpRet(std::vector origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector> oprets); CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::pair opretWithId); CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::vector> oprets); +int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, std::vector> &oprets); uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector> &oprets); diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 121a16475..695ccd16b 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -504,6 +504,31 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK return(totalinputs); } +int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk) +{ + char coinaddr[64]; int64_t txfee = 10000; uint256 txid,hashBlock; CTransaction vintx; int32_t vout; + std::vector > unspentOutputs; + GetCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f vs %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN,(double)threshold/COIN); + if ( it->second.satoshis < txfee ) + continue; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + { + if ( (nValue= IsCClibvout(cp,vintx,vout,coinaddr)) != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + return(it->second.satoshis); + } //else fprintf(stderr,"nValue %.8f too small or already spent in mempool\n",(double)nValue/COIN); + } else fprintf(stderr,"couldnt get tx\n"); + } + return(0); +} + std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); diff --git a/src/cc/dilithium.c b/src/cc/dilithium.c index e36ea807e..4136b0bca 100644 --- a/src/cc/dilithium.c +++ b/src/cc/dilithium.c @@ -2929,6 +2929,29 @@ int32_t main(void) void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen); char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len); +struct dilithium_handle +{ + UT_hash_handle hh; + uint256 destpubtxid; + char handle[32]; +} *Dilithium_handles; + +struct dilithium_handle *dilithium_handlenew(std::string handle) +{ + struct dilithium_handle *hashstr = 0; + if ( handle.size() < sizeof(Dilithium_handles[0].handle)-1 ) + { + HASH_FIND(hh,Dilithium_handles,handle,(int32_t)handle.size(),hashstr); + if ( hashstr == 0 ) + { + hashstr = calloc(1,sizeof(*hashstr)); + strncpy(hashstr->handle,handle.c_str(),sizeof(hashstr->handle)); + HASH_ADD_KEYPTR(hh,Dilithium_handles,hashstr->handle,(int32_t)handle.size(),hashstr); + } + } + return(hashstr); +} + int32_t dilithium_Qmsghash(uint8_t *msg,CTransaction tx,int32_t numvouts,std::vector voutpubtxids) { CScript data; uint256 hash; int32_t i,numvins,len = 0; std::vector vintxids; std::vector vinprevns; std::vector vouts; @@ -3110,12 +3133,20 @@ UniValue dilithium_keypair(uint64_t txfee,struct CCcontract_info *cp,cJSON *para return(result); } +CPubKey Faucet_pubkeyget() +{ + struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_FAUCET); + return(GetUnspendable(cp,0)); +} + UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,dilithiumpk; uint8_t seed[SEEDBYTES],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES]; char coinaddr[64],str[CRYPTO_SECRETKEYBYTES*2+1]; std::vector bigpub; int32_t i,n,warningflag = 0; + UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey faucetpk,mypk,dilithiumpk; uint8_t seed[SEEDBYTES],pk[CRYPTO_PUBLICKEYBYTES],sk[CRYPTO_SECRETKEYBYTES]; char coinaddr[64],str[CRYPTO_SECRETKEYBYTES*2+1]; int64_t CCchange,inputs; std::vector bigpub; int32_t i,n,warningflag = 0; if ( txfee == 0 ) txfee = DILITHIUM_TXFEE; + faucetpk = Faucet_pubkeyget(); mypk = pubkey2pk(Mypubkey()); dilithiumpk = GetUnspendable(cp,0); if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) ) @@ -3132,14 +3163,23 @@ UniValue dilithium_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *par result.push_back(Pair("skaddr",dilithium_addr(coinaddr,sk,CRYPTO_SECRETKEYBYTES))); for (i=0; i= 3*txfee ) + if ( (inputs= AddCClibtxfee(cp,mtx,dilithiumpk)) > 0 ) { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,dilithiumpk)); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_registeropret(handle,mypk,bigpub)); - return(musig_rawtxresult(result,rawtx)); - } else return(cclib_error(result,"couldnt find enough funds")); - } else return(cclib_error(result,"not enough parameters")); + if ( inputs > txfee ) + CCchange = (inputs - txfee); + else CCchange = 0; + if ( AddNormalinputs(mtx,mypk,COIN+3*txfee,64) >= 3*txfee ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,2*txfee,dilithiumpk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET,COIN,faucetpk)); + if ( CCchange != 0 ) + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dilithiumpk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,dilithium_registeropret(handle,mypk,bigpub)); + return(musig_rawtxresult(result,rawtx)); + } else return(cclib_error(result,"couldnt find enough funds")); + } else return(cclib_error(result,"not enough parameters")); + } else return(cclib_error(result,"not dilithiumpk funds")); } UniValue dilithium_sign(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) @@ -3452,6 +3492,65 @@ bool dilithium_Qvalidate(struct CCcontract_info *cp,int32_t height,Eval *eval,co } else return eval->Invalid("unexpected zero signerpubtxid"); } +bool dilithium_Rvalidate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + static int32_t didinit; + std::vector > txids; + uint256 txid,hashBlock; int32_t numvouts; struct dilithium_handle *hashstr; std::string handle; std::vector bigpub; CTransaction txi; CPubKey pub33,dilithiumpk; CTxOut vout,vout0; char CCaddr[64]; + dilithiumpk = GetUnspendable(cp,0); + if ( didinit == 0 ) + { + GetCCaddress(cp,CCaddr,dilithiumpk); + SetCCtxids(txids,CCaddr); + for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) + { + txid = it->first.txhash; + if ( myGetTransaction(txid,txi,hashBlock) != 0 && (numvouts= txi.vout.size()) > 1 ) + { + if ( dilithium_registeropretdecode(handle,pub33,bigpub,txi.vout[numvouts-1].scriptPubKey) == 'R' ) + { + if ( (hashstr= dilithium_handlenew(handle)) != 0 ) + { + if ( hashstr->destpubtxid != txid ) + { + if ( hashstr->destpubtxid != zeroid ) + fprintf(stderr,"overwriting %s %s with %s\n",handle.c_str(),hashstr->destpubtxid.GetHex().c_str(),txid.GetHex().c_str()); + fprintf(stderr,"%s <- %s\n",handle.c_str(),txid.GetHex().c_str()); + hashstr->destpubtxid = txid; + } + } + } + } + } + didinit = 1; + } + if ( (numvouts= tx.vout.size()) <= 1 ) + return eval->Invalid("not enough vouts for registration tx"); + else if ( dilithium_registeropretdecode(handle,pub33,bigpub,tx.vout[numvouts-1].scriptPubKey) == 'R' ) + { + // relies on all current block tx to be put into mempool + txid = tx.GetHash(); + vout0 = MakeCC1vout(cp->evalcode,2*DILITHIUM_TXFEE,dilithiumpk); + vout = MakeCC1vout(EVAL_FAUCET,COIN,Faucet_pubkeyget()); + if ( tx.vout[0] != vout0 ) + return eval->Invalid("mismatched vout0 for register"); + else if ( tx.vout[1].nValue != DILITHIUM_TXFEE ) + return eval->Invalid("vout1 for register not txfee"); + else if ( tx.vout[2] != vout ) + return eval->Invalid("register not sending to faucet"); + else if ( (hashstr= dilithium_handlenew(handle)) == 0 ) + return eval->Invalid("error creating dilithium handle"); + else if ( hashstr->destpubtxid == zeroid ) + { + hashstr->destpubtxid = txid; + return(true); + } + else if ( hashstr->destpubtxid == txid ) + return(true); + else return eval->Invalid("duplicate dilithium handle rejected"); + } else return eval->Invalid("couldnt decode register opret"); +} + bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { CPubKey destpub33; std::string handle; uint256 hashBlock,destpubtxid,checktxid; CTransaction vintx; int32_t numvouts,mlen,smlen=CRYPTO_BYTES+32; std::vector sig,vopret; uint8_t msg[32],msg2[CRYPTO_BYTES+32],pk[CRYPTO_PUBLICKEYBYTES],*script; @@ -3459,7 +3558,9 @@ bool dilithium_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,con numvouts = tx.vout.size(); GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); script = (uint8_t *)vopret.data(); - if ( script[1] == 'Q' ) + if ( script[1] == 'R' ) + return(dilithium_Rvalidate(cp,height,eval,tx)); + else if ( script[1] == 'Q' ) return(dilithium_Qvalidate(cp,height,eval,tx)); else if ( tx.vout.size() != 2 ) return eval->Invalid("numvouts != 2");