diff --git a/src/Makefile.am b/src/Makefile.am index ce7fd1731..248f9aa27 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -288,6 +288,7 @@ libbitcoin_server_a_SOURCES = \ bloom.cpp \ cc/eval.cpp \ cc/import.cpp \ + cc/importgateway.cpp \ cc/CCassetsCore.cpp \ cc/CCcustom.cpp \ cc/CCtx.cpp \ diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index 1f594e38b..8dfed186f 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -18,7 +18,6 @@ #define CC_GATEWAYS_H #include "CCinclude.h" -#include "../merkleblock.h" bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4); diff --git a/src/cc/CCImportGateway.h b/src/cc/CCImportGateway.h new file mode 100644 index 000000000..995cde460 --- /dev/null +++ b/src/cc/CCImportGateway.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright © 2014-2018 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + + +#ifndef CC_IMPORTGATEWAY_H +#define CC_IMPORTGATEWAY_H + +#include "CCinclude.h" + +// CCcustom +bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn); +bool ImportGatewayExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid); +std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4); +std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vectorproof,CPubKey destpub); +std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount); +std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex); +std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex); +std::string ImportGatewayMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin); +UniValue ImportGatewayPendingDeposits(uint256 bindtxid,std::string refcoin); +UniValue ImportGatewayPendingWithdraws(uint256 bindtxid,std::string refcoin); +UniValue ImportGatewayProcessedWithdraws(uint256 bindtxid,std::string refcoin); +UniValue ImportGatewayExternalAddress(uint256 bindtxid,CPubKey pubkey); +UniValue ImportGatewayDumpPrivKey(uint256 bindtxid,CKey key); +UniValue ImportGatewayList(); +UniValue ImportGatewayInfo(uint256 bindtxid); +#endif \ No newline at end of file diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index 3a00e0c98..6c66b3599 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -31,6 +31,7 @@ #include "CCPayments.h" #include "CCGateways.h" #include "CCtokens.h" +#include "CCImportGateway.h" /* CCcustom has most of the functions that need to be extended to create a new CC contract. @@ -63,7 +64,6 @@ const char *AssetsCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6"; const char *AssetsNormaladdr = "RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u"; char AssetsCChexstr[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" }; uint8_t AssetsCCpriv[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 }; - #include "CCcustom.inc" #undef FUNCNAME #undef EVALCODE @@ -75,7 +75,6 @@ const char *FaucetCCaddr = "R9zHrofhRbub7ER77B7NrVch3A63R39GuC"; const char *FaucetNormaladdr = "RKQV4oYs4rvxAWx1J43VnT73rSTVtUeckk"; char FaucetCChexstr[67] = { "03682b255c40d0cde8faee381a1a50bbb89980ff24539cb8518e294d3a63cefe12" }; uint8_t FaucetCCpriv[32] = { 0xd4, 0x4f, 0xf2, 0x31, 0x71, 0x7d, 0x28, 0x02, 0x4b, 0xc7, 0xdd, 0x71, 0xa0, 0x39, 0xc4, 0xbe, 0x1a, 0xfe, 0xeb, 0xc2, 0x46, 0xda, 0x76, 0xf8, 0x07, 0x53, 0x3d, 0x96, 0xb4, 0xca, 0xa0, 0xe9 }; - #include "CCcustom.inc" #undef FUNCNAME #undef EVALCODE @@ -243,6 +242,17 @@ uint8_t CClibCCpriv[32] = { 0x57, 0xcf, 0x49, 0x71, 0x7d, 0xb4, 0x15, 0x1b, 0x4f #undef FUNCNAME #undef EVALCODE +// ImportGateway +#define FUNCNAME IsImportGatewayInput +#define EVALCODE EVAL_IMPORTGATEWAY +const char *ImportGatewayCCaddr = "RXJT6CRAXHFuQ2UjqdxMj7EfrayF6UJpzZ"; +const char *ImportGatewayNormaladdr = "RNFRho63Ddz1Rh2eGPETykrU4fA8r67S4Y"; +char ImportGatewayCChexstr[67] = { "0397231cfe04ea32d5fafb2206773ec9fba6e15c5a4e86064468bca195f7542714" }; +uint8_t ImportGatewayCCpriv[32] = { 0x65, 0xef, 0x27, 0xeb, 0x3d, 0xb0, 0xb4, 0xae, 0x0f, 0xbc, 0x77, 0xdb, 0xf8, 0x40, 0x48, 0x90, 0x52, 0x20, 0x9e, 0x45, 0x3b, 0x49, 0xd8, 0x97, 0x60, 0x8c, 0x27, 0x4c, 0x59, 0x46, 0xe1, 0xdf }; +#include "CCcustom.inc" +#undef FUNCNAME +#undef EVALCODE + int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode) { CPubKey pk; int32_t i; uint8_t pub33[33],check33[33],hash[32]; char CCaddr[64],checkaddr[64],str[67]; @@ -425,6 +435,14 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) cp->validate = TokensValidate; cp->ismyvin = IsTokensInput; break; + case EVAL_IMPORTGATEWAY: + strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr); + strcpy(cp->normaladdr, ImportGatewayNormaladdr); + strcpy(cp->CChexstr, ImportGatewayCChexstr); + memcpy(cp->CCpriv, ImportGatewayCCpriv, 32); + cp->validate = ImportGatewayValidate; + cp->ismyvin = IsImportGatewayInput; + break; default: if ( CClib_initcp(cp,evalcode) < 0 ) return(0); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 12b4a6d12..d1fda0154 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -51,6 +51,7 @@ one other technical note is that komodod has the insight-explorer extensions bui #include "../komodo_defs.h" #include "../utlist.h" #include "../uthash.h" +#include "merkleblock.h" #define CC_BURNPUBKEY "02deaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead" #define CC_MAXVINS 1024 @@ -185,9 +186,12 @@ bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, CTransaction &txOut, std::vector> &preConditions, std::vector> ¶ms); int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format); -uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format); uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vectorpublishers); uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); +uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format); +uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num); +uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); +int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen); //int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); @@ -212,11 +216,6 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible); bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector &vinPubkeys); -uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); -int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen); - - - // CCcustom CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv); //uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopret1, std::vector &vopret2); @@ -270,6 +269,9 @@ bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t t std::vector Mypubkey(); bool Myprivkey(uint8_t myprivkey[]); int64_t CCduration(int32_t &numblocks,uint256 txid); +uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid); +int32_t CCCointxidExists(char const *logcategory,uint256 cointxid); +uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids); bool komodo_txnotarizedconfirmed(uint256 txid); CPubKey check_signing_pubkey(CScript scriptSig); // CCtx diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 887550a0c..9a68c2456 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -532,6 +532,95 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) return(duration); } +uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid) +{ + CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; + int64_t val,merkleht; CPubKey pk; std::vectordata; char str[65],str2[65]; + + txid = zeroid; + LogPrint(logcategory,"start reverse scan %s\n",uint256_str(str,batontxid)); + while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) + { + LogPrint(logcategory,"check %s\n",uint256_str(str,batontxid)); + if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) + { + LogPrint(logcategory,"decoded %s\n",uint256_str(str,batontxid)); + if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) + { + len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); + len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); + + LogPrint(logcategory,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash)); + if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) + { + txid = batontxid; + LogPrint(logcategory,"set txid\n"); + return(mhash); + } + else + { + LogPrint(logcategory,"missing hash\n"); + return(zeroid); + } + } + else LogPrint(logcategory,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height); + batontxid = bhash; + LogPrint(logcategory,"new hash %s\n",uint256_str(str,batontxid)); + } else break; + } + LogPrint(logcategory,"end of loop\n"); + return(zeroid); +} + +int32_t myIs_coinaddr_inmempoolvout(char const *logcategory,char *coinaddr) +{ + int32_t i,n; char destaddr[64]; + BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) + { + const CTransaction &tx = e.GetTx(); + if ( (n= tx.vout.size()) > 0 ) + { + const uint256 &txid = tx.GetHash(); + for (i=0; i > addressIndex; + CCtxidaddr(txidaddr,cointxid); + SetCCtxids(addressIndex,txidaddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + return(-1); + } + return(myIs_coinaddr_inmempoolvout(logcategory,txidaddr)); +} + +/* Get the block merkle root for a proof + * IN: proofData + * OUT: merkle root + * OUT: transaction IDS + */ +uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids) +{ + CMerkleBlock merkleBlock; + if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) + return uint256(); + return merkleBlock.txn.ExtractMatches(txids); +} + bool komodo_txnotarizedconfirmed(uint256 txid) { char str[65]; diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index cf7a2eacb..6ac014ad1 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -450,10 +450,12 @@ int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *m return(0); } -cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr) +cJSON *get_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxidstr) { - cJSON *retjson; char *retstr; - if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewayspendingwithdraws",bindtxidstr,refcoin,"","")) != 0 ) + cJSON *retjson; char *retstr; char function[64]; + if (type==0) sprintf(function,"%s","gatewayspendingwithdraws"); + else if (type==1) sprintf(function,"%s","importgatewaypendingwithdraws"); + if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,refcoin,"","")) != 0 ) { //printf("pending.(%s)\n",jprint(retjson,0)); return(retjson); @@ -466,10 +468,13 @@ cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr) return(0); } -cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr) +cJSON *get_gatewaysprocessed(int8_t type,char *refcoin,char *acname,char *bindtxidstr) { cJSON *retjson; char *retstr; - if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewaysprocessed",bindtxidstr,refcoin,"","")) != 0 ) + char function[64]; + if (type==0) sprintf(function,"%s","gatewaysprocessed"); + else if (type==1) sprintf(function,"%s","importgatewayprocessed"); + if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,refcoin,"","")) != 0 ) { //printf("pending.(%s)\n",jprint(retjson,0)); return(retjson); @@ -692,10 +697,12 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx, int M) return(0); } -bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) +bits256 gatewayspartialsign(int8_t type,char *refcoin,char *acname,bits256 txid,char *hex) { - char str[65],*retstr; cJSON *retjson; - if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 ) + char str[65],*retstr; cJSON *retjson; char function[64]; + if (type==0) sprintf(function,"%s","gatewayspartialsign"); + else if (type==1) sprintf(function,"%s","importgatewaypartialsign"); + if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,txid),refcoin,hex,"")) != 0 ) { if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson); else printf("%s\n",jstr(retjson,"error")); @@ -710,10 +717,13 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) return (zeroid); } -bits256 gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *hex) +bits256 gatewayscompletesigning(int8_t type,char *refcoin,char *acname,bits256 withtxid,char *hex) { - char str[65],*retstr; cJSON *retjson; bits256 txid; - if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),refcoin,hex,"")) != 0 ) + char str[65],*retstr; cJSON *retjson; bits256 txid; char function[64]; + + if (type==0) sprintf(function,"%s","gatewayscompletesigning"); + else if (type==1) sprintf(function,"%s","importgatewaycompletesigning"); + if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,withtxid),refcoin,hex,"")) != 0 ) { if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson); else printf("%s\n",jstr(retjson,"error")); @@ -728,10 +738,13 @@ bits256 gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char return (zeroid); } -bits256 gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid) +bits256 gatewaysmarkdone(int8_t type,char *refcoin,char *acname,bits256 withtxid) { - char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; - if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),refcoin,"","")) != 0 ) + char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; ; char function[64]; + + if (type==0) sprintf(function,"%s","gatewaysmarkdone"); + else if (type==1) sprintf(function,"%s","importgatewaymarkdone"); + if ( (retjson= get_cli(refcoin,&retstr,acname,function,bits256_str(str,withtxid),refcoin,"","")) != 0 ) { if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson); else printf("%s\n",jstr(retjson,"error")); @@ -746,10 +759,13 @@ bits256 gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid) return (zeroid); } -int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys) +int32_t get_gatewaysinfo(int8_t type,char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys) { - char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n; - if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 ) + char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n; char function[64]; + + if (type==0) sprintf(function,"%s","gatewaysinfo"); + else if (type==1) sprintf(function,"%s","importgatewayinfo"); + if ( (retjson= get_cli(refcoin,&retstr,acname,function,bindtxidstr,"","","")) != 0 ) { if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 ) { @@ -774,7 +790,6 @@ int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *M strcat(*pubkeys,temp); } } - else printf("%s != %s\n",oracle,oraclestr); free_json(retjson); } else if ( retstr != 0 ) @@ -851,7 +866,7 @@ int32_t markerexists(char *refcoin,char *acname,char *coinaddr) } -void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N) +void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N) { // check queue to prevent duplicate // check KMD chain and mempool for txidaddr @@ -864,7 +879,7 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,withdrawtxid,lasttxid,completetxid; int64_t satoshis; memset(&zeroid,0,sizeof(zeroid)); - if ( (retjson= get_gatewayspending(refcoin,acname,bindtxidstr)) != 0 ) + if ( (retjson= get_gatewayspending(type,refcoin,acname,bindtxidstr)) != 0 ) { if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 ) { @@ -888,7 +903,7 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t { if ( (clijson=addsignature(refcoin,"",rawtx,M)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0) { - txid=gatewayscompletesigning(refcoin,acname,withdrawtxid,jstr(clijson,"hex")); + txid=gatewayscompletesigning(type,refcoin,acname,withdrawtxid,jstr(clijson,"hex")); if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s 1of1\n",bits256_str(str,withdrawtxid)); else fprintf(stderr,"### SIGNING error broadcasting tx on %s",acname); free_json(clijson); @@ -910,13 +925,13 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t { if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) { - txid=gatewayscompletesigning(refcoin,acname,lasttxid,jstr(clijson,"hex")); + txid=gatewayscompletesigning(type,refcoin,acname,lasttxid,jstr(clijson,"hex")); if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %dof%d\n",bits256_str(str,withdrawtxid),K+1,N); else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname); } else if ( jint(clijson,"partialtx") != 0 ) { - txid=gatewayspartialsign(refcoin,acname,lasttxid,jstr(clijson,"hex")); + txid=gatewayspartialsign(type,refcoin,acname,lasttxid,jstr(clijson,"hex")); if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %d/%dof%d\n",bits256_str(str,withdrawtxid),K+1,M,N); else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname); } @@ -932,7 +947,7 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t } free_json(retjson); } - if ( (retjson= get_gatewaysprocessed(refcoin,acname,bindtxidstr)) != 0 ) + if ( (retjson= get_gatewaysprocessed(type,refcoin,acname,bindtxidstr)) != 0 ) { if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 ) { @@ -954,7 +969,7 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t { withdrawaddr = jstr(item,"withdrawaddr"); fprintf(stderr,"### WITHDRAW %.8f %s sent to %s\n",amount,refcoin,withdrawaddr); - txid=gatewaysmarkdone(refcoin,acname,completetxid); + txid=gatewaysmarkdone(type,refcoin,acname,completetxid); if (txid.txid!=zeroid.txid) fprintf(stderr,"### MARKDONE withdraw %s\n",bits256_str(str,withdrawtxid)); else fprintf(stderr,"### MARKDONE error broadcasting tx on %s\n",refcoin); } @@ -1024,7 +1039,7 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034 int32_t main(int32_t argc,char **argv) { - cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *pubkeys,*format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid; + cJSON *clijson,*clijson2,*regjson,*item; int32_t type,i,retval,M,N,n,height,prevheight = 0; char *pubkeys,*format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid; if ( argc < 6 ) { printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli]\n"); @@ -1044,8 +1059,7 @@ int32_t main(int32_t argc,char **argv) printf("only formats of L and Ihh are supported now\n"); return(-1); } - M = N = 1; - acheight = 0; + M = N = 0; refcoin[0] = 0; while ( 1 ) { @@ -1061,7 +1075,9 @@ int32_t main(int32_t argc,char **argv) exit(0); } pubkeys=0; - if ( get_gatewaysinfo(refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 ) + if ( get_gatewaysinfo(0,refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) == 0 ) type=0; + else if ( get_gatewaysinfo(1,refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) == 0 ) type=1; + else { printf("cant find bindtxid.(%s)\n",bindtxidstr); exit(0); @@ -1089,9 +1105,8 @@ int32_t main(int32_t argc,char **argv) if ( bits256_nonz(txid) != 0 ) { prevheight = height; - acheight = get_coinheight(refcoin,""); printf("%s ht.%d <- %s\n",refcoin,height,hexstr); - update_gatewayspending(refcoin,acname,bindtxidstr,M,N); + update_gatewayspending(type,refcoin,acname,bindtxidstr,M,N); } free_json(clijson2); } diff --git a/src/cc/eval.h b/src/cc/eval.h index a42bbdb2f..1324d5e21 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -56,7 +56,8 @@ EVAL(EVAL_MARMARA, 0xef) \ EVAL(EVAL_PAYMENTS, 0xf0) \ EVAL(EVAL_GATEWAYS, 0xf1) \ - EVAL(EVAL_TOKENS, 0xf2) + EVAL(EVAL_TOKENS, 0xf2) \ + EVAL(EVAL_IMPORTGATEWAY, 0xf3) \ // evalcodes 0x10 to 0x7f are reserved for cclib dynamic CC diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 3c1a49194..1039e9176 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -412,91 +412,6 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } -static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr) -{ - int32_t i,n; char destaddr[64]; - BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) - { - const CTransaction &tx = e.GetTx(); - if ( (n= tx.vout.size()) > 0 ) - { - const uint256 &txid = tx.GetHash(); - for (i=0; idata; - txid = zeroid; - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "start reverse scan " << batontxid.GetHex() << std::endl); - while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) - { - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "check " << batontxid.GetHex() << std::endl); - if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) - { - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "decoded " << batontxid.GetHex() << std::endl); - if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) - { - len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); - len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); - LOGSTREAM("gatewayscc",CCLOG_DEBUG1, stream << "found merkleht." << (int32_t)merkleht << " len." << len << " len2." << len2 << " " << hash.GetHex() << " " << mhash.GetHex() << std::endl); - if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) - { - txid = batontxid; - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "set txid" << std::endl); - return(mhash); - } - else - { - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "missing hash" << std::endl); - return(zeroid); - } - } else LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "height." << (int32_t)merkleht << " vs search ht." << (int32_t)height << std::endl); - batontxid = bhash; - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "new hash " << batontxid.GetHex() << std::endl); - } else break; - } - LOGSTREAM("gatewayscc",CCLOG_DEBUG2, stream << "end of loop\n"); - return(zeroid); -} - -int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) -{ - char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock; - std::vector > addressIndex; - CCtxidaddr(txidaddr,cointxid); - SetCCtxids(addressIndex,txidaddr); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - { - return(-1); - } - return(myIs_coinaddr_inmempoolvout(txidaddr)); -} - -/* Get the block merkle root for a proof - * IN: proofData - * OUT: merkle root - * OUT: transaction IDS - */ -uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids) -{ - CMerkleBlock merkleBlock; - if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) - return uint256(); - return merkleBlock.txn.ExtractMatches(txids); -} - int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2) { std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; @@ -737,7 +652,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & merkleroot = zeroid; for (i=m=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) @@ -1630,15 +1545,15 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) GetTokensCCaddress(cp,tokensaddr,gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)))); + return(result); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()))); + return(result); } n = msigpubkeys.size(); queueflag = 0; @@ -1717,16 +1632,16 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) gatewayspk = GetUnspendable(cp,0); _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)))); + return(result); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin) { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()))); + return(result); } n = msigpubkeys.size(); queueflag = 0; @@ -1795,16 +1710,16 @@ UniValue GatewaysExternalAddress(uint256 bindtxid,CPubKey pubkey) cp = CCinit(&C,EVAL_GATEWAYS); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)))); + return(result); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()))); + return(result); } GetCustomscriptaddress(addr,CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG,taddr,prefix,prefix2); result.push_back(Pair("result","success")); @@ -1819,16 +1734,16 @@ UniValue GatewaysDumpPrivKey(uint256 bindtxid,CKey key) cp = CCinit(&C,EVAL_GATEWAYS); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)))); + return(result); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()))); + return(result); } priv=EncodeCustomSecret(key,wiftype); @@ -1848,16 +1763,16 @@ UniValue GatewaysInfo(uint256 bindtxid) Gatewayspk = GetUnspendable(cp,0); GetTokensCCaddress(cp,gatewaystokens,Gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)))); + return(result); } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); - return(""); + result.push_back(Pair("result","error")); + result.push_back(Pair("error",strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()))); + return(result); } if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) { @@ -1866,19 +1781,17 @@ UniValue GatewaysInfo(uint256 bindtxid) depositaddr[0] = 0; if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 0 && M <= N && N > 0 ) { - if ( N > 1 ) - { - result.push_back(Pair("M",M)); - result.push_back(Pair("N",N)); - for (i=0; i -//#define LEV_INFO 0 -//#define LEV_DEBUG1 1 -//#define LOGSTREAM(category, level, logoperator) { std::ostringstream stream; logoperator; for(int i = 0; i < level; i ++) if( LogAcceptCategory( (std::string(category) + (level > 0 ? std::string("-")+std::to_string(level) : std::string("") )).c_str() ) ) LogPrintStr(stream.str()); } - -/* - * CC Eval method for import coin. - * - * This method should control every parameter of the ImportCoin transaction, since it has no signature - * to protect it from malleability. - - ##### 0xffffffff is a special CCid for single chain/dual daemon imports - */ +#include "key_io.h" +#define CODA_BURN_ADDRESS "KPrrRoPfHOnNpZZQ6laHXdQDkSQDkVHaN0V+LizLlHxz7NaA59sBAAAA" extern std::string ASSETCHAINS_SELFIMPORT; extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT; @@ -41,10 +32,97 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids); uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid); int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid); -uint8_t DecodeGatewaysBindOpRet(char *depositaddr, const CScript &scriptPubKey, std::string &coin, uint256 &tokenid, int64_t &totalsupply, uint256 &oracletxid, uint8_t &M, uint8_t &N, std::vector &pubkeys, uint8_t &taddr, uint8_t &prefix, uint8_t &prefix2); +uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype); + +char *nonportable_path(char *str) +{ + int32_t i; + for (i=0; str[i]!=0; i++) + if ( str[i] == '/' ) + str[i] = '\\'; + return(str); +} + +char *portable_path(char *str) +{ +#ifdef _WIN32 + return(nonportable_path(str)); +#else +#ifdef __PNACL + /*int32_t i,n; + if ( str[0] == '/' ) + return(str); + else + { + n = (int32_t)strlen(str); + for (i=n; i>0; i--) + str[i] = str[i-1]; + str[0] = '/'; + str[n+1] = 0; + }*/ +#endif + return(str); +#endif +} + +void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) +{ + FILE *fp; + long filesize,buflen = *allocsizep; + uint8_t *buf = *bufp; + *lenp = 0; + if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) + { + fseek(fp,0,SEEK_END); + filesize = ftell(fp); + if ( filesize == 0 ) + { + fclose(fp); + *lenp = 0; + //printf("loadfile null size.(%s)\n",fname); + return(0); + } + if ( filesize > buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +void *filestr(long *allocsizep,char *_fname) +{ + long filesize = 0; char *fname,*buf = 0; void *retptr; + *allocsizep = 0; + fname = (char *)malloc(strlen(_fname)+1); + strcpy(fname,_fname); + retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); + free(fname); + return(retptr); +} // ac_import=chain support: // encode opret for gateways import +CScript EncodeImportTxOpRet(uint32_t targetCCid, std::string coin, std::vector publishers, std::vectortxids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vectorproof, CPubKey destpub, int64_t amount) +{ + CScript opret; + opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount); + return(opret); +} + CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector publishers, std::vectortxids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vectorproof, CPubKey destpub, int64_t amount) { CScript opret; @@ -52,169 +130,132 @@ CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint2 return(opret); } -bool ImportCoinGatewaysVerify(char *refdepositaddr, uint256 oracletxid, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vectorproof, uint256 merkleroot) +CScript EncodeCodaImportTxOpRet(uint32_t targetCCid, std::string coin, std::string burntx, uint256 bindtxid, CPubKey destpub, int64_t amount) +{ + CScript opret; + opret << OP_RETURN << E_MARSHAL(ss << targetCCid << burntx << bindtxid << destpub << amount); + return(opret); +} + +cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,char const *arg3,char const *arg4,char const *arg5) +{ + char cmdstr[5000],fname[256],*jsonstr; + long fsize; + cJSON *retjson=NULL; + + sprintf(fname,"/tmp/coda.%s",arg0); + sprintf(cmdstr,"coda.exe client %s %s %s %s %s %s > %s 2>&1",arg0,arg1,arg2,arg3,arg4,arg5,fname); + *retstr = 0; + if (system(cmdstr)<0) return (retjson); + if ( (jsonstr=(char *)filestr(&fsize,fname)) != 0 ) + { + jsonstr[strlen(jsonstr)-1]='\0'; + if ( (strncmp(jsonstr,"Merkle List of transactions:",28)!=0) || (retjson= cJSON_Parse(jsonstr+29)) == 0) + *retstr=jsonstr; + else free(jsonstr); + } + return(retjson); +} + +bool ImportCoinGatewaysVerify(CTransaction oracletx, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vectorproof, uint256 merkleroot) { std::vector txids; - uint256 proofroot, hashBlock, foundtxid = zeroid; - CTransaction oracletx, burntx; + uint256 proofroot; std::string name, description, format; - char destaddr[64], destpubaddr[64], claimaddr[64]; int32_t i, numvouts; - int64_t nValue = 0; - if (myGetTransaction(oracletxid, oracletx, hashBlock) == 0 || (numvouts = oracletx.vout.size()) <= 0) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify can't find oracletxid=" << oracletxid.GetHex() << std::endl); - return false; - } if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin) { LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl); return false; } - proofroot = BitcoinGetProofMerkleRoot(proof, txids); - if (proofroot != merkleroot) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl); - return false; - } - - // check the burntxid is in the proof: - if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify invalid proof for this burntxid=" << burntxid.GetHex() << std::endl); - return false; - } - - /* - if (DecodeHexTx(burntx, rawburntx) != 0) - { - Getscriptaddress(claimaddr, burntx.vout[claimvout].scriptPubKey); - Getscriptaddress(destpubaddr, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); - if (strcmp(claimaddr, destpubaddr) == 0) - { - for (i = 0; iproof, std::string rawburntx, int32_t ivout, uint256 burntxid) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction burntx, bindtx; - CPubKey mypk, gatewayspk; - uint256 oracletxid, merkleroot, mhash, hashBlock, tokenid, txid; - int64_t totalsupply; - int32_t i, m, n, numvouts; - uint8_t M, N, taddr, prefix, prefix2; - std::string coin; - struct CCcontract_info *cp, C; - std::vector pubkeys, publishers; - std::vectortxids; - char depositaddr[64], txidaddr[64]; +// std::string MakeGatewaysImportTx(uint64_t txfee, uint256 oracletxid, int32_t height, std::string refcoin, std::vector proof, std::string rawburntx, int32_t ivout, uint256 burntxid,std::string destaddr) +// { +// CMutableTransaction burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); +// CTransaction oracletx,regtx; CPubKey regpk; +// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts; +// std::string name,desc,format; std::vector vouts; +// std::vector pubkeys; std::vectortxids; +// char markeraddr[64]; int64_t datafee; +// std::vector > unspentOutputs; - cp = CCinit(&C, EVAL_GATEWAYS); - /*if (txfee == 0) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cp, 0); */ - - if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx)) - return std::string(""); - - CAmount amount = GetCoinImportValue(burntx); // equal to int64_t - - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl); - - if (GetTransaction(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find bindtxid=" << bindtxid.GetHex() << std::endl); - return(""); - } -/* if (DecodeGatewaysBindOpRet(depositaddr, bindtx.vout[numvouts - 1].scriptPubKey, coin, tokenid, totalsupply, oracletxid, M, N, pubkeys, taddr, prefix, prefix2) != 'B' || refcoin != coin) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid coin - bindtxid=" << bindtxid.GetHex() << " coin=" << coin.c_str() << std::endl); - return(""); - } eliminate link err */ - n = (int32_t)pubkeys.size(); - merkleroot = zeroid; - for (i = m = 0; i < n; i++) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl); - if ((mhash = GatewaysReverseScan(txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) - { - if (merkleroot == zeroid) - merkleroot = mhash, m = 1; - else if (mhash == merkleroot) - m ++; - publishers.push_back(pubkeys[i]); - txids.push_back(txid); - } - } - - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl); - if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << coin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); - return(""); - } - if (GatewaysCointxidExists(cp, burntxid) != 0) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " already exists" << std::endl); - return(""); - } - if (!ImportCoinGatewaysVerify(depositaddr, oracletxid, ivout, coin, burntxid, rawburntx, proof, merkleroot)) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx could not validate burntx, txid=" << burntxid.GetHex() << std::endl); - return(""); - } - - - std::vector leaftxids; - BitcoinGetProofMerkleRoot(proof, leaftxids); - MerkleBranch newBranch(0, leaftxids); - TxProof txProof = std::make_pair(burntxid, newBranch); - - std::vector vouts; - - - - return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts))); - - /*if (AddNormalinputs(mtx, mypk, 3 * txfee, 4) > 0) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, destpub)); - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr, burntxid))) << OP_CHECKSIG)); - return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeGatewaysImportTxOpRet(0xFFFFFFFF, coin, bindtxid, publishers, txids, height, burntxid, ivout, rawburntx, proof, destpub, amount))); - } - LOGSTREAM("importcoin", LEV_INFO, stream << "MakeGatewaysImportTx coud not find normal imputs" << std::endl);*/ - return(""); -} +// if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx)) +// return std::string(""); +// CAmount amount = GetCoinImportValue(burntx); // equal to int64_t +// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl); +// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0) +// { +// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find oracletxid=" << oracletxid.GetHex() << std::endl); +// return(""); +// } +// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C') +// { +// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl); +// return(""); +// } +// if (name!=refcoin || format!="Ihh") +// { +// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl); +// return(""); +// } +// CCtxidaddr(markeraddr,oracletxid); +// SetCCunspents(unspentOutputs,markeraddr); +// for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) +// { +// txid = it->first.txhash; +// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0 +// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid ) +// { +// pubkeys.push_back(regpk); +// n++; +// } +// } +// merkleroot = zeroid; +// for (i = m = 0; i < n; i++) +// { +// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl); +// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) +// { +// if (merkleroot == zeroid) +// merkleroot = mhash, m = 1; +// else if (mhash == merkleroot) +// m ++; +// txids.push_back(txid); +// } +// } +// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl); +// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot +// { +// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); +// return(""); +// } +// proofroot = BitcoinGetProofMerkleRoot(proof, txids); +// if (proofroot != merkleroot) +// { +// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl); +// return(""); +// } +// // check the burntxid is in the proof: +// if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) { +// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid proof for this burntxid=" << burntxid.GetHex() << std::endl); +// return(""); +// } +// burntx.vout.push_back(MakeBurnOutput(amount,0xffffffff,refcoin,vouts,proof,oracletxid,height)); +// std::vector leaftxids; +// BitcoinGetProofMerkleRoot(proof, leaftxids); +// MerkleBranch newBranch(0, leaftxids); +// TxProof txProof = std::make_pair(burntxid, newBranch); +// CTxDestination dest = DecodeDestination(destaddr.c_str()); +// CScript scriptPubKey = GetScriptForDestination(dest); +// vouts.push_back(CTxOut(amount,scriptPubKey)); +// return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts))); +// } // makes source tx for self import tx std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx) @@ -332,6 +373,90 @@ int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript return 0; } +// make import tx with burntx and dual daemon +std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector vouts) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()),burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; uint256 codaburntxid; std::vector dummyproof; + int32_t i,numvouts,n,m; std::string coin,error; struct CCcontract_info *cp, C; + cJSON *result,*tmp,*tmp1; unsigned char hash[SHA256_DIGEST_LENGTH+1]; + char out[SHA256_DIGEST_LENGTH*2+1],*retstr,*destaddr,*receiver; TxProof txProof; uint64_t amount; + + cp = CCinit(&C, EVAL_GATEWAYS); + if (txfee == 0) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, receipt.c_str(), receipt.size()); + SHA256_Final(hash, &sha256); + for(i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + sprintf(out + (i * 2), "%02x", hash[i]); + } + out[65]='\0'; + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: hash=" << out << std::endl); + codaburntxid.SetHex(out); + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receipt=" << receipt << " codaburntxid=" << codaburntxid.GetHex().data() << " amount=" << (double)amount / COIN << std::endl); + result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),""); + if (result==0) + { + if (retstr!=0) + { + CCerror=std::string("CodaRPC: ")+retstr; + free(retstr); + } + return(""); + } + else + { + if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))!=0 && (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))!=0 && + (receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))!=0 && (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))!=0) + { + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receiver=" << receiver << " destaddr=" << destaddr << " amount=" << amount << std::endl); + if (strcmp(receiver,CODA_BURN_ADDRESS)!=0) + { + CCerror="MakeCodaImportTx: invalid burn address, coins do not go to predefined burn address - "; + CCerror+=CODA_BURN_ADDRESS; + LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); + free(result); + return(""); + } + CTxDestination dest = DecodeDestination(destaddr); + CScript scriptPubKey = GetScriptForDestination(dest); + if (vouts[0]!=CTxOut(amount*COIN,scriptPubKey)) + { + CCerror="MakeCodaImportTx: invalid destination address, burnTx memo!=importTx destination"; + LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); + free(result); + return(""); + } + if (amount*COIN!=vouts[0].nValue) + { + CCerror="MakeCodaImportTx: invalid amount, burnTx amount!=importTx amount"; + LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); + free(result); + return(""); + } + burntx.vin.push_back(CTxIn(codaburntxid,0,CScript())); + burntx.vout.push_back(MakeBurnOutput(amount*COIN,0xffffffff,"CODA",vouts,dummyproof,srcaddr,receipt)); + return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof,burntx,vouts))); + } + else + { + CCerror="MakeCodaImportTx: invalid Coda burn tx"; + LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); + free(result); + return(""); + } + + } + CCerror="MakeCodaImportTx: error fetching Coda tx"; + LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); + free(result); + return(""); +} + // use proof from the above functions to validate the import int32_t CheckBEAMimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) @@ -340,17 +465,135 @@ int32_t CheckBEAMimport(TxProof proof,std::vector rawproof,CTransaction return(-1); } -int32_t CheckCODAimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) +int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector payouts,std::string srcaddr,std::string receipt) { + cJSON *result,*tmp,*tmp1; char *retstr,out[SHA256_DIGEST_LENGTH*2+1]; unsigned char hash[SHA256_DIGEST_LENGTH+1]; int i,n,m; + SHA256_CTX sha256; uint256 codaburntxid; char *destaddr,*receiver; uint64_t amount; + // check with dual-CODA daemon via ASSETCHAINS_CODAPORT for validity of burnTx - return(-1); + SHA256_Init(&sha256); + SHA256_Update(&sha256, receipt.c_str(), receipt.size()); + SHA256_Final(hash, &sha256); + for(i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + sprintf(out + (i * 2), "%02x", hash[i]); + } + out[65]='\0'; + codaburntxid.SetHex(out); + result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),""); + if (result==0) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CodaRPC error: " << retstr << std::endl); + free(retstr); + return (-1); + } + else + { + if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))==0 || (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))==0 || + (receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))==0 || (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))==0) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid Coda burn tx" << jprint(result,1) << std::endl); + free(result); + return (-1); + } + CTxDestination dest = DecodeDestination(destaddr); + CScript scriptPubKey = GetScriptForDestination(dest); + if (payouts[0]!=CTxOut(amount*COIN,scriptPubKey)); + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "Destination address in burn tx does not match destination in import tx" << std::endl); + free(result); + return (-1); + } + if (strcmp(receiver,CODA_BURN_ADDRESS)!=0) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid burn address " << jstr(tmp1,(char *)"receiver") << std::endl); + free(result); + return (-1); + } + if (amount*COIN!=payouts[0].nValue) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "Burn amount and import amount not matching, " << j64bits(tmp,(char *)"amount") << " - " << payouts[0].nValue/COIN << std::endl); + free(result); + return (-1); + } + if (burnTx.vin[0].prevout.hash!=codaburntxid || importTx.vin[0].prevout.hash!=burnTx.GetHash()) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid import/burn tx vin" << std::endl); + free(result); + return (-1); + } + free(result); + } + return(0); } -int32_t CheckGATEWAYimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) +int32_t CheckGATEWAYimport(CTransaction importTx,CTransaction burnTx,std::string refcoin,std::vector proof, + uint256 bindtxid,std::vector publishers,std::vector txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub) { + // CTransaction oracletx,regtx; CPubKey regpk; + // uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts; + // std::string name,desc,format; std::vector vouts; + // std::vector pubkeys; std::vectortxids; + // char markeraddr[64]; int64_t datafee; + // std::vector > unspentOutputs; // ASSETCHAINS_SELFIMPORT is coin // check for valid burn from external coin blockchain and if valid return(0); - return(-1); + // if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0) + // { + // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl); + // return(-1); + // } + // if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C') + // { + // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl); + // return(-1); + // } + // if (name!=refcoin || format!="Ihh") + // { + // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl); + // return(-1); + // } + // CCtxidaddr(markeraddr,oracletxid); + // SetCCunspents(unspentOutputs,markeraddr); + // for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + // { + // txid = it->first.txhash; + // if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0 + // && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid ) + // { + // pubkeys.push_back(regpk); + // n++; + // } + // } + // merkleroot = zeroid; + // for (i = m = 0; i < n; i++) + // { + // if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) + // { + // if (merkleroot == zeroid) + // merkleroot = mhash, m = 1; + // else if (mhash == merkleroot) + // m ++; + // txids.push_back(txid); + // } + // } + // if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot + // { + // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); + // return(-1); + // } + // proofroot = BitcoinGetProofMerkleRoot(proof, txids); + // if (proofroot != merkleroot) + // { + // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl); + // return(-1); + // } + // // check the burntxid is in the proof: + // if (std::find(txids.begin(), txids.end(), burnTx.GetHash()) == txids.end()) { + // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid proof for this burntxid=" << burnTx.GetHash().GetHex() << std::endl); + // return(-1); + // } + return(0); } int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) @@ -404,10 +647,20 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti return(0); } +/* + * CC Eval method for import coin. + * + * This method should control every parameter of the ImportCoin transaction, since it has no signature + * to protect it from malleability. + + ##### 0xffffffff is a special CCid for single chain/dual daemon imports + */ bool Eval::ImportCoin(const std::vector params,const CTransaction &importTx,unsigned int nIn) { - TxProof proof; CTransaction burnTx; std::vector payouts; uint64_t txfee = 10000; - uint32_t targetCcid; std::string targetSymbol; uint256 payoutsHash; std::vector rawproof; + TxProof proof; CTransaction burnTx; std::vector payouts; uint64_t txfee = 10000; int32_t height,burnvout; std::vector publishers; + uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid; std::vector rawproof; + std::vector txids; CPubKey destpub; + if ( importTx.vout.size() < 2 ) return Invalid("too-few-vouts"); // params @@ -458,7 +711,7 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo { if ( ASSETCHAINS_CODAPORT == 0 ) return Invalid("CODA-import-without-port"); - else if ( CheckCODAimport(proof,rawproof,burnTx,payouts) < 0 ) + else if ( UnmarshalBurnTx(burnTx,srcaddr,receipt)==0 || CheckCODAimport(importTx,burnTx,payouts,srcaddr,receipt) < 0 ) return Invalid("CODA-import-failure"); } else if ( targetSymbol == "PUBKEY" ) @@ -472,7 +725,7 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo { if ( targetSymbol != ASSETCHAINS_SELFIMPORT ) return Invalid("invalid-gateway-import-coin"); - else if ( CheckGATEWAYimport(proof,rawproof,burnTx,payouts) < 0 ) + else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub) < 0 ) return Invalid("GATEWAY-import-failure"); } } diff --git a/src/cc/importgateway.cpp b/src/cc/importgateway.cpp new file mode 100644 index 000000000..4e943b472 --- /dev/null +++ b/src/cc/importgateway.cpp @@ -0,0 +1,1292 @@ +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "CCImportGateway.h" +#include "key_io.h" +#include "../importcoin.h" + +// start of consensus code + +#define KMD_PUBTYPE 60 +#define KMD_P2SHTYPE 85 +#define KMD_WIFTYPE 188 +#define KMD_TADDR 0 +#define CC_MARKER_VALUE 10000 + +CScript EncodeImportGatewayBindOpRet(uint8_t funcid,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector importgatewaypubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2,uint8_t wiftype) +{ + CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << oracletxid << M << N << importgatewaypubkeys << taddr << prefix << prefix2 << wiftype); + return(opret); +} + +uint8_t DecodeImportGatewayBindOpRet(char *burnaddr,const CScript &scriptPubKey,std::string &coin,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &importgatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype) +{ + std::vector vopret; uint8_t *script,e,f; std::vector pubkeys; + + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + burnaddr[0] = 0; + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> oracletxid; ss >> M; ss >> N; ss >> importgatewaypubkeys; ss >> taddr; ss >> prefix; ss >> prefix2; ss >> wiftype) != 0 ) + { + if ( prefix == KMD_PUBTYPE && prefix2 == KMD_P2SHTYPE ) + { + if ( N > 1 ) + { + strcpy(burnaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,importgatewaypubkeys))).ToString().c_str()); + LOGSTREAM("importgateway", CCLOG_DEBUG1, stream << "f." << f << " M." << (int)M << " of N." << (int)N << " size." << (int32_t)importgatewaypubkeys.size() << " -> " << burnaddr << std::endl); + } else Getscriptaddress(burnaddr,CScript() << ParseHex(HexStr(importgatewaypubkeys[0])) << OP_CHECKSIG); + } + else + { + if ( N > 1 ) strcpy(burnaddr,CCustomBitcoinAddress(CScriptID(GetScriptForMultisig(M,importgatewaypubkeys)),taddr,prefix,prefix2).ToString().c_str()); + else GetCustomscriptaddress(burnaddr,CScript() << ParseHex(HexStr(importgatewaypubkeys[0])) << OP_CHECKSIG,taddr,prefix,prefix2); + } + return(f); + } else LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "error decoding bind opret" << std::endl); + return(0); +} + +CScript EncodeImportGatewayDepositOpRet(uint8_t funcid,uint256 bindtxid,std::string refcoin,std::vector publishers,std::vectortxids,int32_t height,uint256 burntxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) +{ + CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << bindtxid << publishers << txids << height << burntxid << claimvout << deposithex << proof << destpub << amount); + return(opret); +} + +uint8_t DecodeImportGatewayDepositOpRet(const CScript &scriptPubKey,uint256 &bindtxid,std::string &refcoin,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &burntxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) +{ + 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 >> refcoin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> burntxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeImportGatewayWithdrawOpRet(uint8_t funcid,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) +{ + CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << withdrawpub << amount); + return(opret); +} + +uint8_t DecodeImportGatewayWithdrawOpRet(const CScript &scriptPubKey,uint256 &bindtxid,std::string &refcoin,CPubKey &withdrawpub,int64_t &amount) +{ + 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 >> bindtxid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeImportGatewayPartialOpRet(uint8_t funcid, uint256 withdrawtxid,std::string refcoin,uint8_t K, CPubKey signerpk,std::string hex) +{ + CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << K << signerpk << hex); + return(opret); +} + +uint8_t DecodeImportGatewayPartialOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,uint8_t &K,CPubKey &signerpk,std::string &hex) +{ + 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 >> withdrawtxid; ss >> refcoin; ss >> K; ss >> signerpk; ss >> hex) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeImportGatewayCompleteSigningOpRet(uint8_t funcid,uint256 withdrawtxid,std::string refcoin,uint8_t K,std::string hex) +{ + CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << K << hex); + return(opret); +} + +uint8_t DecodeImportGatewayCompleteSigningOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,uint8_t &K,std::string &hex) +{ + 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 >> withdrawtxid; ss >> refcoin; ss >> K; ss >> hex) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeImportGatewayMarkDoneOpRet(uint8_t funcid,uint256 withdrawtxid,std::string refcoin,uint256 completetxid) +{ + CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; + + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << completetxid); + return(opret); +} + +uint8_t DecodeImportGatewayMarkDoneOpRet(const CScript &scriptPubKey, uint256 &withdrawtxid, std::string &refcoin, uint256 &completetxid) +{ + 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 >> withdrawtxid; ss >> refcoin; ss >> completetxid;) != 0 ) + { + return(f); + } + return(0); +} + +uint8_t DecodeImportGatewayOpRet(const CScript &scriptPubKey) +{ + std::vector vopret; uint8_t *script,e,f; + + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && script[0] == EVAL_IMPORTGATEWAY) + { + f=script[1]; + if (f == 'B' || f == 'D' || f == 'C' || f == 'W' || f == 'P' || f == 'S' || f == 'M') + return(f); + } + return(0); +} + +int64_t IsImportGatewayvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +{ + char destaddr[64]; + + if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) + return(tx.vout[v].nValue); + } + return(0); +} + +int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 burntxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2) +{ + std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; + char destaddr[64],destpubaddr[64],claimaddr[64]; int32_t i,numvouts; int64_t nValue = 0; + + if ( myGetTransaction(oracletxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify cant find oracletxid " << oracletxid.GetHex() << std::endl); + return(0); + } + if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin ) + { + LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify mismatched oracle name " << name << " != " << refcoin << std::endl); + return(0); + } + proofroot = BitcoinGetProofMerkleRoot(proof,txids); + if ( proofroot != merkleroot ) + { + LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify mismatched merkleroot " << proofroot.GetHex() << " != " << merkleroot.GetHex() << std::endl); + return(0); + } + if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) + { + LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify invalid proof for this burntxid" << std::endl); + return 0; + } + if ( DecodeHexTx(tx,deposithex) != 0 ) + { + GetCustomscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey,taddr,prefix,prefix2); + GetCustomscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG,taddr,prefix,prefix2); + if ( strcmp(claimaddr,destpubaddr) == 0 ) + { + for (i=0; i publishers; std::vectortxids; uint256 bindtxid,burntxid; std::vector proof; CPubKey claimpubkey; + if ( (numvouts= tx.vout.size()) > 0 ) + { + if ( DecodeImportGatewayDepositOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,publishers,txids,height,burntxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) + { + return(amount); + } + } + return(0); +} + +int32_t ImportGatewayBindExists(struct CCcontract_info *cp,CPubKey importgatewaypk,std::string refcoin) +{ + char markeraddr[64],burnaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; + uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; CTransaction tx; + std::vector > addressIndex; + + _GetCCaddress(markeraddr,EVAL_IMPORTGATEWAY,importgatewaypk); + SetCCtxids(addressIndex,markeraddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + if ( myGetTransaction(it->first.txhash,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 && DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey)=='B' ) + { + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) == 'B' ) + { + if ( coin == refcoin ) + { + LOGSTREAM("importgateway",CCLOG_INFO, stream << "trying to bind an existing import for coin" << std::endl); + return(1); + } + } + } + } + BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) + { + const CTransaction &txmempool = e.GetTx(); + const uint256 &hash = txmempool.GetHash(); + + if ((numvouts=txmempool.vout.size()) > 0 && DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey)=='B') + if (DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) == 'B') + return(1); + } + + return(0); +} + +bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn) +{ + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks,height,claimvout; bool retval; uint8_t funcid,hash[32],K,M,N,taddr,prefix,prefix2,wiftype; + char str[65],destaddr[65],burnaddr[65],importgatewayaddr[65],validationError[512]; + std::vector txids; std::vector pubkeys,publishers,tmppublishers; std::vector proof; int64_t amount,tmpamount; + uint256 hashblock,txid,bindtxid,deposittxid,withdrawtxid,completetxid,tmptokenid,oracletxid,bindtokenid,burntxid,tmptxid,merkleroot,mhash; CTransaction bindtx,tmptx; + std::string refcoin,tmprefcoin,hex,name,description,format; CPubKey pubkey,tmppubkey,importgatewaypk; + + return (true); + numvins = tx.vin.size(); + numvouts = tx.vout.size(); + preventCCvins = preventCCvouts = -1; + if ( numvouts < 1 ) + return eval->Invalid("no vouts"); + else + { + //LogPrint("importgateway-1","check amounts\n"); + // if ( ImportGatewayExactAmounts(cp,eval,tx,1,10000) == false ) + // { + // return eval->Invalid("invalid inputs vs. outputs!"); + // } + // else + // { + importgatewaypk = GetUnspendable(cp,0); + GetCCaddress(cp, importgatewayaddr, importgatewaypk); + if ( (funcid = DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey)) != 0) + { + switch ( funcid ) + { + case 'B': + //vin.0: normal input + //vout.0: CC vout marker + //vout.n-1: opreturn - 'B' coin oracletxid M N pubkeys taddr prefix prefix2 wiftype + return eval->Invalid("unexpected ImportGatewayValidate for gatewaysbind!"); + break; + case 'W': + //vin.0: normal input + //vin.1: CC input of tokens + //vout.0: CC vout marker to gateways CC address + //vout.1: CC vout of gateways tokens back to gateways tokens CC address + //vout.2: CC vout change of tokens back to owners pubkey (if any) + //vout.n-1: opreturn - 'W' bindtxid refcoin withdrawpub amount + return eval->Invalid("unexpected ImportGatewayValidate for gatewaysWithdraw!"); + break; + case 'P': + //vin.0: normal input + //vin.1: CC input of marker from previous tx (withdraw or partialsing) + //vout.0: CC vout marker to gateways CC address + //vout.n-1: opreturn - 'P' withdrawtxid refcoin number_of_signs mypk hex + if ((numvouts=tx.vout.size()) > 0 && DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,refcoin,K,pubkey,hex)!='P') + return eval->Invalid("invalid gatewaysPartialSign OP_RETURN data!"); + else if (myGetTransaction(withdrawtxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid withdraw txid!"); + else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,tmprefcoin,pubkey,amount)!='W') + return eval->Invalid("invalid gatewayswithdraw OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different than in bind tx"); + else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for gatewaysWithdraw!"); + else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for gatewaysWithdraw!"); + else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) + return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); + else if ( ConstrainVout(tmptx.vout[1],1,importgatewayaddr,amount)==0) + return eval->Invalid("invalid tokens to gateways vout for gatewaysWithdraw!"); + else if (tmptx.vout[1].nValue!=amount) + return eval->Invalid("amount in opret not matching tx tokens amount!"); + else if (komodo_txnotarizedconfirmed(withdrawtxid) == false) + return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarised)!"); + else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid gatewaysbind txid!"); + else if ((numvouts=tmptx.vout.size()) < 1 || DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,tmprefcoin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B') + return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different than in bind tx"); + else if (komodo_txnotarizedconfirmed(bindtxid) == false) + return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); + else if (IsCCInput(tx.vin[0].scriptSig) != 0) + return eval->Invalid("vin.0 is normal for gatewayspartialsign!"); + else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin.1 is CC marker for gatewayspartialsign or invalid marker amount!"); + else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 ) + return eval->Invalid("vout.0 invalid marker for gatewayspartialsign!"); + else if (K>M) + return eval->Invalid("invalid number of signs!"); + break; + case 'S': + //vin.0: normal input + //vin.1: CC input of marker from previous tx (withdraw or partialsing) + //vout.0: CC vout marker to gateways CC address + //vout.n-1: opreturn - 'S' withdrawtxid refcoin hex + if ((numvouts=tx.vout.size()) > 0 && DecodeImportGatewayCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,refcoin,K,hex)!='S') + return eval->Invalid("invalid gatewayscompletesigning OP_RETURN data!"); + else if (myGetTransaction(withdrawtxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid withdraw txid!"); + else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,tmprefcoin,pubkey,amount)!='W') + return eval->Invalid("invalid gatewayswithdraw OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different than in bind tx"); + else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for gatewaysWithdraw!"); + else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for gatewaysWithdraw!"); + else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) + return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); + else if ( ConstrainVout(tmptx.vout[1],1,importgatewayaddr,amount)==0) + return eval->Invalid("invalid tokens to gateways vout for gatewaysWithdraw!"); + else if (tmptx.vout[1].nValue!=amount) + return eval->Invalid("amount in opret not matching tx tokens amount!"); + else if (komodo_txnotarizedconfirmed(withdrawtxid) == false) + return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarised)!"); + else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid gatewaysbind txid!"); + else if ((numvouts=tmptx.vout.size()) < 1 || DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,tmprefcoin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B') + return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different than in bind tx"); + else if (komodo_txnotarizedconfirmed(bindtxid) == false) + return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); + else if (IsCCInput(tx.vin[0].scriptSig) != 0) + return eval->Invalid("vin.0 is normal for gatewayscompletesigning!"); + else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin.1 is CC marker for gatewayscompletesigning or invalid marker amount!"); + else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 ) + return eval->Invalid("vout.0 invalid marker for gatewayscompletesigning!"); + else if (KInvalid("invalid number of signs!"); + break; + case 'M': + //vin.0: normal input + //vin.1: CC input of gatewayscompletesigning tx marker to gateways CC address + //vout.0: opreturn - 'M' withdrawtxid refcoin completetxid + if ((numvouts=tx.vout.size()) > 0 && DecodeImportGatewayMarkDoneOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,refcoin,completetxid)!='M') + return eval->Invalid("invalid gatewaysmarkdone OP_RETURN data!"); + else if (myGetTransaction(completetxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid gatewayscompletesigning txid!"); + else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayCompleteSigningOpRet(tmptx.vout[numvouts-1].scriptPubKey,withdrawtxid,tmprefcoin,K,hex)!='S') + return eval->Invalid("invalid gatewayscompletesigning OP_RETURN data!"); + else if (komodo_txnotarizedconfirmed(completetxid) == false) + return eval->Invalid("gatewayscompletesigning tx is not yet confirmed(notarised)!"); + else if (myGetTransaction(withdrawtxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid withdraw txid!"); + else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,tmprefcoin,pubkey,amount)!='W') + return eval->Invalid("invalid gatewayswithdraw OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different than in bind tx"); + else if (komodo_txnotarizedconfirmed(withdrawtxid) == false) + return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarised)!"); + else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) + return eval->Invalid("invalid gatewaysbind txid!"); + else if ((numvouts=tmptx.vout.size()) < 1 || DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,tmprefcoin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B') + return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different than in bind tx"); + else if (komodo_txnotarizedconfirmed(bindtxid) == false) + return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); + else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for gatewaysmarkdone!"); + else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin.1 is CC marker for gatewaysmarkdone or invalid marker amount!"); + else if (KInvalid("invalid number of signs!"); + break; + } + } + retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); + if ( retval != 0 ) + LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGateway tx validated" << std::endl); + else fprintf(stderr,"ImportGateway tx invalid\n"); + return(retval); + // } + } +} +// end of consensus code + +// helper functions for rpc calls in rpcwallet.cpp + +std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction oracletx; uint8_t taddr,prefix,prefix2,wiftype; CPubKey mypk,importgatewaypk; CScript opret; uint256 hashBlock; + struct CCcontract_info *cp,*cpTokens,C,CTokens; std::string name,description,format; int32_t i,numvouts; + char destaddr[64],coinaddr[64],myTokenCCaddr[64],str[65],*fstr; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + cpTokens = CCinit(&CTokens,EVAL_TOKENS); + if (coin=="KMD") + { + prefix = KMD_PUBTYPE; + prefix2 = KMD_P2SHTYPE; + wiftype = KMD_WIFTYPE; + taddr = KMD_TADDR; + } + else + { + prefix = p1; + prefix2 = p2; + wiftype = p3; + taddr = p4; + LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "set prefix " << prefix << ", prefix2 " << prefix2 << ", wiftype " << wiftype << ", taddr " << taddr << " for " << coin << std::endl); + } + if ( N == 0 || N > 15 || M > N ) + { + CCerror = strprintf("illegal M.%d or N.%d",M,N); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( pubkeys.size() != N ) + { + CCerror = strprintf("M.%d N.%d but pubkeys[%d]",M,N,(int32_t)pubkeys.size()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + for (i=0; i 0 ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CC_MARKER_VALUE,importgatewaypk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayBindOpRet('B',coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype))); + } + CCerror = strprintf("cant find enough inputs"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); +} + +std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t claimvout,std::string rawburntx,std::vectorproof,CPubKey destpub) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()), burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction bindtx; CPubKey mypk; uint256 oracletxid,merkleroot,mhash,hashBlock,txid; std::vector vouts; + int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::string coin; struct CCcontract_info *cp,C; + std::vector pubkeys,publishers; std::vector txids; char str[128],burnaddr[64]; int64_t amount; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx)) + { + return std::string(""); + } + amount=burntx.vout[0].nValue; + LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "ImportGatewayDeposit ht." << height << " " << refcoin << " " << (double)amount/COIN << " numpks." << (int32_t)pubkeys.size() << std::endl); + if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) + { + CCerror = strprintf("invalid coin - bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if (komodo_txnotarizedconfirmed(bindtxid)==false) + { + CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + n = (int32_t)pubkeys.size(); + merkleroot = zeroid; + for (i=m=0; i leaftxids; + BitcoinGetProofMerkleRoot(proof, leaftxids); + MerkleBranch newBranch(0, leaftxids); + TxProof txProof = std::make_pair(burntxid, newBranch); + return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts))); +} + +std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction tx; CPubKey mypk,importgatewaypk,signerpk; uint256 txid,hashBlock,oracletxid,tmptokenid,tmpbindtxid,withdrawtxid; int32_t vout,numvouts; + int64_t nValue,inputs,CCchange=0,tmpamount; uint8_t funcid,K,M,N,taddr,prefix,prefix2,wiftype; std::string coin,hex; + std::vector msigpubkeys; char burnaddr[64],str[65],coinaddr[64]; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + importgatewaypk = GetUnspendable(cp, 0); + + if( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || coin != refcoin ) + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if (komodo_txnotarizedconfirmed(bindtxid)==false) + { + CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,importgatewaypk); + 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; + nValue = (int64_t)it->second.satoshis; + K=0; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P')) + { + if (funcid=='W' && DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,tmpamount)=='W' + && refcoin==coin && tmpbindtxid==bindtxid) + { + CCerror = strprintf("unable to create withdraw, another withdraw pending"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + + else if (funcid=='P' && DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)=='P' && + GetTransaction(withdrawtxid,tx,hashBlock,false)!=0 && (numvouts=tx.vout.size())>0 && DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,tmpamount)=='W' + && refcoin==coin && tmpbindtxid==bindtxid) + { + CCerror = strprintf("unable to create withdraw, another withdraw pending"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + } + } + if( AddNormalinputs(mtx, mypk, txfee+CC_MARKER_VALUE+amount, 64) > 0 ) + { + mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,CC_MARKER_VALUE,importgatewaypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,amount,importgatewaypk)); + return(FinalizeCCTx(0, cp, mtx, mypk, txfee,EncodeImportGatewayWithdrawOpRet('W',bindtxid,refcoin,withdrawpub,amount))); + } + CCerror = strprintf("cant find enough normal inputs"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); +} + +std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,withdrawpub,signerpk,importgatewaypk; struct CCcontract_info *cp,C; CTransaction tx,tmptx; + std::vector > unspentOutputs; char funcid,str[65],burnaddr[64]; + int32_t numvouts; uint256 withdrawtxid,hashBlock,bindtxid,tokenid,oracletxid; std::string coin,tmphex; int64_t amount; + uint8_t K=0,M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + importgatewaypk = GetUnspendable(cp,0); + if (GetTransaction(lasttxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0 + || (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) + { + CCerror = strprintf("can't find last tx %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if (funcid=='W') + { + withdrawtxid=lasttxid; + if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("invalid withdraw tx %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) + { + CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' + || refcoin!=coin) + { + CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + } + else if (funcid=='P') + { + if (DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) + { + CCerror = strprintf("cannot decode partialsign tx opret %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(withdrawtxid,tmptx,hashBlock,false)==0 || (numvouts= tmptx.vout.size())<=0) + { + CCerror = strprintf("can't find withdraw tx %s",uint256_str(str,withdrawtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' + || refcoin!=coin) + { + CCerror = strprintf("invalid withdraw tx %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) + { + CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' + || refcoin!=coin) + { + CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + } + if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + { + mtx.vin.push_back(CTxIn(tx.GetHash(),0,CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,CC_MARKER_VALUE,importgatewaypk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayPartialOpRet('P',withdrawtxid,refcoin,K+1,mypk,hex))); + } + CCerror = strprintf("error adding funds for partialsign"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); +} + +std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,importgatewaypk,signerpk,withdrawpub; struct CCcontract_info *cp,C; char funcid,str[65],burnaddr[64]; int64_t amount; + std::string coin,tmphex; CTransaction tx,tmptx; uint256 withdrawtxid,hashBlock,tokenid,bindtxid,oracletxid; int32_t numvouts; + uint8_t K=0,M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + mypk = pubkey2pk(Mypubkey()); + importgatewaypk = GetUnspendable(cp,0); + if ( txfee == 0 ) + txfee = 10000; + if (GetTransaction(lasttxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0 + || (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) + { + CCerror = strprintf("invalid last txid %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if (funcid=='W') + { + withdrawtxid=lasttxid; + if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) + { + CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' + || refcoin!=coin) + { + CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + } + else if (funcid=='P') + { + if (DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) + { + CCerror = strprintf("cannot decode partialsign tx opret %s",uint256_str(str,lasttxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(withdrawtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())==0) + { + CCerror = strprintf("invalid withdraw txid %s",uint256_str(str,withdrawtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s",uint256_str(str,withdrawtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (komodo_txnotarizedconfirmed(withdrawtxid)==false) + { + CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' + || refcoin!=coin) + { + CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + } + if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + { + mtx.vin.push_back(CTxIn(lasttxid,0,CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,CC_MARKER_VALUE,importgatewaypk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayCompleteSigningOpRet('S',withdrawtxid,refcoin,K+1,hex))); + } + CCerror = strprintf("error adding funds for completesigning"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); +} + +std::string ImportGatewayMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; struct CCcontract_info *cp,C; char str[65],burnaddr[64]; CTransaction tx; int32_t numvouts; + uint256 withdrawtxid,bindtxid,oracletxid,tokenid,hashBlock; std::string coin,hex; + uint8_t K,M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; int64_t amount; CPubKey withdrawpub; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + mypk = pubkey2pk(Mypubkey()); + if ( txfee == 0 ) + txfee = 10000; + if (GetTransaction(completetxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0) + { + CCerror = strprintf("invalid completesigning txid %s",uint256_str(str,completetxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,hex)!='S' || refcoin!=coin) + { + CCerror = strprintf("cannot decode completesigning tx opret %s",uint256_str(str,completetxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if (komodo_txnotarizedconfirmed(completetxid)==false) + { + CCerror = strprintf("gatewayscompletesigning tx not yet confirmed/notarized"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())==0) + { + CCerror = strprintf("invalid withdraw txid %s",uint256_str(str,withdrawtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (GetTransaction(bindtxid,tx,hashBlock,false)==0 || (numvouts=tx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + else if (DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' + || refcoin!=coin) + { + CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + { + mtx.vin.push_back(CTxIn(completetxid,0,CScript())); + mtx.vout.push_back(CTxOut(CC_MARKER_VALUE,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayMarkDoneOpRet('M',withdrawtxid,refcoin,completetxid))); + } + CCerror = strprintf("error adding funds for markdone"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); +} + +UniValue ImportGatewayPendingDeposits(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex,pub; + CPubKey mypk,importgatewaypk,destpub; std::vector pubkeys,publishers; std::vector txids; + uint256 tmpbindtxid,hashBlock,txid,oracletxid,burntxid; uint8_t M,N,taddr,prefix,prefix2,wiftype; + char burnaddr[65],coinaddr[65],str[65],destaddr[65],txidaddr[65]; std::vector proof; + int32_t numvouts,vout,claimvout,height; int64_t nValue,amount; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + mypk = pubkey2pk(Mypubkey()); + importgatewaypk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,mypk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin) + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + 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; + nValue = (int64_t)it->second.satoshis; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size())>0 && + DecodeImportGatewayDepositOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,publishers,txids,height,burntxid,claimvout,hex,proof,destpub,amount) == 'D' + && tmpbindtxid==bindtxid && refcoin == coin && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("burntxid",uint256_str(str,burntxid))); + obj.push_back(Pair("deposittxid",uint256_str(str,txid))); + CCtxidaddr(txidaddr,txid); + obj.push_back(Pair("deposittxidaddr",txidaddr)); + _GetCCaddress(destaddr,EVAL_TOKENS,destpub); + obj.push_back(Pair("depositaddr",burnaddr)); + obj.push_back(Pair("tokens_destination_address",destaddr)); + pub=HexStr(destpub); + obj.push_back(Pair("claim_pubkey",pub)); + obj.push_back(Pair("amount",(double)amount/COIN)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + pending.push_back(obj); + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("pending",pending)); + return(result); +} + +UniValue ImportGatewayPendingWithdraws(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex; CPubKey mypk,importgatewaypk,withdrawpub,signerpk; + std::vector msigpubkeys; uint256 hashBlock,txid,tmpbindtxid,tmptokenid,oracletxid,withdrawtxid; uint8_t K,M,N,taddr,prefix,prefix2,wiftype; + char funcid,burnaddr[65],coinaddr[65],destaddr[65],str[65],withaddr[65],numstr[32],signeraddr[65],txidaddr[65]; + int32_t i,n,numvouts,vout,queueflag; int64_t amount,nValue; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + mypk = pubkey2pk(Mypubkey()); + importgatewaypk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,importgatewaypk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + n = msigpubkeys.size(); + queueflag = 0; + for (i=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + K=0; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P') && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0) + { + if (funcid=='W') + { + if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,amount)==0 || refcoin!=coin || tmpbindtxid!=bindtxid) continue; + } + else if (funcid=='P') + { + if (DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)!='P' || GetTransaction(withdrawtxid,tx,hashBlock,false)==0 + || (numvouts=tx.vout.size())<=0 || DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,amount)!='W' + || refcoin!=coin || tmpbindtxid!=bindtxid) + continue; + } + Getscriptaddress(destaddr,tx.vout[1].scriptPubKey); + GetCustomscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG,taddr,prefix,prefix2); + if ( strcmp(destaddr,coinaddr) == 0 ) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("withdrawtxid",uint256_str(str,tx.GetHash()))); + CCCustomtxidaddr(txidaddr,tx.GetHash(),taddr,prefix,prefix2); + obj.push_back(Pair("withdrawtxidaddr",txidaddr)); + obj.push_back(Pair("withdrawaddr",withaddr)); + sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); + obj.push_back(Pair("amount",numstr)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(tx.GetHash()))); + if ( queueflag != 0 ) + { + obj.push_back(Pair("depositaddr",burnaddr)); + GetCustomscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG,taddr,prefix,prefix2); + obj.push_back(Pair("signeraddr",signeraddr)); + } + if (N>1) + { + obj.push_back(Pair("number_of_signs",K)); + obj.push_back(Pair("last_txid",uint256_str(str,txid))); + if (K>0) obj.push_back(Pair("hex",hex)); + } + pending.push_back(obj); + } + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("pending",pending)); + result.push_back(Pair("queueflag",queueflag)); + return(result); +} + +UniValue ImportGatewayProcessedWithdraws(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string coin,hex; + CPubKey mypk,importgatewaypk,withdrawpub; std::vector msigpubkeys; + uint256 withdrawtxid,hashBlock,txid,tmptokenid,oracletxid; uint8_t K,M,N,taddr,prefix,prefix2,wiftype; + char burnaddr[65],coinaddr[65],str[65],numstr[32],withaddr[65],txidaddr[65]; + int32_t i,n,numvouts,vout,queueflag; int64_t nValue,amount; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + mypk = pubkey2pk(Mypubkey()); + importgatewaypk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,importgatewaypk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin) + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + n = msigpubkeys.size(); + queueflag = 0; + for (i=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + DecodeImportGatewayCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,hex) == 'S' && refcoin == coin && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0) + { + if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 + && DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount) == 'W' || refcoin!=coin) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("completesigningtxid",uint256_str(str,txid))); + obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); + CCCustomtxidaddr(txidaddr,withdrawtxid,taddr,prefix,prefix2); + obj.push_back(Pair("withdrawtxidaddr",txidaddr)); + GetCustomscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG,taddr,prefix,prefix2); + obj.push_back(Pair("withdrawaddr",withaddr)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); + obj.push_back(Pair("amount",numstr)); + obj.push_back(Pair("hex",hex)); + processed.push_back(obj); + } + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("processed",processed)); + result.push_back(Pair("queueflag",queueflag)); + return(result); +} + +UniValue ImportGatewayList() +{ + UniValue result(UniValue::VARR); std::vector > addressIndex; + struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction vintx; std::string coin; + char str[65],burnaddr[64]; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + SetCCtxids(addressIndex,cp->unspendableCCaddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + txid = it->first.txhash; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + { + if ( vintx.vout.size() > 0 && DecodeImportGatewayBindOpRet(burnaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 0 ) + { + result.push_back(uint256_str(str,txid)); + } + } + } + return(result); +} + +UniValue ImportGatewayExternalAddress(uint256 bindtxid,CPubKey pubkey) +{ + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction tx; + std::string coin; int64_t numvouts; char str[65],addr[65],burnaddr[65]; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector msigpubkeys; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + GetCustomscriptaddress(addr,CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG,taddr,prefix,prefix2); + result.push_back(Pair("result","success")); + result.push_back(Pair("address",addr)); + return(result); +} + +UniValue ImportGatewayDumpPrivKey(uint256 bindtxid,CKey key) +{ + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction tx; + std::string coin,priv; int64_t numvouts; char str[65],addr[65],burnaddr[65]; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector msigpubkeys; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + + priv=EncodeCustomSecret(key,wiftype); + result.push_back(Pair("result","success")); + result.push_back(Pair("privkey",priv.c_str())); + return(result); +} + +UniValue ImportGatewayInfo(uint256 bindtxid) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],burnaddr[64],gatewaystokens[64]; + uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2,wiftype; uint256 oracletxid,hashBlock; CTransaction tx; + CPubKey ImportGatewaypk; struct CCcontract_info *cp,C; int32_t i; int64_t numvouts,remaining; std::vector msigpubkeys; + + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + ImportGatewaypk = GetUnspendable(cp,0); + GetTokensCCaddress(cp,gatewaystokens,ImportGatewaypk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') + { + CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } + if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("name","ImportGateway")); + burnaddr[0] = 0; + if ( tx.vout.size() > 0 && DecodeImportGatewayBindOpRet(burnaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 0 && M <= N && N > 0 ) + { + result.push_back(Pair("M",M)); + result.push_back(Pair("N",N)); + for (i=0; i > unspentOutputs; CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector data; + CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; + struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector data; cp = CCinit(&C,EVAL_ORACLES); CCtxidaddr(markeraddr,origtxid); if ( GetTransaction(origtxid,tx,hashBlock,false) == 0 ) diff --git a/src/importcoin.cpp b/src/importcoin.cpp index 018025e5a..051129020 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -35,8 +35,7 @@ CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction b mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload)); mtx.vout = payouts; auto importData = E_MARSHAL(ss << proof; ss << burnTx); - mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << importData)); - + mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << importData)); if (nExpiryHeightOverride != 0) mtx.nExpiryHeight = nExpiryHeightOverride; //this is for construction of the tx used for validating importtx return CTransaction(mtx); @@ -53,29 +52,97 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb return CTxOut(value, CScript() << OP_RETURN << opret); } +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, + uint256 bindtxid,std::vector publishers,std::vector txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub) +{ + std::vector opret; + opret = E_MARSHAL(ss << VARINT(targetCCid); + ss << targetSymbol; + ss << SerializeHash(payouts); + ss << rawproof; + ss << bindtxid; + ss << publishers; + ss << txids; + ss << height; + ss << burnvout; + ss << rawburntx; + ss << destpub); + + return CTxOut(value, CScript() << OP_RETURN << opret); +} -bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx, +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof,std::string srcaddr, + std::string receipt) +{ + std::vector opret; + opret = E_MARSHAL(ss << VARINT(targetCCid); + ss << targetSymbol; + ss << SerializeHash(payouts); + ss << rawproof; + ss << srcaddr; + ss << receipt); + return CTxOut(value, CScript() << OP_RETURN << opret); +} + + +bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx, std::vector &payouts) { std::vector vData; - GetOpReturnData(importTx.vout[0].scriptPubKey, vData); + GetOpReturnData(importTx.vout[importTx.vout.size()-1].scriptPubKey, vData); if (importTx.vout.size() < 1) return false; - payouts = std::vector(importTx.vout.begin()+1, importTx.vout.end()); + payouts = std::vector(importTx.vout.begin(), importTx.vout.end()-1); return importTx.vin.size() == 1 && importTx.vin[0].scriptSig == (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN)) && E_UNMARSHAL(vData, ss >> proof; ss >> burnTx); } -bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) +bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) { - std::vector burnOpret; uint32_t ccid = 0; + std::vector burnOpret; uint32_t ccid = 0; bool isEof=true; + if (burnTx.vout.size() == 0) return false; GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); ss >> targetSymbol; ss >> payoutsHash; - ss >> rawproof); + ss >> rawproof; isEof=ss.eof();) || !isEof; +} + +bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt) +{ + std::vector burnOpret,rawproof; bool isEof=true; + std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; + + if (burnTx.vout.size() == 0) return false; + GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); + return (E_UNMARSHAL(burnOpret, ss >> VARINT(targetCCid); + ss >> targetSymbol; + ss >> payoutsHash; + ss >> rawproof; + ss >> srcaddr; + ss >> receipt)); +} + +bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub) +{ + std::vector burnOpret,rawproof; bool isEof=true; + uint32_t targetCCid; uint256 payoutsHash; std::string targetSymbol; + + if (burnTx.vout.size() == 0) return false; + GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); + return (E_UNMARSHAL(burnOpret, ss >> VARINT(targetCCid); + ss >> targetSymbol; + ss >> payoutsHash; + ss >> rawproof; + ss >> bindtxid; + ss >> publishers; + ss >> txids; + ss >> height; + ss >> burnvout; + ss >> rawburntx; + ss >> destpub)); } diff --git a/src/importcoin.h b/src/importcoin.h index 947debcd8..8cb8dbc58 100644 --- a/src/importcoin.h +++ b/src/importcoin.h @@ -29,10 +29,15 @@ CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride = 0); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof); +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, + uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub); +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof,std::string srcaddr, + std::string receipt); -bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector &rawproof); -bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx, - std::vector &payouts); +bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector &rawproof); +bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt); +bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub); +bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx,std::vector &payouts); bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state); diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index 710f99f09..fa795e0e5 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -24,6 +24,7 @@ #include "consensus/validation.h" #include "cc/eval.h" #include "cc/utils.h" +#include "cc/CCinclude.h" #include "main.h" #include "primitives/transaction.h" #include "rpc/server.h" @@ -35,6 +36,7 @@ #include "script/standard.h" #include "key_io.h" +#include "cc/CCImportGateway.h" #include #include @@ -42,19 +44,23 @@ using namespace std; +#define RETURN_IF_ERROR(CCerror) if ( CCerror != "" ) { ERR_RESULT(CCerror); return(result); } +#define ERR_RESULT(x) result.push_back(Pair("result", "error")) , result.push_back(Pair("error", x)); + +extern std::string CCerror; extern std::string ASSETCHAINS_SELFIMPORT; extern uint16_t ASSETCHAINS_CODAPORT, ASSETCHAINS_BEAMPORT; +int32_t ensure_CCrequirements(uint8_t evalcode); int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip); int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height); struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi); uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth); extern std::string ASSETCHAINS_SELFIMPORT; -uint256 Parseuint256(char *hexstr); std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx); int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount); -std::string MakeGatewaysImportTx(uint64_t txfee, uint256 bindtxid, int32_t height, std::string refcoin, std::vectorproof, std::string rawburntx, int32_t ivout, uint256 burntxid); +std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector vouts); UniValue assetchainproof(const UniValue& params, bool fHelp) { @@ -338,7 +344,6 @@ UniValue selfimport(const UniValue& params, bool fHelp) source = params[5].get_str(); } */ - if (source == "BEAM") { if (ASSETCHAINS_BEAMPORT == 0) @@ -398,14 +403,348 @@ UniValue selfimport(const UniValue& params, bool fHelp) // source is external coin is the assetchains symbol in the burnTx OP_RETURN // burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent - std::string hextx = MakeGatewaysImportTx(0, bindtxid, height, source, rawproof, rawsourcetx, ivout, sourcetxid); + //std::string hextx = MakeGatewaysImportTx(0, bindtxid, height, source, rawproof, rawsourcetx, ivout, ""); - result.push_back(Pair("hex", hextx)); - result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx + // result.push_back(Pair("hex", hextx)); + // result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx } return result; } +UniValue importdual(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + CMutableTransaction mtx; + std::string hex,source,sourceaddr,destaddr,burntxid; uint64_t burnAmount; + CPubKey destpub; std::vector vouts; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importdual only works on -ac_import chains"); + + if (fHelp || params.size() < 4) + throw runtime_error("burntxid source_addr dest_pubkey amount\n"); + + CCerror = ""; + + burntxid = params[0].get_str(); + sourceaddr = params[1].get_str(); + destaddr = params[2].get_str(); + burnAmount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999; + + source = ASSETCHAINS_SELFIMPORT; //defaults to -ac_import=... param + + CTxDestination dest = DecodeDestination(destaddr.c_str()); + CScript scriptPubKey = GetScriptForDestination(dest); + vouts.push_back(CTxOut(burnAmount,scriptPubKey)); + + if (source == "BEAM") + { + if (ASSETCHAINS_BEAMPORT == 0) + return(-1); + // confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn + // return(0); + return -1; + } + else if (source == "CODA") + { + if (ASSETCHAINS_CODAPORT == 0) + return(-1); + hex=MakeCodaImportTx(0,burntxid,sourceaddr,vouts); + // confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn + // return(0); + } + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt importdual"); + return result; +} + +UniValue importgatewayinfo(const UniValue& params, bool fHelp) +{ + uint256 txid; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importgatewaybind only works on -ac_import chains"); + if ( fHelp || params.size() != 1 ) + throw runtime_error("importgatewayinfo bindtxid\n"); + txid = Parseuint256(params[0].get_str().c_str()); + return(ImportGatewayInfo(txid)); +} + +UniValue importgatewaybind(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + CMutableTransaction mtx; std::vector pubkey; + std::string hex,coin; int32_t i,M,N; std::vector pubkeys; + uint256 oracletxid; uint8_t p1,p2,p3,p4; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importgatewaybind only works on -ac_import chains"); + if ( fHelp || params.size() != 8) + throw runtime_error("use \'importgatewaybind coin orcletxid M N pubkeys pubtype p2shtype wiftype [taddr]\' to bind an import gateway\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + CCerror = ""; + coin = params[0].get_str(); + oracletxid = Parseuint256(params[1].get_str().c_str()); + M = atoi(params[2].get_str().c_str()); + N = atoi(params[3].get_str().c_str()); + if ( M > N || N == 0 || N > 15 ) + throw runtime_error("illegal M or N > 15\n"); + if ( params.size() < 4+N+3 ) + throw runtime_error("not enough parameters for N pubkeys\n"); + for (i=0; i 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt importgatewaybind"); + return result; +} + +UniValue importgatewaydeposit(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + CMutableTransaction mtx; std::vector rawproof; + std::string hex,coin,rawburntx; int32_t height,burnvout; + CPubKey destpub; std::vector vouts; uint256 bindtxid,burntxid; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importgatewaydeposit only works on -ac_import chains"); + if ( fHelp || params.size() != 8) + throw runtime_error("use \'importgatewaydeposit bindtxid height coin burntxid nvout rawburntx rawproof destpub\' to import deposited coins\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + CCerror = ""; + bindtxid = Parseuint256(params[0].get_str().c_str()); + height = atoi(params[1].get_str().c_str()); + coin = params[2].get_str(); + burntxid = Parseuint256(params[3].get_str().c_str()); + burnvout = atoi(params[4].get_str().c_str()); + rawburntx = params[5].get_str(); + rawproof = ParseHex(params[6].get_str()); + destpub = ParseHex(params[7].get_str()); + if (coin == "BEAM" || coin == "CODA") + { + ERR_RESULT("for BEAM and CODA import use importdual RPC"); + return result; + } + else if (coin != ASSETCHAINS_SELFIMPORT) + { + ERR_RESULT("source coin not equal to ac_import name"); + return result; + } + hex = ImportGatewayDeposit(0, bindtxid, height, coin, burntxid, burnvout, rawburntx, rawproof, destpub); + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt importgatewaydeposit"); + return result; +} + +UniValue importgatewaywithdraw(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + CMutableTransaction mtx; std::vector rawproof; + std::string hex,coin,rawburntx; int64_t amount; int32_t height,burnvout; + CPubKey destpub; std::vector vouts; uint256 bindtxid,burntxid; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importgatewaywithdraw only works on -ac_import chains"); + if ( fHelp || params.size() != 4) + throw runtime_error("use \'importgatewaywithdraw bindtxid coin withdrawpub amount\' to burn imported coins and withdraw them on external chain\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + CCerror = ""; + bindtxid = Parseuint256(params[0].get_str().c_str()); + coin = params[1].get_str(); + destpub = ParseHex(params[2].get_str()); + amount = atof((char *)params[3].get_str().c_str()) * COIN + 0.00000000499999; + if (coin == "BEAM" || coin == "CODA") + { + ERR_RESULT("for BEAM and CODA import use importdual RPC"); + return result; + } + else if (coin != ASSETCHAINS_SELFIMPORT) + { + ERR_RESULT("source coin not equal to ac_import name"); + return result; + } + hex = ImportGatewayWithdraw(0, bindtxid, coin, destpub, amount); + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt importgatewaywithdraw"); + return result; +} + +UniValue importgatewaypartialsign(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); std::string coin,parthex,hex; uint256 txid; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importgatewayspartialsign only works on -ac_import chains"); + if ( fHelp || params.size() != 3 ) + throw runtime_error("importgatewayspartialsign txidaddr refcoin hex\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + txid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + parthex = params[2].get_str(); + hex = ImportGatewayPartialSign(0,txid,coin,parthex); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex",hex)); + } else ERR_RESULT("couldnt importgatewayspartialsign"); + return(result); +} + +UniValue importgatewaycompletesigning(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 withdrawtxid; std::string txhex,hex,coin; + + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) + throw runtime_error("importgatewaycompletesigning only works on -ac_import chains"); + if ( fHelp || params.size() != 3 ) + throw runtime_error("importgatewaycompletesigning withdrawtxid coin hex\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + withdrawtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + txhex = params[2].get_str(); + hex = ImportGatewayCompleteSigning(0,withdrawtxid,coin,txhex); + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt importgatewaycompletesigning"); + return(result); +} + +UniValue importgatewaymarkdone(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 completetxid; std::string hex,coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("importgatewaymarkdone completesigningtx coin\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + completetxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + hex = ImportGatewayMarkDone(0,completetxid,coin); + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt importgatewaymarkdone"); + return(result); +} + +UniValue importgatewaypendingdeposits(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; std::string coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("importgatewaypendingdeposits bindtxid coin\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + return(ImportGatewayPendingDeposits(bindtxid,coin)); +} + +UniValue importgatewaypendingwithdraws(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; std::string coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("importgatewaypendingwithdraws bindtxid coin\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + return(ImportGatewayPendingWithdraws(bindtxid,coin)); +} + +UniValue importgatewayprocessed(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; std::string coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("importgatewayprocessed bindtxid coin\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + return(ImportGatewayProcessedWithdraws(bindtxid,coin)); +} + +UniValue importgatewayexternaladdress(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; CPubKey pubkey; + + if ( fHelp || params.size() != 2) + throw runtime_error("importgatewayexternaladdress bindtxid pubkey\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + pubkey = ParseHex(params[1].get_str().c_str()); + return(ImportGatewayExternalAddress(bindtxid,pubkey)); +} + +UniValue importgatewaydumpprivkey(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; + + if ( fHelp || params.size() != 2) + throw runtime_error("importgatewaydumpprivkey bindtxid address\n"); + if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + std::string strAddress = params[1].get_str(); + CTxDestination dest = DecodeDestination(strAddress); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid transparent address"); + } + const CKeyID *keyID = boost::get(&dest); + if (!keyID) { + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + } + CKey vchSecret; + // if (!pwalletMain->GetKey(*keyID, vchSecret)) { + // throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); + //} + return(ImportGatewayDumpPrivKey(bindtxid,vchSecret)); +} + UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -536,9 +875,9 @@ UniValue getimports(const UniValue& params, bool fHelp) UniValue objTx(UniValue::VOBJ); objTx.push_back(Pair("txid",tx.GetHash().ToString())); TxProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; - TotalImported += tx.vout[1].nValue; - objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[1].nValue))); - if (ExtractDestination(tx.vout[1].scriptPubKey, importaddress)) + TotalImported += tx.vout[0].nValue; + objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[0].nValue))); + if (ExtractDestination(tx.vout[0].scriptPubKey, importaddress)) { objTx.push_back(Pair("address", CBitcoinAddress(importaddress).ToString())); } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index a48ef6cb1..fc34a2a3f 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -354,6 +354,21 @@ static const CRPCCommand vRPCCommands[] = { "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true }, { "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true }, { "crosschain", "selfimport", &selfimport, true }, + { "crosschain", "importdual", &importdual, true }, + //ImportGateway + { "crosschain", "importgatewayddress", &importgatewayaddress, true }, + { "crosschain", "importgatewayinfo", &importgatewayinfo, true }, + { "crosschain", "importgatewaybind", &importgatewaybind, true }, + { "crosschain", "importgatewaydeposit", &importgatewaydeposit, true }, + { "crosschain", "importgatewaywithdraw", &importgatewaywithdraw, true }, + { "crosschain", "importgatewaypartialsign", &importgatewaypartialsign, true }, + { "crosschain", "importgatewaycompletesigning", &importgatewaycompletesigning, true }, + { "crosschain", "importgatewaymarkdone", &importgatewaymarkdone, true }, + { "crosschain", "importgatewaypendingdeposits", &importgatewaypendingdeposits, true }, + { "crosschain", "importgatewaypendingwithdraws", &importgatewaypendingwithdraws, true }, + { "crosschain", "importgatewayprocessed", &importgatewayprocessed, true }, + + /* Mining */ { "mining", "getblocktemplate", &getblocktemplate, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 79a12bb7b..d8fd0e736 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -314,7 +314,6 @@ extern UniValue channelsopen(const UniValue& params, bool fHelp); extern UniValue channelspayment(const UniValue& params, bool fHelp); extern UniValue channelsclose(const UniValue& params, bool fHelp); extern UniValue channelsrefund(const UniValue& params, bool fHelp); - //extern UniValue tokenswapask(const UniValue& params, bool fHelp); //extern UniValue tokenfillswap(const UniValue& params, bool fHelp); extern UniValue faucetfund(const UniValue& params, bool fHelp); @@ -435,6 +434,18 @@ extern UniValue invalidateblock(const UniValue& params, bool fHelp); extern UniValue reconsiderblock(const UniValue& params, bool fHelp); extern UniValue getspentinfo(const UniValue& params, bool fHelp); extern UniValue selfimport(const UniValue& params, bool fHelp); +extern UniValue importdual(const UniValue& params, bool fHelp); +extern UniValue importgatewayaddress(const UniValue& params, bool fHelp); +extern UniValue importgatewayinfo(const UniValue& params, bool fHelp); +extern UniValue importgatewaybind(const UniValue& params, bool fHelp); +extern UniValue importgatewaydeposit(const UniValue& params, bool fHelp); +extern UniValue importgatewaywithdraw(const UniValue& params, bool fHelp); +extern UniValue importgatewaypartialsign(const UniValue& params, bool fHelp); +extern UniValue importgatewaycompletesigning(const UniValue& params, bool fHelp); +extern UniValue importgatewaymarkdone(const UniValue& params, bool fHelp); +extern UniValue importgatewaypendingdeposits(const UniValue& params, bool fHelp); +extern UniValue importgatewaypendingwithdraws(const UniValue& params, bool fHelp); +extern UniValue importgatewayprocessed(const UniValue& params, bool fHelp); extern UniValue getblocksubsidy(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d720cf33f..77b2fb62d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5858,6 +5858,19 @@ UniValue tokenaddress(const UniValue& params, bool fHelp) return(CCaddress(cp,(char *)"Tokens", pubkey)); } +UniValue importgatewayaddress(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp,C; std::vector pubkey; + cp = CCinit(&C,EVAL_IMPORTGATEWAY); + if ( fHelp || params.size() > 1 ) + throw runtime_error("importgatewayddress [pubkey]\n"); + if ( ensure_CCrequirements(0) < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + if ( params.size() == 1 ) + pubkey = ParseHex(params[0].get_str().c_str()); + return(CCaddress(cp,(char *)"ImportGateway", pubkey)); +} + UniValue marmara_poolpayout(const UniValue& params, bool fHelp) { int32_t firstheight; double perc; char *jsonstr; @@ -7994,7 +8007,6 @@ UniValue test_heirmarker(const UniValue& params, bool fHelp) return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret)); } - UniValue test_burntx(const UniValue& params, bool fHelp) { // make fake token tx: