From 03794dc2087785e630e5e8c9b226312631ff812a Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Fri, 19 Apr 2019 21:57:10 +0300 Subject: [PATCH 01/20] first approach to get HTTPS in libcurl work 1. libcurl.mk now changed to build against static openssl from deps. 2. but, it won't work with openssl 1.1.1a, bcz of SSL: couldn't create a context: error:00000000:lib(0):func(0):reason(0) , so, in test i decided to upgrade openssl to 1.1.1b. 3. original openssl.mk was with many disabled features, i enable all of them, of course it's don't needed and we need to leave only SSL/TLS things enabled in OpenSSL build. 4. probably i broke something in Windows and MacOS build. This commit is only first approach to continue work. --- depends/packages/libcurl.mk | 23 +++++++++--- depends/packages/openssl.mk | 72 +----------------------------------- depends/packages/packages.mk | 2 +- 3 files changed, 21 insertions(+), 76 deletions(-) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 642fc066d..1ce0a9161 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -1,9 +1,10 @@ package=libcurl -$(package)_version=7.54.0 +$(package)_version=7.64.1 +$(package)_dependencies=openssl $(package)_download_path=https://curl.haxx.se/download $(package)_file_name=curl-$($(package)_version).tar.gz -$(package)_sha256_hash=a84b635941c74e26cce69dd817489bec687eb1f230e7d1897fc5b5f108b59adf -$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) +$(package)_sha256_hash=432d3f466644b9416bc5b649d344116a753aeaa520c8beaf024a90cba9d3d35d +$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-unknown-linux-gnu $(package)_config_opts_mingw32=--enable-mingw --disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-w64-mingw32 $(package)_config_opts_darwin=--disable-shared --enable-static --prefix=$(host_prefix) $(package)_cflags_darwin=-mmacosx-version-min=10.9 @@ -15,11 +16,21 @@ define $(package)_set_vars endef endif -define $(package)_config_cmds - $($(package)_conf_tool) $($(package)_config_opts) +ifeq ($(build_os),linux) +define $(package)_set_vars + $(package)_config_env=LD_LIBRARY_PATH="$(host_prefix)/lib" PKG_CONFIG_LIBDIR="$(host_prefix)/lib/pkgconfig" CPPFLAGS="-I$(host_prefix)/include" LDFLAGS="-L$(host_prefix)/lib" endef +endif +define $(package)_config_cmds + echo '=== config for $(package):' && \ + echo '$($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts)' && \ + sleep 10 && \ + echo '=== ' && \ + $($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts) +endef + ifeq ($(build_os),darwin) define $(package)_build_cmds $(MAKE) CPPFLAGS='-fPIC' CFLAGS='-mmacosx-version-min=10.9' @@ -31,5 +42,7 @@ endef endif define $(package)_stage_cmds + echo 'Staging dir: $($(package)_staging_dir)$(host_prefix)/' && \ + sleep 10 && \ $(MAKE) DESTDIR=$($(package)_staging_dir) install endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index e378088e6..96908e151 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,81 +1,13 @@ package=openssl -$(package)_version=1.1.1a +$(package)_version=1.1.1b $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41 +$(package)_sha256_hash=5c557b023230413dfb0756f3137a13e6d726838ccd1430888ad15bfb2b43ea4b define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl -$(package)_config_opts+=no-afalgeng -$(package)_config_opts+=no-asm -$(package)_config_opts+=no-async -$(package)_config_opts+=no-bf -$(package)_config_opts+=no-blake2 -$(package)_config_opts+=no-camellia -$(package)_config_opts+=no-capieng -$(package)_config_opts+=no-cast -$(package)_config_opts+=no-chacha -$(package)_config_opts+=no-cmac -$(package)_config_opts+=no-cms -$(package)_config_opts+=no-comp -$(package)_config_opts+=no-crypto-mdebug -$(package)_config_opts+=no-crypto-mdebug-backtrace -$(package)_config_opts+=no-ct -$(package)_config_opts+=no-des -$(package)_config_opts+=no-dgram -$(package)_config_opts+=no-dsa -$(package)_config_opts+=no-dso -$(package)_config_opts+=no-dtls -$(package)_config_opts+=no-dtls1 -$(package)_config_opts+=no-dtls1-method -$(package)_config_opts+=no-dynamic-engine -$(package)_config_opts+=no-ec2m -$(package)_config_opts+=no-ec_nistp_64_gcc_128 -$(package)_config_opts+=no-egd -$(package)_config_opts+=no-engine -$(package)_config_opts+=no-err -$(package)_config_opts+=no-gost -$(package)_config_opts+=no-heartbeats -$(package)_config_opts+=no-idea -$(package)_config_opts+=no-md2 -$(package)_config_opts+=no-md4 -$(package)_config_opts+=no-mdc2 -$(package)_config_opts+=no-multiblock -$(package)_config_opts+=no-nextprotoneg -$(package)_config_opts+=no-ocb -$(package)_config_opts+=no-ocsp -$(package)_config_opts+=no-poly1305 -$(package)_config_opts+=no-posix-io -$(package)_config_opts+=no-psk -$(package)_config_opts+=no-rc2 -$(package)_config_opts+=no-rc4 -$(package)_config_opts+=no-rc5 -$(package)_config_opts+=no-rdrand -$(package)_config_opts+=no-rfc3779 -$(package)_config_opts+=no-rmd160 -$(package)_config_opts+=no-scrypt -$(package)_config_opts+=no-sctp -$(package)_config_opts+=no-seed $(package)_config_opts+=no-shared -$(package)_config_opts+=no-sock -$(package)_config_opts+=no-srp -$(package)_config_opts+=no-srtp -$(package)_config_opts+=no-ssl -$(package)_config_opts+=no-ssl3 -$(package)_config_opts+=no-ssl3-method -$(package)_config_opts+=no-ssl-trace -$(package)_config_opts+=no-stdio -$(package)_config_opts+=no-tls -$(package)_config_opts+=no-tls1 -$(package)_config_opts+=no-tls1-method -$(package)_config_opts+=no-ts -$(package)_config_opts+=no-ui -$(package)_config_opts+=no-unit-test -$(package)_config_opts+=no-weak-ssl-ciphers -$(package)_config_opts+=no-whirlpool -$(package)_config_opts+=no-zlib -$(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) $(package)_config_opts+=-DPURIFY $(package)_config_opts_linux=-fPIC -Wa,--noexecstack diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 5bc8fcda6..e29c62580 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -47,7 +47,7 @@ native_packages := native_ccache wallet_packages=bdb ifeq ($(host_os),linux) - packages := boost openssl libevent zeromq $(zcash_packages) googletest #googlemock + packages := boost openssl libevent zeromq $(zcash_packages) googletest libcurl #googlemock else packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock endif From 2f19aeaa4adab8c5462b76ef65f93e0fd1c0e204 Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Fri, 19 Apr 2019 22:01:54 +0300 Subject: [PATCH 02/20] + debug (ssl and curl version printout) --- src/komodo_bitcoind.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index bb5a093d3..92943089a 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -206,8 +206,11 @@ try_again: if ( strncmp(url,"https",5) == 0 ) { - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); + + /* printf("[ Decker ] SSL: %s\n", curl_version()); */ + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + //curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); // this is useful for debug, but seems crash on libcurl/7.64.1 OpenSSL/1.1.1b zlib/1.2.8 librtmp/2.3 } if ( userpass != 0 ) curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); From fea2b66581b9a6fbcfed431e91a6c6ee97fb70ea Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sat, 20 Apr 2019 19:29:16 +0800 Subject: [PATCH 03/20] add validation for OP_RETURN to payments CC. Enable ccvoutopret for payments fund. --- src/cc/CCinclude.h | 7 +++- src/cc/CCutils.cpp | 53 ++++++++++++++++++++----- src/cc/customcc.cpp | 32 +++++---------- src/cc/payments.cpp | 96 +++++++++++++++++++++++++++++++++++---------- 4 files changed, 135 insertions(+), 53 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 5a515634d..db1ee7475 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -226,8 +226,11 @@ bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]); CPubKey buf2pk(uint8_t *buf33); void endiancpy(uint8_t *dest,uint8_t *src,int32_t len); uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout); -CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, const std::vector>* vData = NULL); -CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, const std::vector>* vData = NULL); +CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, std::vector>* vData = NULL); +CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, std::vector>* vData = NULL); +int32_t has_opret(const CTransaction &tx, uint8_t evalcode); +CScript getCCopret(const CScript &scriptPubKey); +bool makeCCopret(CScript &opret, std::vector> &vData); CC *MakeCCcond1(uint8_t evalcode,CPubKey pk); CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2); CC* GetCryptoCondition(CScript const& scriptSig); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index e9acfbe20..b563bd09a 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -58,35 +58,70 @@ CC *MakeCCcond1(uint8_t evalcode,CPubKey pk) return CCNewThreshold(2, {condCC, Sig}); } -CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, const std::vector>* vData) +int32_t has_opret(const CTransaction &tx, uint8_t evalcode) +{ + int i = 0; + for ( auto vout : tx.vout ) + { + if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode ) + return i; + i++; + } + return 0; +} + +CScript getCCopret(const CScript &scriptPubKey) +{ + std::vector> vParams = std::vector>(); + CScript dummy; CScript opret; + if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) ) + { + //opret << E_MARSHAL(ss << vParams[0]); + opret = CScript(vParams[0].begin()+6, vParams[0].end()); + } + //fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vParams.size(), HexStr(vParams[0].begin(),vParams[0].end()).c_str()); + //opret = CScript(vParams[0].begin(), vParams[0].end()); + return opret; +} + +bool makeCCopret(CScript &opret, std::vector> &vData) +{ + if ( opret.empty() ) + return false; + vData.push_back(std::vector(opret.begin(), opret.end())); + return true; +} + +CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, std::vector>* vData) { CTxOut vout; CC *payoutCond = MakeCCcond1(evalcode,pk); vout = CTxOut(nValue,CCPubKey(payoutCond)); if ( vData ) { - std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); + //std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); std::vector vPubKeys = std::vector(); - vPubKeys.push_back(pk); - COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, vtmpData); + //vPubKeys.push_back(pk); + COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, ( * vData)); vout.scriptPubKey << ccp.AsVector() << OP_DROP; } cc_free(payoutCond); return(vout); } -CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, const std::vector>* vData) +CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, std::vector>* vData) { CTxOut vout; CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2); vout = CTxOut(nValue,CCPubKey(payoutCond)); if ( vData ) { - std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); + //std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); std::vector vPubKeys = std::vector(); - vPubKeys.push_back(pk1); - vPubKeys.push_back(pk2); - COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, vtmpData); + // skip pubkeys. These need to maybe be optional and we need some way to get them out that is easy! + //vPubKeys.push_back(pk1); + //vPubKeys.push_back(pk2); + COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, ( * vData)); vout.scriptPubKey << ccp.AsVector() << OP_DROP; } cc_free(payoutCond); diff --git a/src/cc/customcc.cpp b/src/cc/customcc.cpp index 2e174f510..a8b0bf871 100644 --- a/src/cc/customcc.cpp +++ b/src/cc/customcc.cpp @@ -67,38 +67,26 @@ UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) // make op_return payload as normal. CScript opret = custom_opret('1',mypk); std::vector> vData = std::vector>(); - vData.push_back(std::vector(opret.begin(), opret.end())); - // make vout0 with op_return included as payload. - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData)); - fprintf(stderr, "vout size2.%li\n", mtx.vout.size()); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript()); - return(custom_rawtxresult(result,rawtx,broadcastflag)); + if ( makeCCopret(opret, vData) ) + { + // make vout0 with op_return included as payload. + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData)); + fprintf(stderr, "vout size2.%li\n", mtx.vout.size()); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript()); + return(custom_rawtxresult(result,rawtx,broadcastflag)); + } } return(result); } -bool has_opret(const CTransaction &tx, uint8_t evalcode) -{ - for ( auto vout : tx.vout ) - { - if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode ) - return true; - } - return false; -} - bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { char expectedaddress[64]; CPubKey pk; CScript opret; int32_t numvout; - if ( !has_opret(tx, EVAL_CUSTOM) ) + if ( has_opret(tx, EVAL_CUSTOM) == 0 ) { std::vector> vParams = std::vector>(); - CScript dummy; - if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 ) - { - opret << E_MARSHAL(ss << vParams[0]); - } + opret = getCCopret(tx.vout[0].scriptPubKey); numvout = 1; } else diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index d83cd0bec..3e4666f47 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,6 +16,12 @@ #include "CCPayments.h" /* + +-earlytxid is not an -ac_param, so it doesnt affect the chain magics +extra data after the normal CCvout is whatever data we want and can represent whatever we want +so -ac_script= +in the validation if you see the useearlytxid in the opreturn data or extra data, you use the earlytxid as the txid that specifies the payment + 0) txidopret <- allocation, scriptPubKey, opret 1) create <- locked_blocks, minrelease, list of txidopret @@ -212,6 +218,20 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & allocations.push_back(allocation); //fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation); checkallocations += allocation; + // if we have an op_return to pay to need to check it exists and is paying the correct opret. + if ( !opret.empty() ) + { + if ( !fHasOpret ) + { + fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str()); + return(eval->Invalid("missing opret in payments release")); + } + else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey ) + { + fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str()); + return(eval->Invalid("pays incorrect opret")); + } + } } i++; } @@ -277,14 +297,24 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey); if ( strcmp(destaddr,coinaddr) != 0 ) { - std::vector scriptPubKey,opret; uint256 checktxid; - if ( txin.vout.size() < 2 || DecodePaymentsFundOpRet(txin.vout[txin.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid ) + CScript opret; uint256 checktxid; int32_t opret_ind; + if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) + { + // get op_return from CCvout + opret = getCCopret(txin.vout[0].scriptPubKey); + } + else + { + // get op_return from the op_return + opret = txin.vout[opret_ind].scriptPubKey; + } // else return(eval->Invalid("vin has wrong amount of vouts")); // dont think this is needed? + if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); return(eval->Invalid("vin is not paymentsCC type")); - } //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str()); + } } - // check the chain depth vs locked blcoks requirement. + // check the chain depth vs locked blocks requirement. CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if ( pblockindex->GetHeight() > ht-lockedblocks ) { @@ -340,8 +370,18 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP } if ( iter == 0 ) { - std::vector scriptPubKey,opret; - if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() < 2 || DecodePaymentsFundOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid ) + CScript opret; uint256 checktxid; int32_t opret_ind; + if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 ) + { + // get op_return from CCvout + opret = getCCopret(vintx.vout[0].scriptPubKey); + } + else + { + // get op_return from the op_return + opret = vintx.vout[opret_ind].scriptPubKey; + } + if ( myGetTransaction(txid,tx,hashBlock) == 0 || DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str()); continue; @@ -603,10 +643,16 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) } else { - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); opret = EncodePaymentsFundOpRet(txid); + fprintf(stderr, "opret.%s\n", HexStr(opret.begin(), opret.end()).c_str()); + std::vector> vData = std::vector>(); + if ( makeCCopret(opret, vData) ) + { + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); + fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vData.size(), HexStr(vData[0].begin(),vData[0].end()).c_str()); + } } - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); if ( params != 0 ) free_json(params); return(payments_rawtxresult(result,rawtx,1)); @@ -630,24 +676,34 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx; - std::vector scriptPubKey,opret; int32_t allocation,n,retval0,retval1=0; + std::vector scriptPubKey,opret; int32_t n,retval0,retval1=0; int64_t allocation; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); if ( params != 0 && n > 1 && n <= 3 ) { - allocation = juint(jitem(params,0),0); + allocation = (int64_t)jint(jitem(params,0),0); retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0); - if ( n == 3 ) - retval1 = payments_parsehexdata(opret,jitem(params,2),0); - if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE,10) > 0 ) + CScript test = CScript(scriptPubKey.begin(),scriptPubKey.end()); + txnouttype whichType; + if (!::IsStandard(test, whichType)) { - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); - if ( params != 0 ) - free_json(params); - return(payments_rawtxresult(result,rawtx,1)); + result.push_back(Pair("result","error")); + result.push_back(Pair("error","scriptPubkey is not valid payment.")); + } + else + { + if ( n == 3 ) + retval1 = payments_parsehexdata(opret,jitem(params,2),0); + if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE*2,10) > 0 ) + { + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid params or cant find txfee")); } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","invalid params or cant find txfee")); } else { @@ -867,7 +923,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) funds = CCaddress_balance(fundsaddr,1); result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); GetCCaddress(cp,fundsopretaddr,Paymentspk); - fundsopret = CCaddress_balance(fundsopretaddr,1); + fundsopret = CCaddress_balance(fundsopretaddr,1); // Shows balance for ALL payments plans, not just the one asked for! result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret))); result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret))); result.push_back(Pair("result","success")); From 82e6cd0f935e934eedafcb3fad554e4c86dc1793 Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sun, 21 Apr 2019 11:48:16 +0800 Subject: [PATCH 04/20] fix two bugs for Alright --- src/cc/CCutils.cpp | 6 +++++- src/cc/payments.cpp | 9 ++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index b563bd09a..3c4c6c67c 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -149,8 +149,12 @@ bool IsCCInput(CScript const& scriptSig) bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime) { + LOCK(mempool.cs); + CCoinsView dummy; + CCoinsViewCache view(&dummy); int64_t interest; uint64_t valuein; - CCoinsViewCache &view = *pcoinsTip; + CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); + view.SetBackend(viewMemPool); valuein = view.GetValueIn(height,&interest,tx,blocktime); if ( valuein-tx.GetValueOut() > txfee ) { diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 3e4666f47..526fea52f 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -199,11 +199,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) return(eval->Invalid("negative values")); - if ( !CheckTxFee(tx, PAYMENTS_TXFEE, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) - return eval->Invalid("txfee is too high"); Paymentspk = GetUnspendable(cp,0); //fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() ); - + if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + return eval->Invalid("txfee is too high"); // Get all the script pubkeys and allocations std::vector allocations; std::vector scriptPubKeys; @@ -267,7 +266,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t test = allocations[n]; test *= checkamount; test /= totalallocations; - if ( test != tx.vout[i].nValue ) + if ( test != tx.vout[i].nValue && test != tx.vout[i].nValue-1 ) { fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue); return(eval->Invalid("amounts do not match")); @@ -564,7 +563,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue); mtx.vout[i+1].nValue = PAYMENTS_TXFEE; } - } + } if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE ) { std::string rawtx; From d16cdf5538e349e72ba537c1c2f7626a2715479d Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sun, 21 Apr 2019 13:05:39 +0800 Subject: [PATCH 05/20] Add -testmode command line arg --- src/chainparams.cpp | 2 ++ src/chainparams.h | 1 + src/komodo_defs.h | 1 + src/komodo_globals.h | 2 ++ src/komodo_utils.h | 1 + src/wallet-utility.cpp | 1 + 6 files changed, 8 insertions(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b09ccf7c3..b8b2998b7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -289,6 +289,8 @@ void *chainparams_commandline(void *ptr) mainParams.SetNValue(ASSETCHAINS_NK[0]); mainParams.SetKValue(ASSETCHAINS_NK[1]); } + if ( KOMODO_TESTNODE != 0 ) + mainParams.SetMiningRequiresPeers(false); if ( ASSETCHAINS_RPCPORT == 0 ) ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1; mainParams.pchMessageStart[0] = ASSETCHAINS_MAGIC & 0xff; diff --git a/src/chainparams.h b/src/chainparams.h index 3b1ad1f72..daa16af8c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -121,6 +121,7 @@ public: void SetCheckpointData(CCheckpointData checkpointData); void SetNValue(uint64_t n) { nEquihashN = n; } void SetKValue(uint64_t k) { nEquihashK = k; } + void SetMiningRequiresPeers(bool flag) { fMiningRequiresPeers = flag; } //void setnonce(uint32_t nonce) { memcpy(&genesis.nNonce,&nonce,sizeof(nonce)); } //void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; } diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 964ec852d..ecaf7339a 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -78,6 +78,7 @@ extern std::string DONATION_PUBKEY; extern uint8_t ASSETCHAINS_PRIVATE; extern int32_t USE_EXTERNAL_PUBKEY; extern char NOTARYADDRS[64][64]; +extern int32_t KOMODO_TESTNODE; int tx_height( const uint256 &hash ); extern std::vector vWhiteListAddress; void komodo_netevent(std::vector payload); diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 6070e9326..dc8cbda35 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -109,6 +109,8 @@ uint64_t PENDING_KOMODO_TX; extern int32_t KOMODO_LOADINGBLOCKS; unsigned int MAX_BLOCK_SIGOPS = 20000; +int32_t KOMODO_TESTNODE; + struct komodo_kv *KOMODO_KV; pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 4a1080cc1..88efb0264 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1710,6 +1710,7 @@ void komodo_args(char *argv0) DONATION_PUBKEY = GetArg("-donation", ""); NOTARY_PUBKEY = GetArg("-pubkey", ""); KOMODO_DEALERNODE = GetArg("-dealer",0); + KOMODO_TESTNODE = GetArg("-testnode",0); if ( strlen(NOTARY_PUBKEY.c_str()) == 66 ) { decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str()); diff --git a/src/wallet-utility.cpp b/src/wallet-utility.cpp index 655a3cab4..0b664ecb3 100644 --- a/src/wallet-utility.cpp +++ b/src/wallet-utility.cpp @@ -24,6 +24,7 @@ int32_t ASSETCHAINS_LWMAPOS = 0; int32_t VERUS_BLOCK_POSUNITS = 1000; int32_t ASSETCHAINS_OVERWINTER = 227520; int32_t ASSETCHAINS_SAPLING = 227520; +int32_t KOMODO_TESTNODE = 0; unsigned int MAX_BLOCK_SIGOPS = 20000; From 06bed214f9af422fbc72dad021290761d6c3e315 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:16:55 -1100 Subject: [PATCH 06/20] Check for null ptr before -> --- src/komodo_bitcoind.h | 11 +++++++++++ src/komodo_defs.h | 1 + src/wallet/asyncrpcoperation_mergetoaddress.cpp | 2 +- src/wallet/asyncrpcoperation_sendmany.cpp | 2 +- src/wallet/rpcwallet.cpp | 6 +++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index bb5a093d3..b342cc932 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1091,6 +1091,17 @@ int32_t komodo_blockheight(uint256 hash) return(0); } +uint32_t komodo_blocktime(uint256 hash) +{ + BlockMap::const_iterator it; CBlockIndex *pindex = 0; + if ( (it = mapBlockIndex.find(hash)) != mapBlockIndex.end() ) + { + if ( (pindex= it->second) != 0 ) + return(pindex->nTime); + } + return(0); +} + int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash) { int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex; diff --git a/src/komodo_defs.h b/src/komodo_defs.h index ecaf7339a..ee44132bc 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -95,6 +95,7 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160, int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width); int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen); +uint32_t komodo_blocktime(uint256 hash); int32_t komodo_longestchain(); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); int8_t komodo_segid(int32_t nocache,int32_t height); diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index bba44fe50..e5ce59a17 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -677,7 +677,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString())); } - wtxHeight = mapBlockIndex[wtx.hashBlock]->GetHeight(); + wtxHeight = komodo_blockheight(wtx.hashBlock); wtxDepth = wtx.GetDepthInMainChain(); } LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 0ea17a5f8..45d61b885 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -836,7 +836,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString())); } - wtxHeight = mapBlockIndex[wtx.hashBlock]->GetHeight(); + wtxHeight = komodo_blockheight(wtx.hashBlock); wtxDepth = wtx.GetDepthInMainChain(); } LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 847205ec1..028b18861 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -122,10 +122,10 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("generated", true)); if (confirms > 0) { - entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)mapBlockIndex[wtx.hashBlock]->GetHeight(),confirms))); + entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)komodo_blockheight(wtx.hashBlock),confirms))); entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + entry.push_back(Pair("blocktime", komodo_blocktime(wtx.hashBlock))); entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); } else entry.push_back(Pair("confirmations", confirms)); uint256 hash = wtx.GetHash(); @@ -1624,7 +1624,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) tallyitem& item = mapTally[address]; item.nAmount += txout.nValue; // komodo_interest? item.nConf = min(item.nConf, nDepth); - item.nHeight = mapBlockIndex[wtx.hashBlock]->GetHeight(); + item.nHeight = komodo_blockheight(wtx.hashBlock); item.txids.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) item.fIsWatchonly = true; From 564da3c9826d7d830453693a3060f2e3ddb31e1c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:33:31 -1100 Subject: [PATCH 07/20] Change mapblockindex[] into function calls with guards --- src/cc/CCutils.cpp | 2 +- src/cc/payments.cpp | 6 +++--- src/main.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 3c4c6c67c..f47bc4212 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -623,7 +623,7 @@ bool komodo_txnotarizedconfirmed(uint256 txid) fprintf(stderr,"komodo_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str()); return(0); } - else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txheight= pindex->GetHeight()) <= 0 ) + else if ( (pindex= komodo_blockindex(hashBlock)) == 0 || (txheight= pindex->GetHeight()) <= 0 ) { fprintf(stderr,"komodo_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str()); return(0); diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 526fea52f..8bd41b333 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -314,10 +314,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } } // check the chain depth vs locked blocks requirement. - CBlockIndex* pblockindex = mapBlockIndex[blockhash]; - if ( pblockindex->GetHeight() > ht-lockedblocks ) + CBlockIndex* pblockindex = komodo_blockindex(blockhash); + if ( pblockindex == 0 || pblockindex->GetHeight() > ht-lockedblocks ) { - fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex->GetHeight(), ht-lockedblocks); + fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex!=0?pblockindex->GetHeight():0, ht-lockedblocks); return(eval->Invalid("vin not elegible")); } } else return(eval->Invalid("cant get vin transaction")); diff --git a/src/main.cpp b/src/main.cpp index 40da1b855..2e0102b8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6413,8 +6413,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) nLoaded++; if (state.IsError()) break; - } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->GetHeight() % 1000 == 0) { - LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->GetHeight()); + } else if (hash != chainparams.GetConsensus().hashGenesisBlock && komodo_blockheight(hash) % 1000 == 0) { + LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), komodo_blockheight(hash)); } // Recursively process earlier encountered successors of this block From f79d72fb94630e8c4e962fc1681725c6c4615ac2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:34:31 -1100 Subject: [PATCH 08/20] Include file --- src/wallet/asyncrpcoperation_mergetoaddress.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index e5ce59a17..3268c2f0d 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -46,6 +46,7 @@ #include #include "paymentdisclosuredb.h" +#include "komodo_defs.h" using namespace libzcash; From 124156f956a3bdb8bcb79589ddb0d83b89743f00 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:36:46 -1100 Subject: [PATCH 09/20] int32_t komodo_blockheight(uint256 hash); --- src/wallet/asyncrpcoperation_mergetoaddress.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 3268c2f0d..82860d18e 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -46,7 +46,7 @@ #include #include "paymentdisclosuredb.h" -#include "komodo_defs.h" +int32_t komodo_blockheight(uint256 hash); using namespace libzcash; From 70015ce70d6ee1dfe9cb5ab867513f7d29bf380e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:37:51 -1100 Subject: [PATCH 10/20] int32_t komodo_blockheight(uint256 hash); --- src/wallet/asyncrpcoperation_sendmany.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 45d61b885..bc335fc4c 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -55,6 +55,7 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[65]; int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +int32_t komodo_blockheight(uint256 hash); int tx_height( const uint256 &hash ); extern UniValue signrawtransaction(const UniValue& params, bool fHelp); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); From 0b66a88ba29347d1f171e255836fe70326717c84 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:40:49 -1100 Subject: [PATCH 11/20] int32_t komodo_blockheight(uint256 hash); --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 028b18861..c73e177cd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -125,7 +125,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)komodo_blockheight(wtx.hashBlock),confirms))); entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", komodo_blocktime(wtx.hashBlock))); + entry.push_back(Pair("blocktime", (uint64_t)komodo_blocktime(wtx.hashBlock))); entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); } else entry.push_back(Pair("confirmations", confirms)); uint256 hash = wtx.GetHash(); From 74b256333469d431bf8020cca4125de26d4a2570 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Apr 2019 07:58:05 -0700 Subject: [PATCH 12/20] Reduce unnecessary warnings to STDOUT --- src/komodo_bitcoind.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index b342cc932..2fc8f480e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -75,7 +75,8 @@ int tx_height( const uint256 &hash ){ nHeight = it->second->GetHeight(); //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); } else { - fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); + // Unconfirmed xtns + //fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); } return nHeight; } From 1a9f6cb60796f5ee49520c22b2ea332403505ced Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Mon, 22 Apr 2019 20:27:28 +0300 Subject: [PATCH 13/20] return OpenSSL 1.1.1a and applied patch More info: - https://github.com/openssl/openssl/issues/7350 - https://github.com/openssl/openssl/commit/f725fe5b4b6504df08e30f5194d321c3025e2336 Without this patch we will get following error: ``` SSL: couldn't create a context: error:00000000:lib(0):func(0):reason(0) ``` during trying to connect HTTPS. --- depends/packages/openssl.mk | 8 +- depends/patches/openssl/ssl_fix.patch | 273 ++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 depends/patches/openssl/ssl_fix.patch diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 96908e151..5c689fe0b 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,8 +1,9 @@ package=openssl -$(package)_version=1.1.1b +$(package)_version=1.1.1a $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=5c557b023230413dfb0756f3137a13e6d726838ccd1430888ad15bfb2b43ea4b +$(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41 +$(package)_patches=ssl_fix.patch define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" @@ -25,7 +26,8 @@ endef define $(package)_preprocess_cmds sed -i.old 's/built on: $date/built on: not available/' util/mkbuildinf.pl && \ - sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure + sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure && \ + patch -p1 < $($(package)_patch_dir)/ssl_fix.patch endef define $(package)_config_cmds diff --git a/depends/patches/openssl/ssl_fix.patch b/depends/patches/openssl/ssl_fix.patch new file mode 100644 index 000000000..d7f79fed5 --- /dev/null +++ b/depends/patches/openssl/ssl_fix.patch @@ -0,0 +1,273 @@ +From f725fe5b4b6504df08e30f5194d321c3025e2336 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Tue, 20 Nov 2018 15:32:55 +0000 +Subject: [PATCH] Fix a RUN_ONCE bug + +We have a number of instances where there are multiple "init" functions for +a single CRYPTO_ONCE variable, e.g. to load config automatically or to not +load config automatically. Unfortunately the RUN_ONCE mechanism was not +correctly giving the right return value where an alternative init function +was being used. + +Reviewed-by: Tim Hudson +(Merged from https://github.com/openssl/openssl/pull/7983) +--- + crypto/init.c | 38 +++++++++----- + include/internal/thread_once.h | 92 ++++++++++++++++++++++++++++++++++ + ssl/ssl_init.c | 6 ++- + 3 files changed, 121 insertions(+), 15 deletions(-) + +diff --git a/crypto/init.c b/crypto/init.c +index 209d1a483da..f20a12f069a 100644 +--- a/crypto/init.c ++++ b/crypto/init.c +@@ -177,12 +177,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete) + + static CRYPTO_ONCE load_crypto_strings = CRYPTO_ONCE_STATIC_INIT; + static int load_crypto_strings_inited = 0; +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_load_crypto_strings) +-{ +- /* Do nothing in this case */ +- return 1; +-} +- + DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) + { + int ret = 1; +@@ -201,6 +195,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) + return ret; + } + ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_crypto_strings, ++ ossl_init_load_crypto_strings) ++{ ++ /* Do nothing in this case */ ++ return 1; ++} ++ + static CRYPTO_ONCE add_all_ciphers = CRYPTO_ONCE_STATIC_INIT; + DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers) + { +@@ -218,6 +219,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers) + return 1; + } + ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_ciphers, ++ ossl_init_add_all_ciphers) ++{ ++ /* Do nothing */ ++ return 1; ++} ++ + static CRYPTO_ONCE add_all_digests = CRYPTO_ONCE_STATIC_INIT; + DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests) + { +@@ -235,7 +243,8 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests) + return 1; + } + +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_add_algs) ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_digests, ++ ossl_init_add_all_digests) + { + /* Do nothing */ + return 1; +@@ -255,7 +264,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_config) + config_inited = 1; + return 1; + } +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_config) ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_config, ossl_init_config) + { + #ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, +@@ -595,8 +604,9 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS) +- && !RUN_ONCE(&load_crypto_strings, +- ossl_init_no_load_crypto_strings)) ++ && !RUN_ONCE_ALT(&load_crypto_strings, ++ ossl_init_no_load_crypto_strings, ++ ossl_init_load_crypto_strings)) + return 0; + + if ((opts & OPENSSL_INIT_LOAD_CRYPTO_STRINGS) +@@ -604,7 +614,8 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS) +- && !RUN_ONCE(&add_all_ciphers, ossl_init_no_add_algs)) ++ && !RUN_ONCE_ALT(&add_all_ciphers, ossl_init_no_add_all_ciphers, ++ ossl_init_add_all_ciphers)) + return 0; + + if ((opts & OPENSSL_INIT_ADD_ALL_CIPHERS) +@@ -612,7 +623,8 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_ADD_ALL_DIGESTS) +- && !RUN_ONCE(&add_all_digests, ossl_init_no_add_algs)) ++ && !RUN_ONCE_ALT(&add_all_digests, ossl_init_no_add_all_digests, ++ ossl_init_add_all_digests)) + return 0; + + if ((opts & OPENSSL_INIT_ADD_ALL_DIGESTS) +@@ -624,7 +636,7 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG) +- && !RUN_ONCE(&config, ossl_init_no_config)) ++ && !RUN_ONCE_ALT(&config, ossl_init_no_config, ossl_init_config)) + return 0; + + if (opts & OPENSSL_INIT_LOAD_CONFIG) { +diff --git a/include/internal/thread_once.h b/include/internal/thread_once.h +index 224244353ab..e268a959ef3 100644 +--- a/include/internal/thread_once.h ++++ b/include/internal/thread_once.h +@@ -9,6 +9,20 @@ + + #include + ++/* ++ * DEFINE_RUN_ONCE: Define an initialiser function that should be run exactly ++ * once. It takes no arguments and returns and int result (1 for success or ++ * 0 for failure). Typical usage might be: ++ * ++ * DEFINE_RUN_ONCE(myinitfunc) ++ * { ++ * do_some_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ */ + #define DEFINE_RUN_ONCE(init) \ + static int init(void); \ + int init##_ossl_ret_ = 0; \ +@@ -17,10 +31,30 @@ + init##_ossl_ret_ = init(); \ + } \ + static int init(void) ++ ++/* ++ * DECLARE_RUN_ONCE: Declare an initialiser function that should be run exactly ++ * once that has been defined in another file via DEFINE_RUN_ONCE(). ++ */ + #define DECLARE_RUN_ONCE(init) \ + extern int init##_ossl_ret_; \ + void init##_ossl_(void); + ++/* ++ * DEFINE_RUN_ONCE_STATIC: Define an initialiser function that should be run ++ * exactly once. This function will be declared as static within the file. It ++ * takes no arguments and returns and int result (1 for success or 0 for ++ * failure). Typical usage might be: ++ * ++ * DEFINE_RUN_ONCE_STATIC(myinitfunc) ++ * { ++ * do_some_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ */ + #define DEFINE_RUN_ONCE_STATIC(init) \ + static int init(void); \ + static int init##_ossl_ret_ = 0; \ +@@ -30,6 +64,46 @@ + } \ + static int init(void) + ++/* ++ * DEFINE_RUN_ONCE_STATIC_ALT: Define an alternative initialiser function. This ++ * function will be declared as static within the file. It takes no arguments ++ * and returns an int result (1 for success or 0 for failure). An alternative ++ * initialiser function is expected to be associated with a primary initialiser ++ * function defined via DEFINE_ONCE_STATIC where both functions use the same ++ * CRYPTO_ONCE object to synchronise. Where an alternative initialiser function ++ * is used only one of the primary or the alternative initialiser function will ++ * ever be called - and that function will be called exactly once. Definitition ++ * of an alternative initialiser function MUST occur AFTER the definition of the ++ * primary initialiser function. ++ * ++ * Typical usage might be: ++ * ++ * DEFINE_RUN_ONCE_STATIC(myinitfunc) ++ * { ++ * do_some_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ * ++ * DEFINE_RUN_ONCE_STATIC_ALT(myaltinitfunc, myinitfunc) ++ * { ++ * do_some_alternative_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ */ ++#define DEFINE_RUN_ONCE_STATIC_ALT(initalt, init) \ ++ static int initalt(void); \ ++ static void initalt##_ossl_(void) \ ++ { \ ++ init##_ossl_ret_ = initalt(); \ ++ } \ ++ static int initalt(void) ++ + /* + * RUN_ONCE - use CRYPTO_THREAD_run_once, and check if the init succeeded + * @once: pointer to static object of type CRYPTO_ONCE +@@ -43,3 +117,21 @@ + */ + #define RUN_ONCE(once, init) \ + (CRYPTO_THREAD_run_once(once, init##_ossl_) ? init##_ossl_ret_ : 0) ++ ++/* ++ * RUN_ONCE_ALT - use CRYPTO_THREAD_run_once, to run an alternative initialiser ++ * function and check if that initialisation succeeded ++ * @once: pointer to static object of type CRYPTO_ONCE ++ * @initalt: alternative initialiser function name that was previously given to ++ * DEFINE_RUN_ONCE_STATIC_ALT. This function must return 1 for ++ * success or 0 for failure. ++ * @init: primary initialiser function name that was previously given to ++ * DEFINE_RUN_ONCE_STATIC. This function must return 1 for success or ++ * 0 for failure. ++ * ++ * The return value is 1 on success (*) or 0 in case of error. ++ * ++ * (*) by convention, since the init function must return 1 on success. ++ */ ++#define RUN_ONCE_ALT(once, initalt, init) \ ++ (CRYPTO_THREAD_run_once(once, initalt##_ossl_) ? init##_ossl_ret_ : 0) +diff --git a/ssl/ssl_init.c b/ssl/ssl_init.c +index c0ccb9304a6..96526472c57 100644 +--- a/ssl/ssl_init.c ++++ b/ssl/ssl_init.c +@@ -134,7 +134,8 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_ssl_strings) + return 1; + } + +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_load_ssl_strings) ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_ssl_strings, ++ ossl_init_load_ssl_strings) + { + /* Do nothing in this case */ + return 1; +@@ -207,7 +208,8 @@ int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS * settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_LOAD_SSL_STRINGS) +- && !RUN_ONCE(&ssl_strings, ossl_init_no_load_ssl_strings)) ++ && !RUN_ONCE_ALT(&ssl_strings, ossl_init_no_load_ssl_strings, ++ ossl_init_load_ssl_strings)) + return 0; + + if ((opts & OPENSSL_INIT_LOAD_SSL_STRINGS) From 0930945aa0c7db4a990726ee24bfed7b1c8bd04b Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Mon, 22 Apr 2019 20:54:49 +0300 Subject: [PATCH 14/20] remove debug delays in libcurl.mk --- depends/packages/libcurl.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 1ce0a9161..71e9803a4 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -26,7 +26,6 @@ endif define $(package)_config_cmds echo '=== config for $(package):' && \ echo '$($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts)' && \ - sleep 10 && \ echo '=== ' && \ $($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts) endef @@ -43,6 +42,5 @@ endif define $(package)_stage_cmds echo 'Staging dir: $($(package)_staging_dir)$(host_prefix)/' && \ - sleep 10 && \ $(MAKE) DESTDIR=$($(package)_staging_dir) install endef From c4c5746e9c9988de03c506ca02354b580865e8d6 Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Mon, 22 Apr 2019 20:56:25 +0300 Subject: [PATCH 15/20] added config flags to openssl to make libcurl HTTPS connections work OpenSSL needs to be built with sock, ssl, tls and des. all other config options can be disabled, like in ZCash. --- depends/packages/openssl.mk | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 5c689fe0b..c5ac5bb32 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -8,7 +8,71 @@ $(package)_patches=ssl_fix.patch define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl +$(package)_config_opts+=no-afalgeng +$(package)_config_opts+=no-asm +$(package)_config_opts+=no-async +$(package)_config_opts+=no-bf +$(package)_config_opts+=no-blake2 +$(package)_config_opts+=no-camellia +$(package)_config_opts+=no-capieng +$(package)_config_opts+=no-cast +$(package)_config_opts+=no-chacha +$(package)_config_opts+=no-cmac +$(package)_config_opts+=no-cms +$(package)_config_opts+=no-comp +$(package)_config_opts+=no-crypto-mdebug +$(package)_config_opts+=no-crypto-mdebug-backtrace +$(package)_config_opts+=no-ct +$(package)_config_opts+=no-dgram +$(package)_config_opts+=no-dsa +$(package)_config_opts+=no-dso +$(package)_config_opts+=no-dtls +$(package)_config_opts+=no-dtls1 +$(package)_config_opts+=no-dtls1-method +$(package)_config_opts+=no-dynamic-engine +$(package)_config_opts+=no-ec2m +$(package)_config_opts+=no-ec_nistp_64_gcc_128 +$(package)_config_opts+=no-egd +$(package)_config_opts+=no-engine +$(package)_config_opts+=no-err +$(package)_config_opts+=no-gost +$(package)_config_opts+=no-heartbeats +$(package)_config_opts+=no-idea +$(package)_config_opts+=no-md2 +$(package)_config_opts+=no-md4 +$(package)_config_opts+=no-mdc2 +$(package)_config_opts+=no-multiblock +$(package)_config_opts+=no-nextprotoneg +$(package)_config_opts+=no-ocb +$(package)_config_opts+=no-ocsp +$(package)_config_opts+=no-poly1305 +$(package)_config_opts+=no-posix-io +$(package)_config_opts+=no-psk +$(package)_config_opts+=no-rc2 +$(package)_config_opts+=no-rc4 +$(package)_config_opts+=no-rc5 +$(package)_config_opts+=no-rdrand +$(package)_config_opts+=no-rfc3779 +$(package)_config_opts+=no-rmd160 +$(package)_config_opts+=no-scrypt +$(package)_config_opts+=no-sctp +$(package)_config_opts+=no-seed $(package)_config_opts+=no-shared +$(package)_config_opts+=no-srp +$(package)_config_opts+=no-srtp +$(package)_config_opts+=no-ssl3 +$(package)_config_opts+=no-ssl3-method +$(package)_config_opts+=no-ssl-trace +$(package)_config_opts+=no-stdio +$(package)_config_opts+=no-tls1 +$(package)_config_opts+=no-tls1-method +$(package)_config_opts+=no-ts +$(package)_config_opts+=no-ui +$(package)_config_opts+=no-unit-test +$(package)_config_opts+=no-weak-ssl-ciphers +$(package)_config_opts+=no-whirlpool +$(package)_config_opts+=no-zlib +$(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) $(package)_config_opts+=-DPURIFY $(package)_config_opts_linux=-fPIC -Wa,--noexecstack From 191fc2e152b94db232863d65f02763727593a91b Mon Sep 17 00:00:00 2001 From: Bartlomiej Lisiecki Date: Fri, 1 Feb 2019 14:54:48 +0100 Subject: [PATCH 16/20] Add support for importing and exporting sapling ivk --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/ivk_import_export.py | 137 +++++++++++++++++++++++++ src/gtest/test_keys.cpp | 14 +++ src/key_io.cpp | 28 ++++- src/wallet/gtest/test_wallet.cpp | 53 ++++++++++ src/wallet/gtest/test_wallet_zkeys.cpp | 3 + src/wallet/rpcdump.cpp | 63 ++++++++---- src/wallet/rpcwallet.cpp | 3 +- src/wallet/wallet.cpp | 99 ++++++++++++------ src/wallet/wallet.h | 13 +++ src/zcash/Address.hpp | 2 +- 11 files changed, 364 insertions(+), 52 deletions(-) create mode 100755 qa/rpc-tests/ivk_import_export.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index c4775fa85..24e8566d5 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -65,6 +65,7 @@ testScripts=( 'disablewallet.py' 'zcjoinsplit.py' 'zcjoinsplitdoublespend.py' + 'ivk_import_export.py' 'zkey_import_export.py' 'reorg_limit.py' 'getblocktemplate.py' diff --git a/qa/rpc-tests/ivk_import_export.py b/qa/rpc-tests/ivk_import_export.py new file mode 100755 index 000000000..0546b0a44 --- /dev/null +++ b/qa/rpc-tests/ivk_import_export.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python2 +# Copyright (c) 2019 Bartlomiej Lisiecki +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from decimal import Decimal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_greater_than, start_nodes,\ + initialize_chain_clean, connect_nodes_bi, wait_and_assert_operationid_status + +import logging + +logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) + +fee = Decimal('0.0001') # constant (but can be changed within reason) + +class IVKImportExportTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self, split=False): + self.nodes = start_nodes(4, self.options.tmpdir, [[ + '-nuparams=5ba81b19:101', # Overwinter + '-nuparams=76b809bb:102', # Sapling + ]] * 4) + + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,0,3) + self.is_network_split=False + self.sync_all() + + def run_test(self): + [alice, bob, charlie, miner] = self.nodes + + # the sender loses 'amount' plus fee; to_addr receives exactly 'amount' + def z_send(from_node, from_addr, to_addr, amount): + global fee + opid = from_node.z_sendmany(from_addr, + [{"address": to_addr, "amount": Decimal(amount)}], 1, fee) + wait_and_assert_operationid_status(from_node, opid) + self.sync_all() + miner.generate(1) + self.sync_all() + + def verify_utxos(node, amts, zaddr): + amts.sort(reverse=True) + txs = node.z_listreceivedbyaddress(zaddr) + + def cmp_confirmations_high_to_low(a, b): + return cmp(b["amount"], a["amount"]) + + txs.sort(cmp_confirmations_high_to_low) + print("Sorted txs", txs) + print("amts", amts) + + try: + assert_equal(amts, [tx["amount"] for tx in txs]) + except AssertionError: + logging.error( + 'Expected amounts: %r; txs: %r', + amts, txs) + raise + + def get_private_balance(node): + balance = node.z_gettotalbalance() + return balance['private'] + + def find_imported_zaddr(node, import_zaddr): + zaddrs = node.z_listaddresses() + assert(import_zaddr in zaddrs) + return import_zaddr + + # activate sapling + alice.generate(102) + self.sync_all() + + # sanity-check the test harness + assert_equal(self.nodes[0].getblockcount(), 102) + + # shield alice's coinbase funds to her zaddr + alice_zaddr = alice.z_getnewaddress('sapling') + res = alice.z_shieldcoinbase("*", alice_zaddr) + wait_and_assert_operationid_status(alice, res['opid']) + self.sync_all() + miner.generate(1) + self.sync_all() + + # the amounts of each txn embodied which generates a single utxo: + amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) + + # internal test consistency assertion: + assert_greater_than( + get_private_balance(alice), + reduce(Decimal.__add__, amounts)) + + + # now get a pristine z-address for receiving transfers: + bob_zaddr = bob.z_getnewaddress('sapling') + verify_utxos(bob, [], bob_zaddr) + + logging.info("sending pre-export txns...") + for amount in amounts[0:2]: + z_send(alice, alice_zaddr, bob_zaddr, amount) + + logging.info("exporting ivk from bob...") + bob_ivk = bob.z_exportviewingkey(bob_zaddr) + + logging.info("sending post-export txns...") + for amount in amounts[2:4]: + z_send(alice, alice_zaddr, bob_zaddr, amount) + + verify_utxos(bob, amounts[:4], bob_zaddr) + + logging.info("importing bob_ivk into charlie...") + # we need to pass bob_zaddr since it's a sapling address + charlie.z_importviewingkey(bob_ivk, 'yes', 0, bob_zaddr) + + # z_importkey should have rescanned for new key, so this should pass: + verify_utxos(charlie, amounts[:4], bob_zaddr) + + # verify idempotent behavior: + charlie.z_importviewingkey(bob_ivk, 'yes', 0, bob_zaddr) + verify_utxos(charlie, amounts[:4], bob_zaddr) + + + logging.info("Sending post-import txns...") + for amount in amounts[4:]: + z_send(alice, alice_zaddr, bob_zaddr, amount) + + verify_utxos(bob, amounts, bob_zaddr) + verify_utxos(charlie, amounts, bob_zaddr) + +if __name__ == '__main__': + IVKImportExportTest().main() diff --git a/src/gtest/test_keys.cpp b/src/gtest/test_keys.cpp index bd9599421..ae5831261 100644 --- a/src/gtest/test_keys.cpp +++ b/src/gtest/test_keys.cpp @@ -44,5 +44,19 @@ TEST(Keys, EncodeAndDecodeSapling) auto addr2 = boost::get(paymentaddr2); EXPECT_EQ(addr, addr2); } + { + auto ivk = sk.ToXFVK().fvk.in_viewing_key(); + std::string ivk_string = EncodeViewingKey(ivk); + EXPECT_EQ( + ivk_string.substr(0, 5), + Params().Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY)); + + auto viewing_key = DecodeViewingKey(ivk_string); + EXPECT_TRUE(IsValidViewingKey(viewing_key)); + + auto ivk2 = boost::get(&viewing_key); + ASSERT_TRUE(ivk2 != nullptr); + EXPECT_EQ(*ivk2, ivk); + } } } diff --git a/src/key_io.cpp b/src/key_io.cpp index 1953d9623..014159d65 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -128,6 +128,19 @@ public: return ret; } + std::string operator()(const libzcash::SaplingIncomingViewingKey& vk) const + { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << vk; + std::vector serkey(ss.begin(), ss.end()); + std::vector data; + ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end()); + std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY), data); + memory_cleanse(serkey.data(), serkey.size()); + memory_cleanse(data.data(), data.size()); + return ret; + } + std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; } }; @@ -175,6 +188,7 @@ public: // perform ceiling division to get the number of 5-bit clusters. const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5; const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5; +const size_t ConvertedSaplingIncomingViewingKeySize = (32 * 8 + 4) / 5; } // namespace CKey DecodeSecret(const std::string& str) @@ -346,7 +360,19 @@ libzcash::ViewingKey DecodeViewingKey(const std::string& str) return ret; } } - memory_cleanse(data.data(), data.size()); + data.clear(); + auto bech = bech32::Decode(str); + if(bech.first == Params().Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY) && + bech.second.size() == ConvertedSaplingIncomingViewingKeySize) { + // Bech32 decoding + data.reserve((bech.second.size() * 5) / 8); + if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) { + CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION); + libzcash::SaplingIncomingViewingKey ret; + ss >> ret; + return ret; + } + } return libzcash::InvalidEncoding(); } diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 2b1a89cc7..1fe9db11a 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -526,6 +526,59 @@ TEST(WalletTests, FindMySaplingNotes) { UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } +TEST(WalletTests, FindMySaplingNotesWithIvkOnly) { + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + auto consensusParams = Params().GetConsensus(); + + TestWallet wallet; + + // Generate dummy Sapling address + std::vector> rawSeed(32); + HDSeed seed(rawSeed); + auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed); + auto addr = sk.DefaultAddress(); + auto expsk = sk.expsk; + auto fvk = expsk.full_viewing_key(); + auto pk = sk.DefaultAddress(); + auto ivk = fvk.in_viewing_key(); + + // Generate dummy Sapling note + libzcash::SaplingNote note(pk, 50000); + auto cm = note.cm().get(); + SaplingMerkleTree tree; + tree.append(cm); + auto anchor = tree.root(); + auto witness = tree.witness(); + + // Generate transaction + auto builder = TransactionBuilder(consensusParams, 1); + ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness)); + builder.AddSaplingOutput(fvk.ovk, pk, 25000, {}); + auto maybe_tx = builder.Build(); + ASSERT_EQ(static_cast(maybe_tx), true); + auto tx = maybe_tx.get(); + + // No Sapling notes can be found in tx which does not belong to the wallet + CWalletTx wtx {&wallet, tx}; + ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk)); + ASSERT_FALSE(wallet.HaveSaplingIncomingViewingKey(addr)); + auto noteMap = wallet.FindMySaplingNotes(wtx).first; + EXPECT_EQ(0, noteMap.size()); + + // Add ivk to wallet, so Sapling notes can be found + ASSERT_TRUE(wallet.AddSaplingIncomingViewingKey(ivk, addr)); + ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk)); + ASSERT_TRUE(wallet.HaveSaplingIncomingViewingKey(addr)); + noteMap = wallet.FindMySaplingNotes(wtx).first; + EXPECT_EQ(2, noteMap.size()); + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); +} + TEST(WalletTests, FindMySproutNotes) { CWallet wallet; diff --git a/src/wallet/gtest/test_wallet_zkeys.cpp b/src/wallet/gtest/test_wallet_zkeys.cpp index 5f022c5d5..365533b6c 100644 --- a/src/wallet/gtest/test_wallet_zkeys.cpp +++ b/src/wallet/gtest/test_wallet_zkeys.cpp @@ -82,6 +82,9 @@ TEST(wallet_zkeys_tests, StoreAndLoadSaplingZkeys) { EXPECT_TRUE(wallet.HaveSaplingIncomingViewingKey(sk.DefaultAddress())); EXPECT_TRUE(wallet.HaveSaplingIncomingViewingKey(dpa)); + // verify that resets nTimeFirstKey, since there is no birthday info for watch-only keys + EXPECT_EQ(wallet.nTimeFirstKey, 1); + // Load a third key into the wallet auto sk2 = m.Derive(1); ASSERT_TRUE(wallet.LoadSaplingZKey(sk2)); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index c66ce3485..05552b50b 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -694,7 +694,7 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() < 1 || params.size() > 3) + if (fHelp || params.size() < 1 || params.size() > 4) throw runtime_error( "z_importviewingkey \"vkey\" ( rescan startHeight )\n" "\nAdds a viewing key (as returned by z_exportviewingkey) to your wallet.\n" @@ -702,6 +702,7 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) "1. \"vkey\" (string, required) The viewing key (see z_exportviewingkey)\n" "2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n" "3. startHeight (numeric, optional, default=0) Block height to start rescan from\n" + "4. zaddr (string, optional, default=\"\") zaddr in case of importing viewing key for Sapling\n" "\nNote: This call can take minutes to complete if rescan is true.\n" "\nExamples:\n" "\nImport a viewing key\n" @@ -712,6 +713,8 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) + HelpExampleCli("z_importviewingkey", "\"vkey\" whenkeyisnew 30000") + "\nRe-import the viewing key with longer partial rescan\n" + HelpExampleCli("z_importviewingkey", "\"vkey\" yes 20000") + + "\nImport the viewing key for Sapling address\n" + + HelpExampleCli("z_importviewingkey", "\"vkey\" no 0 \"zaddr\"") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("z_importviewingkey", "\"vkey\", \"no\"") ); @@ -751,14 +754,34 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) if (!IsValidViewingKey(viewingkey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key"); } - // TODO: Add Sapling support. For now, return an error to the user. - if (boost::get(&viewingkey) == nullptr) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Currently, only Sprout viewing keys are supported"); - } - auto vkey = boost::get(viewingkey); - auto addr = vkey.address(); - { + if (boost::get(&viewingkey) == nullptr) { + if (params.size() < 4) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Missing zaddr for Sapling viewing key."); + } + string strAddress = params[3].get_str(); + auto address = DecodePaymentAddress(strAddress); + if (!IsValidPaymentAddress(address)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); + } + + auto addr = boost::get(address); + auto ivk = boost::get(viewingkey); + + if (pwalletMain->HaveSaplingIncomingViewingKey(addr)) { + if (fIgnoreExistingKey) { + return NullUniValue; + } + } else { + pwalletMain->MarkDirty(); + + if (!pwalletMain->AddSaplingIncomingViewingKey(ivk, addr)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); + } + } + } else { + auto vkey = boost::get(viewingkey); + auto addr = vkey.address(); if (pwalletMain->HaveSproutSpendingKey(addr)) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this viewing key"); } @@ -775,13 +798,12 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); } } - - // We want to scan for transactions and notes - if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true); - } } + // We want to scan for transactions and notes + if (fRescan) { + pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true); + } return NullUniValue; } @@ -853,12 +875,17 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp) if (!IsValidPaymentAddress(address)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); } - // TODO: Add Sapling support. For now, return an error to the user. - if (boost::get(&address) == nullptr) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Currently, only Sprout zaddrs are supported"); - } - auto addr = boost::get(address); + if (boost::get(&address) == nullptr) { + auto addr = boost::get(address); + libzcash::SaplingIncomingViewingKey ivk; + if(!pwalletMain->GetSaplingIncomingViewingKey(addr, ivk)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold viewing key for this zaddr"); + } + return EncodeViewingKey(ivk); + } + + auto addr = boost::get(address); libzcash::SproutViewingKey vk; if (!pwalletMain->GetSproutViewingKey(addr, vk)) { libzcash::SproutSpendingKey k; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a21de63f4..93b438e19 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3915,7 +3915,8 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) } // Visitor to support Sprout and Sapling addrs - if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr)) { + if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr) && + !boost::apply_visitor(IncomingViewingKeyBelongsToWallet(pwalletMain), zaddr)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9b2975db1..fa39d204a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -185,6 +185,7 @@ bool CWallet::AddSaplingZKey( return false; } + nTimeFirstKey = 1; // No birthday information for viewing keys. if (!fFileBacked) { return true; } @@ -1541,26 +1542,29 @@ void CWallet::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) { } else { uint64_t position = nd.witnesses.front().position(); - SaplingFullViewingKey fvk = mapSaplingFullViewingKeys.at(nd.ivk); - OutputDescription output = wtx.vShieldedOutput[op.n]; - auto optPlaintext = SaplingNotePlaintext::decrypt(output.encCiphertext, nd.ivk, output.ephemeralKey, output.cm); - if (!optPlaintext) { - // An item in mapSaplingNoteData must have already been successfully decrypted, - // otherwise the item would not exist in the first place. - assert(false); + // Skip if we only have incoming viewing key + if (mapSaplingFullViewingKeys.count(nd.ivk) != 0) { + SaplingFullViewingKey fvk = mapSaplingFullViewingKeys.at(nd.ivk); + OutputDescription output = wtx.vShieldedOutput[op.n]; + auto optPlaintext = SaplingNotePlaintext::decrypt(output.encCiphertext, nd.ivk, output.ephemeralKey, output.cm); + if (!optPlaintext) { + // An item in mapSaplingNoteData must have already been successfully decrypted, + // otherwise the item would not exist in the first place. + assert(false); + } + auto optNote = optPlaintext.get().note(nd.ivk); + if (!optNote) { + assert(false); + } + auto optNullifier = optNote.get().nullifier(fvk, position); + if (!optNullifier) { + // This should not happen. If it does, maybe the position has been corrupted or miscalculated? + assert(false); + } + uint256 nullifier = optNullifier.get(); + mapSaplingNullifiersToNotes[nullifier] = op; + item.second.nullifier = nullifier; } - auto optNote = optPlaintext.get().note(nd.ivk); - if (!optNote) { - assert(false); - } - auto optNullifier = optNote.get().nullifier(fvk, position); - if (!optNullifier) { - // This should not happen. If it does, maybe the position has been corrupted or miscalculated? - assert(false); - } - uint256 nullifier = optNullifier.get(); - mapSaplingNullifiersToNotes[nullifier] = op; - item.second.nullifier = nullifier; } } } @@ -1991,23 +1995,40 @@ std::pair CWallet::FindMySap // Protocol Spec: 4.19 Block Chain Scanning (Sapling) for (uint32_t i = 0; i < tx.vShieldedOutput.size(); ++i) { const OutputDescription output = tx.vShieldedOutput[i]; + bool found = false; for (auto it = mapSaplingFullViewingKeys.begin(); it != mapSaplingFullViewingKeys.end(); ++it) { SaplingIncomingViewingKey ivk = it->first; auto result = SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cm); - if (!result) { - continue; + if (result) { + auto address = ivk.address(result.get().d); + if (address && mapSaplingIncomingViewingKeys.count(address.get()) == 0) { + viewingKeysToAdd[address.get()] = ivk; + } + // We don't cache the nullifier here as computing it requires knowledge of the note position + // in the commitment tree, which can only be determined when the transaction has been mined. + SaplingOutPoint op {hash, i}; + SaplingNoteData nd; + nd.ivk = ivk; + noteData.insert(std::make_pair(op, nd)); + found = true; + break; } - auto address = ivk.address(result.get().d); - if (address && mapSaplingIncomingViewingKeys.count(address.get()) == 0) { - viewingKeysToAdd[address.get()] = ivk; + } + if (!found) { + for (auto it = mapSaplingIncomingViewingKeys.begin(); it != mapSaplingIncomingViewingKeys.end(); ++it) { + SaplingIncomingViewingKey ivk = it-> second; + auto result = SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cm); + if (!result) { + continue; + } + // We don't cache the nullifier here as computing it requires knowledge of the note position + // in the commitment tree, which can only be determined when the transaction has been mined. + SaplingOutPoint op {hash, i}; + SaplingNoteData nd; + nd.ivk = ivk; + noteData.insert(std::make_pair(op, nd)); + break; } - // We don't cache the nullifier here as computing it requires knowledge of the note position - // in the commitment tree, which can only be determined when the transaction has been mined. - SaplingOutPoint op {hash, i}; - SaplingNoteData nd; - nd.ivk = ivk; - noteData.insert(std::make_pair(op, nd)); - break; } } @@ -5071,6 +5092,22 @@ void CWallet::GetFilteredNotes( // Shielded key and address generalizations // +bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const +{ + return m_wallet->HaveSproutViewingKey(zaddr); +} + +bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const +{ + libzcash::SaplingIncomingViewingKey ivk; + return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk); +} + +bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const +{ + return false; +} + bool PaymentAddressBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const { return m_wallet->HaveSproutSpendingKey(zaddr) || m_wallet->HaveSproutViewingKey(zaddr); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 10aa83ce6..b00365a77 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1392,6 +1392,19 @@ public: bool operator()(const libzcash::InvalidEncoding& no) const; }; + +class IncomingViewingKeyBelongsToWallet : public boost::static_visitor +{ +private: + CWallet *m_wallet; +public: + IncomingViewingKeyBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {} + + bool operator()(const libzcash::SproutPaymentAddress &zaddr) const; + bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const; + bool operator()(const libzcash::InvalidEncoding& no) const; +}; + class HaveSpendingKeyForPaymentAddress : public boost::static_visitor { private: diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index 42f01b57b..42ee0031b 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -219,7 +219,7 @@ public: }; typedef boost::variant PaymentAddress; -typedef boost::variant ViewingKey; +typedef boost::variant ViewingKey; } From a0053d8ef082d085f1d5ecf817167a809cf82953 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Wed, 24 Apr 2019 13:02:08 +0200 Subject: [PATCH 17/20] Defragmenting utxos in Gateways deposit address (#24) - adding up to 3 more utxos when doing withdraw for defragmentation - corrected gateways validation --- src/cc/dapps/oraclefeed.c | 45 ++++++++++++++++++++++----------------- src/cc/gateways.cpp | 35 ++++++++++++++++-------------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index 6ac014ad1..4687837ac 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -592,7 +592,7 @@ void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys) cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) { - cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; + cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,j=0,n,v; int64_t satoshis; bits256 txid; *totalp = 0; if ( (n= cJSON_GetArraySize(unspents)) > 0 ) { @@ -610,7 +610,10 @@ cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) jaddi(vins,vin); *totalp += satoshis; if ( (*totalp) >= required ) - break; + { + if (j<3) j++; + else break; + } } } } @@ -910,10 +913,11 @@ void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxi processed++; } free(rawtx); - } else fprintf(stderr,"couldnt create rawtx\n"); + } else fprintf(stderr,"couldnt create rawtx\n"); } else { + rawtx=0; lasttxid = jbits256(item,"last_txid"); if ( lasttxid.txid==withdrawtxid.txid) { @@ -921,24 +925,27 @@ void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxi } else rawtx=jstr(item,"hex"); K=jint(item,"number_of_signs"); - if ( rawtx!=0 && (clijson=addsignature(refcoin,"",rawtx,M)) != 0 ) + if (rawtx!=0) { - if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) - { - 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 ) + if ((clijson=addsignature(refcoin,"",rawtx,M)) != 0 ) { - 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); - } - free_json(clijson); - processed++; - if ( lasttxid.txid==withdrawtxid.txid) free(rawtx); - } + if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) + { + 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(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); + } + free_json(clijson); + processed++; + if ( lasttxid.txid==withdrawtxid.txid) free(rawtx); + } + } else fprintf(stderr,"couldnt create rawtx or find previous partial signed tx\n"); } } } diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index d88b3d25f..00c80082b 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -628,20 +628,25 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("deposit amount greater then bind total supply"); else if (komodo_txnotarizedconfirmed(deposittxid) == false) return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); - else if (myGetTransaction(tx.vin[2].prevout.hash,tmptx,hashblock) == 0) - return eval->Invalid("invalid gatewaysdeposittxid!"); else if (IsCCInput(tx.vin[0].scriptSig) != 0) return eval->Invalid("vin.0 is normal for gatewaysclaim!"); - else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + else if (tx.vin.size()>2) + { + i=1; + while (i<=tx.vin.size()-2) + { + if (IsCCInput(tx.vin[i].scriptSig)==0) return eval->Invalid("vin."+std::to_string(i)+" is CC for gatewaysclaim!"); + i++; + } + } + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewaysclaim or invalid marker amount!"); else if (_GetCCaddress(destaddr,EVAL_TOKENS,pubkey)==0 || ConstrainVout(tx.vout[0],1,destaddr,amount)==0) return eval->Invalid("invalid vout tokens to destpub for gatewaysclaim!"); - else if (numvouts>2 && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || ConstrainVout(tx.vout[1],1,gatewaystokensaddr,tmptx.vout[tx.vin[1].prevout.n].nValue-amount)==0)) + else if (numvouts>2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || ConstrainVout(tx.vout[1],1,gatewaystokensaddr,tmptx.vout[tx.vin[1].prevout.n].nValue-amount)==0)) return eval->Invalid("invalid CC change vout for gatewaysclaim!"); else if (amount!=tmpamount) - return eval->Invalid("claimed amount different then deposit amount"); - else if (tx.vout[0].nValue!=amount) - return eval->Invalid("claim amount not matching amount in opret"); + return eval->Invalid("claimed amount different then deposit amount"); else if (pubkey!=tmppubkey) return eval->Invalid("claim destination pubkey different than in deposit tx"); else @@ -697,8 +702,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); else if ( ConstrainVout(tmptx.vout[1],1,gatewaystokensaddr,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) @@ -953,7 +956,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,2) > 0 ) { if (AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, totalsupply, 64)>0) { @@ -1032,7 +1035,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( AddNormalinputs(mtx,mypk,txfee+2*CC_MARKER_VALUE,4) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee+2*CC_MARKER_VALUE,3) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,CC_MARKER_VALUE,destpub)); mtx.vout.push_back(CTxOut(CC_MARKER_VALUE,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); @@ -1104,7 +1107,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) { if ((inputs=AddGatewaysInputs(cp, mtx, gatewayspk, bindtxid, amount, 60)) > 0) { @@ -1182,7 +1185,7 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin } } } - if( AddNormalinputs(mtx, mypk, txfee+CC_MARKER_VALUE, 4) > 0 ) + if( AddNormalinputs(mtx, mypk, txfee+CC_MARKER_VALUE, 2) > 0 ) { if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, amount, 60)) > 0) { @@ -1294,7 +1297,7 @@ std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refc return(""); } } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + if (AddNormalinputs(mtx,mypk,txfee,1)!=0) { mtx.vin.push_back(CTxIn(tx.GetHash(),0,CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CC_MARKER_VALUE,gatewayspk)); @@ -1393,7 +1396,7 @@ std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string return(""); } } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + if (AddNormalinputs(mtx,mypk,txfee,1)!=0) { mtx.vin.push_back(CTxIn(lasttxid,0,CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CC_MARKER_VALUE,gatewayspk)); @@ -1458,7 +1461,7 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + if (AddNormalinputs(mtx,mypk,txfee,1)!=0) { mtx.vin.push_back(CTxIn(completetxid,0,CScript())); mtx.vout.push_back(CTxOut(CC_MARKER_VALUE,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); From 8a574b96237a25218d7926e28461c43ff1f53e1b Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Wed, 24 Apr 2019 17:30:21 +0200 Subject: [PATCH 18/20] Corrected ChannelsCC validation. --- src/cc/channels.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 254f7e3a5..64bb95572 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -250,10 +250,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("channelopen is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelpayment!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelpayment!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for channelpayment!"); + else if ( IsCCInput(tx.vin[tx.vin.size()-2].scriptSig) == 0 ) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-2)+" is CC for channelpayment!"); else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 ) return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelpayment!"); else if ( ConstrainVout(tx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 ) @@ -283,8 +281,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid previous tx OP_RETURN data!"); else if ( ConstrainVout(tx.vout[0],1,channeladdress,(p1-param2)*payment)==0 ) return eval->Invalid("vout.0 is CC or invalid CC change amount for channelpayment!"); - else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelpayment!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || prevTx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker or invalid marker amount for channelpayment!"); else if (param1+param2!=p1) return eval->Invalid("invalid payment depth!"); else if (tx.vout[3].nValue > prevTx.vout[0].nValue) @@ -313,10 +311,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("channelopen is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelclose!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelclose!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for channelclose!"); + else if ( IsCCInput(tx.vin[tx.vin.size()-2].scriptSig) == 0 ) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-2)+" is CC for channelclose!"); else if ( ConstrainVout(tx.vout[0],1,channeladdress,0)==0 ) return eval->Invalid("vout.0 is CC for channelclose!"); else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 ) @@ -329,8 +325,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); - else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelclose!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || prevTx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker or invalid marker amount for channelclose!"); else if (tx.vout[0].nValue != prevTx.vout[0].nValue) return eval->Invalid("invalid CC amount, amount must match funds in channel"); } @@ -358,10 +354,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("channelClose is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelrefund!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelrefund!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for channelrefund!"); + else if ( IsCCInput(tx.vin[tx.vin.size()-2].scriptSig) == 0 ) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-2)+" CC for channelrefund!"); else if ( ConstrainVout(tx.vout[0],1,srcmarker,CC_MARKER_VALUE)==0 ) return eval->Invalid("vout.0 is CC marker to srcpub or invalid amount for channelrefund!"); else if ( ConstrainVout(tx.vout[1],1,destmarker,CC_MARKER_VALUE)==0 ) @@ -376,8 +370,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); - else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelrefund!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || prevTx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker or invalid marker amount for channelrefund!"); else if (tx.vout[2].nValue != prevTx.vout[0].nValue) return eval->Invalid("invalid amount, refund amount and funds in channel must match!"); } From 6af417b9901a84cdb844b2baf512e78285a7d6af Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Thu, 25 Apr 2019 14:24:53 +0300 Subject: [PATCH 19/20] build-mac.sh fix on latest libcurl changes https://github.com/jl777/komodo/issues/1452 --- depends/packages/libcurl.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 71e9803a4..159817139 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -32,7 +32,7 @@ endef ifeq ($(build_os),darwin) define $(package)_build_cmds - $(MAKE) CPPFLAGS='-fPIC' CFLAGS='-mmacosx-version-min=10.9' + $(MAKE) CPPFLAGS="-I$(host_prefix)/include -fPIC" CFLAGS='-mmacosx-version-min=10.9' endef else define $(package)_build_cmds From a0aaff137153810c39833d7ce8eb44a14511bf7b Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 29 Apr 2019 12:32:41 +0500 Subject: [PATCH 20/20] fix unmarshal source symbol from rawproof --- src/rpc/rawtransaction.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index c5d2bea86..1c3cb96f2 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -217,7 +217,8 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& { if (rawproof.size() > 0) { - std::string sourceSymbol(rawproof.begin(), rawproof.end()); + std::string sourceSymbol; + E_UNMARSHAL(rawproof, ss >> sourceSymbol); in.push_back(Pair("address", "IMP-" + sourceSymbol + "-" + burnTx.GetHash().ToString())); } }