From 9e0ac062fa1db5ba6d11349cac3289be3c804bd6 Mon Sep 17 00:00:00 2001 From: Duke Date: Tue, 30 Jan 2024 11:23:35 -0500 Subject: [PATCH] Delete a lot of CC stuff #381 --- src/Makefile.am | 7 - src/cc/CCcustom.cpp | 24 +- src/cc/CCutils.cpp | 40 -- src/cc/assets.cpp | 26 - src/cc/auction.cpp | 213 ------- src/cc/betprotocol.cpp | 305 --------- src/cc/faucet.cpp | 253 -------- src/cc/fsm.cpp | 192 ------ src/cc/heir.cpp | 1293 -------------------------------------- src/cc/oracles.cpp | 1233 ------------------------------------ src/rpc/server.cpp | 12 +- src/rpc/server.h | 10 - src/wallet/rpcwallet.cpp | 233 +------ 13 files changed, 16 insertions(+), 3825 deletions(-) delete mode 100644 src/cc/assets.cpp delete mode 100644 src/cc/auction.cpp delete mode 100644 src/cc/betprotocol.cpp delete mode 100644 src/cc/faucet.cpp delete mode 100644 src/cc/fsm.cpp delete mode 100644 src/cc/heir.cpp delete mode 100644 src/cc/oracles.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 2e890ebd7..97ae53ae1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -276,13 +276,6 @@ libbitcoin_server_a_SOURCES = \ cc/CCcustom.cpp \ cc/CCtx.cpp \ cc/CCutils.cpp \ - cc/assets.cpp \ - cc/faucet.cpp \ - cc/fsm.cpp \ - cc/heir.cpp \ - cc/oracles.cpp \ - cc/auction.cpp \ - cc/betprotocol.cpp \ chain.cpp \ checkpoints.cpp \ fs.cpp \ diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index 28e15b148..1e9653609 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -295,16 +295,16 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) strcpy(cp->normaladdr,AssetsNormaladdr); strcpy(cp->CChexstr,AssetsCChexstr); memcpy(cp->CCpriv,AssetsCCpriv,32); - cp->validate = AssetsValidate; - cp->ismyvin = IsAssetsInput; + //cp->validate = AssetsValidate; + //cp->ismyvin = IsAssetsInput; break; case EVAL_FAUCET: strcpy(cp->unspendableCCaddr,FaucetCCaddr); strcpy(cp->normaladdr,FaucetNormaladdr); strcpy(cp->CChexstr,FaucetCChexstr); memcpy(cp->CCpriv,FaucetCCpriv,32); - cp->validate = FaucetValidate; - cp->ismyvin = IsFaucetInput; + //cp->validate = FaucetValidate; + //cp->ismyvin = IsFaucetInput; break; case EVAL_REWARDS: strcpy(cp->unspendableCCaddr,RewardsCCaddr); @@ -335,24 +335,24 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) strcpy(cp->normaladdr,FSMNormaladdr); strcpy(cp->CChexstr,FSMCChexstr); memcpy(cp->CCpriv,FSMCCpriv,32); - cp->validate = FSMValidate; - cp->ismyvin = IsFSMInput; + //cp->validate = FSMValidate; + //cp->ismyvin = IsFSMInput; break; case EVAL_AUCTION: strcpy(cp->unspendableCCaddr,AuctionCCaddr); strcpy(cp->normaladdr,AuctionNormaladdr); strcpy(cp->CChexstr,AuctionCChexstr); memcpy(cp->CCpriv,AuctionCCpriv,32); - cp->validate = AuctionValidate; - cp->ismyvin = IsAuctionInput; + //cp->validate = AuctionValidate; + //cp->ismyvin = IsAuctionInput; break; case EVAL_HEIR: strcpy(cp->unspendableCCaddr,HeirCCaddr); strcpy(cp->normaladdr,HeirNormaladdr); strcpy(cp->CChexstr,HeirCChexstr); memcpy(cp->CCpriv,HeirCCpriv,32); - cp->validate = HeirValidate; - cp->ismyvin = IsHeirInput; + //cp->validate = HeirValidate; + //cp->ismyvin = IsHeirInput; break; case EVAL_CHANNELS: strcpy(cp->unspendableCCaddr,ChannelsCCaddr); @@ -367,8 +367,8 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) strcpy(cp->normaladdr,OraclesNormaladdr); strcpy(cp->CChexstr,OraclesCChexstr); memcpy(cp->CCpriv,OraclesCCpriv,32); - cp->validate = OraclesValidate; - cp->ismyvin = IsOraclesInput; + //cp->validate = OraclesValidate; + //cp->ismyvin = IsOraclesInput; break; case EVAL_PRICES: strcpy(cp->unspendableCCaddr,PricesCCaddr); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index d4a8aa6d8..0a320c461 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -546,46 +546,6 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) return(duration); } -uint256 CCOraclesReverseScan(char const *logcategory,uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid) -{ - CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; - int64_t val,merkleht; CPubKey pk; std::vectordata; char str[65],str2[65]; - - txid = zeroid; - LogPrint(logcategory,"start reverse scan %s\n",uint256_str(str,batontxid)); - while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) - { - LogPrint(logcategory,"check %s\n",uint256_str(str,batontxid)); - if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) - { - LogPrint(logcategory,"decoded %s\n",uint256_str(str,batontxid)); - if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) - { - len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); - len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); - - LogPrint(logcategory,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash)); - if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) - { - txid = batontxid; - LogPrint(logcategory,"set txid\n"); - return(mhash); - } - else - { - LogPrint(logcategory,"missing hash\n"); - return(zeroid); - } - } - else LogPrint(logcategory,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height); - batontxid = bhash; - LogPrint(logcategory,"new hash %s\n",uint256_str(str,batontxid)); - } else break; - } - LogPrint(logcategory,"end of loop\n"); - return(zeroid); -} - int32_t NSPV_coinaddr_inmempool(char const *logcategory,char *coinaddr,uint8_t CCflag); int32_t myIs_coinaddr_inmempoolvout(char const *logcategory,char *coinaddr) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp deleted file mode 100644 index 32e3482d3..000000000 --- a/src/cc/assets.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "CCassets.h" -#include "CCtokens.h" - -// tx validation -bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn) -{ - return false; -} diff --git a/src/cc/auction.cpp b/src/cc/auction.cpp deleted file mode 100644 index ad4ac8f56..000000000 --- a/src/cc/auction.cpp +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "CCauction.h" -#include "../txmempool.h" - -/* -*/ - -// start of consensus code - -int64_t IsAuctionvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) -{ - char destaddr[64]; - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - } - return(0); -} - -bool AuctionExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) -{ - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Auction from mempool"); - if ( (assetoshis= IsAuctionvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + COIN + txfee"); - } - else return(true); -} - -bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) -{ - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval; - return eval->Invalid("no validation yet"); - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - //fprintf(stderr,"check vins\n"); - for (i=0; iInvalid("illegal normal vini"); - } - } - //fprintf(stderr,"check amounts\n"); - if ( AuctionExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"Auctionget invalid amount\n"); - return false; - } - else - { - preventCCvouts = 1; - if ( IsAuctionvout(cp,tx,0) != 0 ) - { - preventCCvouts++; - i = 1; - } else i = 0; - if ( tx.vout[i].nValue != COIN ) - return eval->Invalid("invalid Auction output"); - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"Auctionget validated\n"); - else fprintf(stderr,"Auctionget invalid\n"); - return(retval); - } - } -} -// end of consensus code - -// helper functions for rpc calls in rpcwallet.cpp - -int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) -{ - // add threshold check - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; - std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr,true); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - // prevent dup - if ( it->second.satoshis < 1000000 ) - continue; - if ( myGetTransaction(txid,vintx,hashBlock) != 0 ) - { - if ( (nValue= IsAuctionvout(cp,vintx,(int32_t)it->first.index)) > 0 ) - { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; - } - } - } - return(totalinputs); -} - -std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_AUCTION); - if ( txfee == 0 ) - txfee = 10000; - Auctionpk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddAuctionInputs(cp,mtx,Auctionpk,nValue+txfee,60)) > 0 ) - { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_AUCTION,CCchange,Auctionpk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret)); - } else fprintf(stderr,"cant find Auction inputs\n"); - return(""); -} - -std::string AuctionDeliver(uint64_t txfee,uint256 itemhash,uint256 bidtxid) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_AUCTION); - if ( txfee == 0 ) - txfee = 10000; - Auctionpk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddAuctionInputs(cp,mtx,Auctionpk,nValue+txfee,60)) > 0 ) - { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_AUCTION,CCchange,Auctionpk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret)); - } else fprintf(stderr,"cant find Auction inputs\n"); - return(""); -} - -std::string AuctionPost(uint64_t txfee,uint256 itemhash,int64_t minbid,char *title,char *description) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,Auctionpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_AUCTION); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - Auctionpk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_AUCTION,funds,Auctionpk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } - return(""); -} - - diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp deleted file mode 100644 index fc6b98dc3..000000000 --- a/src/cc/betprotocol.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include - -#include "hash.h" -#include "main.h" -#include "chain.h" -#include "streams.h" -#include "script/cc.h" -#include "cc/betprotocol.h" -#include "cc/eval.h" -#include "cc/utils.h" -#include "primitives/transaction.h" - -int32_t hush_nextheight(); - -std::vector BetProtocol::PlayerConditions() -{ - std::vector subs; - for (int i=0; i result(vmResultHash.begin(), vmResultHash.begin()+32); - mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << result)); - return mtx; -} - - -CMutableTransaction BetProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, - int playerIdx, std::vector state) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - - mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CScript())); - mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state)); - - return mtx; -} - - -CC* BetProtocol::MakePayoutCond(uint256 signedSessionTxHash) -{ - // TODO: 2/3 majority - CC* agree = CCNewThreshold(players.size(), PlayerConditions()); - - CC *import; - { - CC *importEval = CCNewEval(E_MARSHAL( - ss << EVAL_IMPORTPAYOUT << signedSessionTxHash; - )); - - CC *oneof = CCNewThreshold(1, PlayerConditions()); - - import = CCNewThreshold(2, {oneof, importEval}); - } - - return CCNewThreshold(1, {agree, import}); -} - - -CMutableTransaction BetProtocol::MakeStakeTx(CAmount totalPayout, uint256 signedSessionTxHash) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - - CC *payoutCond = MakePayoutCond(signedSessionTxHash); - mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond))); - cc_free(payoutCond); - - return mtx; -} - - -CMutableTransaction BetProtocol::MakeAgreePayoutTx(std::vector payouts, - uint256 signedStakeTxHash) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); - mtx.vout = payouts; - return mtx; -} - - -CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector payouts, - CTransaction signedDisputeTx, uint256 signedStakeTxHash, MoMProof momProof) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); - mtx.vout = payouts; - CScript proofData; - proofData << OP_RETURN << E_MARSHAL(ss << momProof << signedDisputeTx); - mtx.vout.insert(mtx.vout.begin(), CTxOut(0, proofData)); - return mtx; -} - - -bool GetOpReturnHash(CScript script, uint256 &hash) -{ - std::vector vHash; - GetOpReturnData(script, vHash); - if (vHash.size() != 32) return false; - hash = uint256(vHash); - return true; -} - - -/* - * Crypto-Condition EVAL method that verifies a payout against a transaction - * notarized on another chain. - * - * IN: params - condition params - * IN: importTx - Payout transaction on value chain (HUSH) - * IN: nIn - index of input of stake - * - * importTx: Spends stakeTx with payouts from asset chain - * - * in 0: Spends Stake TX and contains ImportPayout CC - * out 0: OP_RETURN MomProof, disputeTx - * out 1-: arbitrary payouts - * - * disputeTx: Spends sessionTx.0 (opener on asset chain) - * - * in 0: spends sessionTx.0 - * in 1-: anything - * out 0: OP_RETURN hash of payouts - * out 1-: anything - */ -bool Eval::ImportPayout(const std::vector params, const CTransaction &importTx, unsigned int nIn) -{ - if (importTx.vout.size() == 0) return Invalid("no-vouts"); - - // load data from vout[0] - MoMProof proof; - CTransaction disputeTx; - { - std::vector vopret; - GetOpReturnData(importTx.vout[0].scriptPubKey, vopret); - if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx)) - return Invalid("invalid-payload"); - } - - // Check disputeTx.0 shows correct payouts - { - uint256 givenPayoutsHash; - GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash); - std::vector payouts(importTx.vout.begin() + 1, importTx.vout.end()); - if (givenPayoutsHash != SerializeHash(payouts)) - return Invalid("wrong-payouts"); - } - - // Check disputeTx spends sessionTx.0 - // condition ImportPayout params is session ID from other chain - { - uint256 sessionHash; - if (!E_UNMARSHAL(params, ss >> sessionHash)) - return Invalid("malformed-params"); - if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0)) - return Invalid("wrong-session"); - } - - // Check disputeTx solves momproof from vout[0] - { - NotarizationData data(0); - if (!GetNotarizationData(proof.notarizationHash, data)) - return Invalid("coudnt-load-mom"); - - if (data.MoM != proof.branch.Exec(disputeTx.GetHash())) - return Invalid("mom-check-fail"); - } - - return Valid(); -} - - -/* - * Crypto-Condition EVAL method that resolves a dispute of a session - * - * IN: vm - AppVM virtual machine to verify states - * IN: params - condition params - * IN: disputeTx - transaction attempting to resolve dispute - * IN: nIn - index of input of dispute tx - * - * disputeTx: attempt to resolve a dispute - * - * in 0: Spends Session TX first output, reveals DisputeHeader - * out 0: OP_RETURN hash of payouts - */ -bool Eval::DisputePayout(AppVM &vm, std::vector params, const CTransaction &disputeTx, unsigned int nIn) -{ - if (disputeTx.vout.size() == 0) return Invalid("no-vouts"); - - // get payouts hash - uint256 payoutHash; - if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash)) - return Invalid("invalid-payout-hash"); - - // load params - uint16_t waitBlocks; - std::vector vmParams; - if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams)) - return Invalid("malformed-params"); - - // ensure that enough time has passed - { - CTransaction sessionTx; - CBlockIndex sessionBlock; - - // if unconformed its too soon - if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock)) - return Error("couldnt-get-parent"); - - if (GetCurrentHeight() < sessionBlock.GetHeight() + waitBlocks) - return Invalid("dispute-too-soon"); // Not yet - } - - // get spends - std::vector spends; - if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends)) - return Error("couldnt-get-spends"); - - // verify result from VM - int maxLength = -1; - uint256 bestPayout; - for (int i=1; i vmState; - if (spends[i].vout.size() == 0) continue; - if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue; - auto out = vm.evaluate(vmParams, vmState); - uint256 resultHash = SerializeHash(out.second); - if (out.first > maxLength) { - maxLength = out.first; - bestPayout = resultHash; - } - // The below means that if for any reason there is a draw, the first dispute wins - else if (out.first == maxLength) { - if (bestPayout != payoutHash) { - fprintf(stderr, "WARNING: VM has multiple solutions of same length\n"); - bestPayout = resultHash; - } - } - } - - if (maxLength == -1) return Invalid("no-evidence"); - - return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout"); -} diff --git a/src/cc/faucet.cpp b/src/cc/faucet.cpp deleted file mode 100644 index 8142fc472..000000000 --- a/src/cc/faucet.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "CCfaucet.h" -#include "../txmempool.h" - -/* - This file implements a simple CC faucet as an example of how to make a new CC contract. It wont have any fancy sybil protection but will serve the purpose of a fully automated faucet. - - In order to implement a faucet, we need to have it funded. Once it is funded, anybody should be able to get some reasonable small amount. - - This leads to needing to lock the funding in a CC protected output. And to put a spending limit. We can do a per transaction spending limit quite easily with vout constraints. However, that would allow anybody to issue thousands of transactions per block, so we also need to add a rate limiter. - - To implement this, we can simply make any faucet vout fund the faucet. Then we can limit the number of confirmed utxo by combining faucet outputs and then only using utxo which are confirmed. This combined with a vout size limit will drastically limit the funds that can be withdrawn from the faucet. -*/ - -// start of consensus code - -int64_t IsFaucetvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) -{ - char destaddr[64]; - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - //else fprintf(stderr,"dest.%s vs (%s)\n",destaddr,cp->unspendableCCaddr); - } - return(0); -} - -bool FaucetExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) -{ - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant faucet from mempool"); - if ( (assetoshis= IsFaucetvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + FAUCETSIZE + txfee"); - } - else return(true); -} - -bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) -{ - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - std::vector > txids; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - for (i=0; iInvalid("illegal normal vini"); - } - } - //fprintf(stderr,"check amounts\n"); - if ( FaucetExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"faucetget invalid amount\n"); - return false; - } - else - { - preventCCvouts = 1; - if ( IsFaucetvout(cp,tx,0) != 0 ) - { - preventCCvouts++; - i = 1; - } else i = 0; - txid = tx.GetHash(); - memcpy(hash,&txid,sizeof(hash)); - fprintf(stderr,"check faucetget txid %s %02x/%02x\n",uint256_str(str,txid),hash[0],hash[31]); - if ( tx.vout[i].nValue != FAUCETSIZE ) - return eval->Invalid("invalid faucet output"); - else if ( (hash[0] & 0xff) != 0 || (hash[31] & 0xff) != 0 ) - return eval->Invalid("invalid faucetget txid"); - Getscriptaddress(destaddr,tx.vout[i].scriptPubKey); - SetCCtxids(txids,destaddr,tx.vout[i].scriptPubKey.IsPayToCryptoCondition()); - for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) - { - //int height = it->first.blockHeight; - if ( CCduration(numblocks,it->first.txhash) > 0 && numblocks > 3 ) - { - return eval->Invalid("faucet is only for brand new addresses"); - } - //fprintf(stderr,"txid %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks); - } - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"faucetget validated\n"); - else fprintf(stderr,"faucetget invalid\n"); - return(retval); - } - } -} -// end of consensus code - -// helper functions for rpc calls in rpcwallet.cpp - -int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) -{ - char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; - std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr,true); - if ( maxinputs > CC_MAXVINS ) - maxinputs = CC_MAXVINS; - if ( maxinputs > 0 ) - threshold = total/maxinputs; - else threshold = total; - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - if ( it->second.satoshis < threshold ) - continue; - //char str[65]; fprintf(stderr,"check %s/v%d %.8f`\n",uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - // no need to prevent dup - if ( myGetTransaction(txid,vintx,hashBlock) != 0 ) - { - if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) - { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; - } else fprintf(stderr,"vout.%d nValue %.8f too small or already spent in mempool\n",vout,(double)nValue/COIN); - } else fprintf(stderr,"couldn't get tx\n"); - } - return(totalinputs); -} - -UniValue FaucetGet(const CPubKey& pk, uint64_t txfee) -{ - CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey faucetpk; int64_t inputs,CCchange=0,nValue=FAUCETSIZE; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; - cp = CCinit(&C,EVAL_FAUCET); - if ( txfee == 0 ) - txfee = 10000; - faucetpk = GetUnspendable(cp,0); - CPubKey mypk = pk.IsValid()?pk:pubkey2pk(Mypubkey()); - if ( (inputs= AddFaucetInputs(cp,mtx,faucetpk,nValue+txfee,60)) > 0 ) - { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET,CCchange,faucetpk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - fprintf(stderr,"start at %u\n",(uint32_t)time(NULL)); - j = rand() & 0xfffffff; - for (i=0; i<1000000; i++,j++) - { - tmpmtx = mtx; - UniValue result = FinalizeCCTxExt(pk.IsValid (),-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FAUCET << (uint8_t)'G' << j)); - if ( (len= (int32_t)result[JSON_HEXTX].getValStr().size()) > 0 && len < 65536 ) - { - len >>= 1; - decode_hex(buf,len,(char *)result[JSON_HEXTX].getValStr().c_str()); - hash = bits256_doublesha256(0,buf,len); - if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 ) - { - fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL)); - return result; - } - //fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]); - } - } - CCERR_RESULT("faucet",CCLOG_ERROR, stream << "couldn't generate valid txid " << (uint32_t)time(NULL)); - } else CCERR_RESULT("faucet",CCLOG_ERROR, stream << "can't find faucet inputs"); -} - -UniValue FaucetFund(const CPubKey& pk, uint64_t txfee,int64_t funds) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey faucetpk; CScript opret; struct CCcontract_info *cp,C; - - cp = CCinit(&C,EVAL_FAUCET); - if ( txfee == 0 ) - txfee = 10000; - CPubKey mypk = pk.IsValid()?pk:pubkey2pk(Mypubkey()); - faucetpk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,funds+txfee,64,pk.IsValid()) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET,funds,faucetpk)); - return(FinalizeCCTxExt(pk.IsValid(),0,cp,mtx,mypk,txfee,opret)); - } - CCERR_RESULT("faucet",CCLOG_ERROR, stream << "can't find normal inputs"); -} - -UniValue FaucetInfo() -{ - UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey faucetpk; struct CCcontract_info *cp,C; int64_t funding; - result.push_back(Pair("result","success")); - result.push_back(Pair("name","Faucet")); - cp = CCinit(&C,EVAL_FAUCET); - faucetpk = GetUnspendable(cp,0); - funding = AddFaucetInputs(cp,mtx,faucetpk,0,0); - sprintf(numstr,"%.8f",(double)funding/COIN); - result.push_back(Pair("funding",numstr)); - return(result); -} diff --git a/src/cc/fsm.cpp b/src/cc/fsm.cpp deleted file mode 100644 index d2998a388..000000000 --- a/src/cc/fsm.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "CCfsm.h" -#include "../txmempool.h" - -/* - FSM CC is a highlevel CC contract that mostly uses other CC contracts. A finite state machine is defined, which combines triggers, payments and whatever other events/actions into a state machine - -*/ - -// start of consensus code - -int64_t IsFSMvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) -{ - char destaddr[64]; - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - } - return(0); -} - -bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) -{ - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant FSM from mempool"); - if ( (assetoshis= IsFSMvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + COIN + txfee"); - } - else return(true); -} - -bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) -{ - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval; - return eval->Invalid("no validation yet"); - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - //fprintf(stderr,"check vins\n"); - for (i=0; iInvalid("illegal normal vini"); - } - } - //fprintf(stderr,"check amounts\n"); - if ( FSMExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"fsmget invalid amount\n"); - return false; - } - else - { - preventCCvouts = 1; - if ( IsFSMvout(cp,tx,0) != 0 ) - { - preventCCvouts++; - i = 1; - } else i = 0; - if ( tx.vout[i].nValue != COIN ) - return eval->Invalid("invalid fsm output"); - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"fsmget validated\n"); - else fprintf(stderr,"fsmget invalid\n"); - return(retval); - } - } -} -// end of consensus code - -// helper functions for rpc calls in rpcwallet.cpp - -int64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) -{ - // add threshold check - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; - std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr,true); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - // prevent dup - if ( it->second.satoshis < 1000000 ) - continue; - if ( myGetTransaction(txid,vintx,hashBlock) != 0 ) - { - if ( (nValue= IsFSMvout(cp,vintx,(int32_t)it->first.index)) > 0 ) - { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; - } - } - } - return(totalinputs); -} - -std::string FSMList() -{ - return(""); -} - -std::string FSMCreate(uint64_t txfee,std::string name,std::string states) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,fsmpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_FSM); - if ( txfee == 0 ) - txfee = 10000; - fsmpk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddFSMInputs(cp,mtx,fsmpk,nValue+txfee,60)) > 0 ) - { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_FSM,CCchange,fsmpk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret)); - } else fprintf(stderr,"cant find fsm inputs\n"); - return(""); -} - -std::string FSMInfo(uint256 fsmtxid) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,fsmpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_FSM); - mypk = pubkey2pk(Mypubkey()); - fsmpk = GetUnspendable(cp,0); - return(""); -} - - diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp deleted file mode 100644 index 859d28656..000000000 --- a/src/cc/heir.cpp +++ /dev/null @@ -1,1293 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "CCHeir.h" -#include "heir_validate.h" -#include - -class CoinHelper; -class TokenHelper; - -/* - The idea of Heir CC is to allow crypto inheritance. - A special 1of2 CC address is created that is freely spendable by the creator (funds owner). - The owner may add additional funds to this 1of2 address. - The heir is only allowed to spend after "the specified amount of idle blocks" (changed to "the owner inactivityTime"). - The idea is that if the address doesnt spend any funds for a year (or whatever amount set), then it is time to allow the heir to spend. - "The design requires the heir to spend all the funds at once" (this requirement was changed to "after the inactivity time both the heir and owner may freely spend available funds") - After the first heir spending a flag is set that spending is allowed for the heir whether the owner adds more funds or spends them. - This Heir contract supports both coins and tokens. - */ - -// tx validation code - -// Plan validation runner, it may be called twice - for coins and tokens -// (sadly we cannot have yet 'templatized' lambdas, if we could we could capture all these params inside HeirValidation()...) -template bool RunValidationPlans(uint8_t funcId, struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint256 latestTxid, CScript fundingOpretScript, uint8_t hasHeirSpendingBegun) -{ - int32_t numvins = tx.vin.size(); - int32_t numvouts = tx.vout.size(); - - // setup validation framework (please see its description in heir_validate.h): - // validation 'plans': - CInputValidationPlan vinPlan; - COutputValidationPlan voutPlan; - - // vin 'identifiers' - CNormalInputIdentifier normalInputIdentifier(cp); - CCCInputIdentifier ccInputIdentifier(cp); - - // vin and vout 'validators' - // not used, too strict for 2 pubkeys: CMyPubkeyVoutValidator normalInputValidator(cp, fundingOpretScript, true); // check normal input for this opret cause this is first tx - CCC1of2AddressValidator cc1of2ValidatorThis(cp, fundingOpretScript, "checking this tx opreturn:"); // 1of2add validator with pubkeys from this tx opreturn - CHeirSpendValidator heirSpendValidator(cp, fundingOpretScript, latestTxid, hasHeirSpendingBegun); // check if heir allowed to spend - - // only for tokens: - CMyPubkeyVoutValidator ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret - COpRetValidator opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx - CMarkerValidator markerValidator(cp); // initial tx marker spending protection - CNullValidator nullValidator(cp); - - switch (funcId) { - case 'F': // fund tokens (only for tokens) - // vin validation plan: - vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin - vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &ownerCCaddrValidator); // check cc owner addr - - // vout validation plan: - voutPlan.pushValidators(0, &cc1of2ValidatorThis); // check 1of2 addr funding - // do not check change at this time - // no checking for opret yet - break; - - case 'A': // add tokens (only for tokens) - // vin validation plan: - vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin - vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &ownerCCaddrValidator); // check cc owner addr - - // vout validation plan: - voutPlan.pushValidators(0, &cc1of2ValidatorThis); // check 1of2 addr funding - // do not check change at this time - voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A: - break; - - case 'C': // spend coins or tokens - // vin validation plan: - vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin - vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &cc1of2ValidatorThis); // cc1of2 funding addr - - // vout validation plan: - voutPlan.pushValidators(0, &heirSpendValidator); // check if heir is allowed to spend - voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A - break; - } - - // call vin/vout validation - if (!vinPlan.validate(tx, eval)) - return false; - if (!voutPlan.validate(tx, eval)) - return false; - - return true; -} - -/** - * Tx validation entry function - */ -bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction& tx, uint32_t nIn) -{ - int32_t numvins = tx.vin.size(); - int32_t numvouts = tx.vout.size(); - //int32_t preventCCvins = -1; - //int32_t preventCCvouts = -1; - - struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - - if (numvouts < 1) - return eval->Invalid("no vouts"); - - //if (chainActive.Height() < 741) - // return true; - - uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenidThis, tokenid = zeroid; - - CScript fundingTxOpRetScript; - uint8_t hasHeirSpendingBegun = 0, hasHeirSpendingBegunDummy; - - CScript opret = (tx.vout.size() > 0) ? tx.vout[tx.vout.size() - 1].scriptPubKey : CScript(); // check boundary - uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenidThis, fundingTxidInOpret, hasHeirSpendingBegunDummy, true); - if (funcId == 0) - return eval->Invalid("invalid opreturn format"); - - if (funcId != 'F') { - if (fundingTxidInOpret == zeroid) { - return eval->Invalid("incorrect tx opreturn: no fundingtxid present"); - } - latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, hasHeirSpendingBegun); - - if( tokenid != zeroid && tokenid != tokenidThis ) - return eval->Invalid("incorrect tx tokenid"); - - if (latestTxid == zeroid) { - return eval->Invalid("no fundingtx found"); - } - } - else { - fundingTxOpRetScript = opret; - } - - std::cerr << "HeirValidate funcid=" << (char)funcId << " evalcode=" << (int)cpHeir->evalcode << std::endl; - - //////////////// temp //////////////////////// - ///return true; - - switch (funcId) { - case 'F': - // fund coins: - // vins.*: normal inputs - // ----------------------------- - // vout.0: funding CC 1of2 addr for the owner and heir - // vout.1: txfee for CC addr used as a marker - // vout.2: normal change - // vout.n-1: opreturn 'F' ownerpk heirpk inactivitytime heirname - - // fund tokens: - // vin.0: normal inputs txfee - // vins.1+: user's CC addr inputs - // ----------------------- - // vout.0: funding heir CC 1of2 addr for the owner and heir - // vout.1: txfee for CC addr used as a marker - // vout.2: normal change - // vout.n-1: opreturn 't' tokenid 'F' ownerpk heirpk inactivitytime heirname tokenid - if (tokenid != zeroid) - return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); - else - return eval->Invalid("unexpected HeirValidate for heirfund"); - // break; - - case 'A': - // add funding coins: - // vins.*: normal inputs - // ------------------------ - // vout.0: funding CC 1of2 addr for the owner and heir - // vout.1: normal change - // vout.n-1: opreturn 'A' ownerpk heirpk inactivitytime fundingtx - - // add funding tokens: - // vins.0: normal inputs txfee - // vins.1+: user's CC addr inputs - // ------------------------ - // vout.0: funding CC 1of2 addr for the owner and heir - // vout.1: normal change - // vout.n-1: opreturn 't' tokenid 'A' ownerpk heirpk inactivitytime fundingtx - if (tokenid != zeroid) - return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); - else - return eval->Invalid("unexpected HeirValidate for heiradd"); - //break; - - case 'C': - // claim coins: - // vin.0: normal input txfee - // vin.1+: input from CC 1of2 addr - // ------------------------------------- - // vout.0: normal output to owner or heir address - // vout.1: change to CC 1of2 addr - // vout.2: change to user's addr from txfee input if any - // vout.n-1: opreturn 'C' ownerpk heirpk inactivitytime fundingtx - - // claim tokens: - // vin.0: normal input txfee - // vin.1+: input from CC 1of2 addr - // -------------------------------------------- - // vout.0: output to user's cc address - // vout.1: change to CC 1of2 addr - // vout.2: change to normal from txfee input if any - // vout.n-1: opreturn 't' tokenid 'C' ownerpk heirpk inactivitytime fundingtx - if (tokenid != zeroid) - return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); - else - return RunValidationPlans(funcId, cpHeir, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); - // break; - - default: - std::cerr << "HeirValidate() illegal heir funcid=" << (char)funcId << std::endl; - return eval->Invalid("unexpected HeirValidate funcid"); - // break; - } - return eval->Invalid("unexpected"); // (PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts)); -} -// end of consensus code - - -// helper functions used in implementations of rpc calls (in rpcwallet.cpp) or validation code - -/** - * Checks if vout is to cryptocondition address - * @return vout value in satoshis - */ -template int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey) -{ - char destaddr[65], heirFundingAddr[65]; - - Helper::GetCoinsOrTokensCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey); - if (tx.vout[voutIndex].scriptPubKey.IsPayToCryptoCondition() != 0) { - // NOTE: dimxy it was unsafe 'Getscriptaddress(destaddr,tx.vout[voutIndex].scriptPubKey) > 0' here: - if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirFundingAddr) == 0) - return (tx.vout[voutIndex].nValue); - else - std::cerr << "IsHeirFundingVout() heirFundingAddr=" << heirFundingAddr << " not equal to destaddr=" << destaddr << std::endl; - } - return (0); -} - -// makes coin initial tx opret -vscript_t EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) -{ - uint8_t evalcode = EVAL_HEIR; - - return /*CScript() << OP_RETURN <<*/ E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName << memo); -} - -// makes coin additional tx opret -vscript_t EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpendingBegun) -{ - uint8_t evalcode = EVAL_HEIR; - - fundingtxid = revuint256(fundingtxid); - return /*CScript() << OP_RETURN <<*/ E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); -} - - -// decode opret vout for Heir contract -uint8_t _DecodeHeirOpRet(vscript_t vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) -{ - uint8_t evalCodeInOpret = 0; - uint8_t heirFuncId = 0; - - fundingTxidInOpret = zeroid; //to init - - evalCodeInOpret = vopret.begin()[0]; - - if (vopret.size() > 1 && evalCodeInOpret == EVAL_HEIR) { - // NOTE: it unmarshals for all F, A and C - uint8_t heirFuncId = 0; - hasHeirSpendingBegun = 0; - - bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; - if (heirFuncId == 'F') { - ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; ss >> memo; - } - else { - ss >> fundingTxidInOpret >> hasHeirSpendingBegun; - } - }); - - if (!result) { - if (!noLogging) std::cerr << "_DecodeHeirOpRet() could not unmarshal opret, evalCode=" << (int)evalCodeInOpret << std::endl; - return (uint8_t)0; - } - - /* std::cerr << "DecodeHeirOpRet()" - << " heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') - << " ownerPubkey=" << HexStr(ownerPubkey) - << " heirPubkey=" << HexStr(heirPubkey) - << " heirName=" << heirName << " inactivityTime=" << inactivityTime - << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << std::endl; */ - - if (isMyFuncId(heirFuncId)) { - fundingTxidInOpret = revuint256(fundingTxidInOpret); - return heirFuncId; - } - else { - if(!noLogging) std::cerr << "_DecodeHeirOpRet() unexpected opret type, heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << std::endl; - } - } - else { - if (!noLogging) std::cerr << "_DecodeHeirOpRet() not a heir opret, vopretExtra.size() == 0 or not EVAL_HEIR evalcode=" << (int)evalCodeInOpret << std::endl; - } - return (uint8_t)0; -} - -// decode combined opret: -uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) -{ - uint8_t evalCodeTokens = 0; - std::vector voutPubkeysDummy; - std::vector> oprets; - vscript_t vopretExtra /*, vopretStripped*/; - - - if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, oprets) != 0 && GetOpretBlob(oprets, OPRETID_HEIRDATA, vopretExtra)) { - /* if (vopretExtra.size() > 1) { - // restore the second opret: - - /* unmarshalled in DecodeTokenOpRet: - if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size - if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl; - return (uint8_t)0; - } - } */ - if (vopretExtra.size() < 1) { - if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl; - return (uint8_t)0; - } - } - else { - GetOpReturnData(scriptPubKey, vopretExtra); - } - - return _DecodeHeirOpRet(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); -} - -// overload to decode opret in fundingtxid: -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging) { - uint256 dummyFundingTxidInOpret; - uint8_t dummyHasHeirSpendingBegun; - - return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging); -} - -// overload to decode opret in A and C heir tx: -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { - CPubKey dummyOwnerPubkey, dummyHeirPubkey; - int64_t dummyInactivityTime; - std::string dummyHeirName, dummyMemo; - - return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, dummyMemo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); -} - -// check if pubkey is in vins -void CheckVinPubkey(std::vector vins, CPubKey pubkey, bool &hasPubkey, bool &hasOtherPubkey) { - - hasPubkey = false; - hasOtherPubkey = false; - - for (auto vin : vins) { - CPubKey vinPubkey = check_signing_pubkey(vin.scriptSig); - if (vinPubkey.IsValid()) { - if (vinPubkey == pubkey) - hasPubkey = true; - if (vinPubkey != pubkey) - hasOtherPubkey = true; - } - } -} - -/** - * find the latest funding tx: it may be the first F tx or one of A or C tx's - * Note: this function is also called from validation code (use non-locking calls) - */ -uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun) -{ - CTransaction fundingtx; - uint256 hashBlock; - const bool allowSlow = false; - - //char markeraddr[64]; - //CCtxidaddr(markeraddr, fundingtxid); - //SetCCunspents(unspentOutputs, markeraddr,true); - - hasHeirSpendingBegun = 0; - funcId = 0; - - // get initial funding tx and set it as initial lasttx: - if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { - - CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); - if (funcId != 0) { - // found at least funding tx! - //std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; - fundingOpretScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; - } else { - std::cerr << "FindLatestFundingTx() could not decode opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; - return zeroid; - } - } else { - std::cerr << "FindLatestFundingTx() could not find funding tx for fundingtxid=" << fundingtxid.GetHex() << '\n'; - return zeroid; - } - - // TODO: correct cc addr: - std::vector> unspentOutputs; - struct CCcontract_info *cp, C; - cp = CCinit(&C, EVAL_HEIR); - char coinaddr[64]; - GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' - - SetCCunspents(unspentOutputs, coinaddr,true); // get vector with tx's with unspent vouts of 1of2pubkey address: - //std::cerr << "FindLatestFundingTx() using 1of2address=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; - - int32_t maxBlockHeight = 0; // max block height - uint256 latesttxid = fundingtxid; - - // try to find the last funding or spending tx by checking fundingtxid in 'opreturn': - for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { - CTransaction regtx; - uint256 hash; - - uint256 txid = it->first.txhash; - //std::cerr << "FindLatestFundingTx() checking unspents for txid=" << txid.GetHex() << '\n'; - - int32_t blockHeight = (int32_t)it->second.blockHeight; - - //NOTE: maybe called from validation code: - if (myGetTransaction(txid, regtx, hash)) { - //std::cerr << "FindLatestFundingTx() found tx for txid=" << txid.GetHex() << " blockHeight=" << blockHeight << " maxBlockHeight=" << maxBlockHeight << '\n'; - uint256 fundingTxidInOpret; - uint256 tokenidInOpret; // not to contaminate the tokenid from the params! - uint8_t tmpFuncId; - uint8_t hasHeirSpendingBegunInOpret; - - CScript heirScript = (regtx.vout.size() > 0) ? regtx.vout[regtx.vout.size() - 1].scriptPubKey : CScript(); - tmpFuncId = DecodeHeirEitherOpRet(heirScript, tokenidInOpret, fundingTxidInOpret, hasHeirSpendingBegunInOpret, true); - if (tmpFuncId != 0 && fundingtxid == fundingTxidInOpret && (tokenid == zeroid || tokenid == tokenidInOpret)) { // check tokenid also - - if (blockHeight > maxBlockHeight) { - - // check owner pubkey in vins - bool isOwner = false; - bool isNonOwner = false; - - CheckVinPubkey(regtx.vin, ownerPubkey, isOwner, isNonOwner); - - // we ignore 'donations' tx (with non-owner inputs) for calculating if heir is allowed to spend: - if (isOwner && !isNonOwner) { - hasHeirSpendingBegun = hasHeirSpendingBegunInOpret; - maxBlockHeight = blockHeight; - latesttxid = txid; - funcId = tmpFuncId; - } - - //std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight - // << " opreturn type=" << (char)(funcId ? funcId : ' ') << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << " - set as current lasttxid" << '\n'; - } - } - } - } - - return latesttxid; -} - -// overload for validation code -uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &hasHeirSpendingBegun) -{ - uint8_t funcId; - CPubKey ownerPubkey; - CPubKey heirPubkey; - int64_t inactivityTime; - std::string heirName, memo; - - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun); -} - -// overload for transaction creation code -uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint8_t &hasHeirSpendingBegun) -{ - CScript opRetScript; - - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun); -} - -// add inputs of 1 of 2 cc address -template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, uint256 fundingtxid, CMutableTransaction& mtx, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t total, int32_t maxinputs) -{ - // TODO: add threshold check - int64_t nValue, voutValue, totalinputs = 0; - CTransaction heirtx; - int32_t n = 0; - std::vector> unspentOutputs; - - char coinaddr[64]; - Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 of 2 pubkeys' - SetCCunspents(unspentOutputs, coinaddr,true); - - // char markeraddr[64]; - // CCtxidaddr(markeraddr, fundingtxid); - // SetCCunspents(unspentOutputs, markeraddr,true); - - std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl; - - for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { - uint256 txid = it->first.txhash; - uint256 hashBlock; - int32_t voutIndex = (int32_t)it->first.index; - // no need to prevent dup - // dimxy: maybe it is good to put tx's in cache? - - //std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl; - - if (myGetTransaction(txid, heirtx, hashBlock) != 0) { - uint256 tokenid; - uint256 fundingTxidInOpret; - uint8_t hasHeirSpendingBegunDummy; - - CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); // check boundary - uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, false); - - if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && - funcId != 0 && - isMyFuncId(funcId) && - (typeid(Helper) != typeid(TokenHelper) ) && // token validation logic - //(voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts - !myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, voutIndex)) - { - std::cerr << "Add1of2AddressInputs() satoshis=" << it->second.satoshis << std::endl; - if (total != 0 && maxinputs != 0) - mtx.vin.push_back(CTxIn(txid, voutIndex, CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) - break; - } - } - } - return totalinputs; -} - -/** - * enumerate all tx's sending to CCHeir 1of2address and calc total lifetime funds - */ -template int64_t LifetimeHeirContractFunds(struct CCcontract_info* cp, uint256 fundingtxid, CPubKey ownerPubkey, CPubKey heirPubkey) -{ - char coinaddr[64]; - Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' - - std::vector> addressIndexes; - SetCCtxids(addressIndexes, coinaddr,true); - - //fprintf(stderr,"LifetimeHeirContractFunds() scan lifetime of %s\n",coinaddr); - int64_t total = 0; - for (std::vector>::const_iterator it = addressIndexes.begin(); it != addressIndexes.end(); it++) { - uint256 hashBlock; - uint256 txid = it->first.txhash; - CTransaction heirtx; - - // TODO: check all funding tx should contain unspendable markers - if (myGetTransaction(txid, heirtx, hashBlock) && heirtx.vout.size() > 0) { - uint256 tokenid; - uint256 fundingTxidInOpret; - uint8_t hasHeirSpendingBegunDummy; - const int32_t ivout = 0; - - CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); // check boundary - uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, false); - - //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; - - if (funcId != 0 && - (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && - isMyFuncId(funcId) && !isSpendingTx(funcId) && - (typeid(Helper) != typeid(TokenHelper) ) && - !myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, ivout)) // exclude tx in mempool - { - total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change) - //std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n'; - } - } - } - return (total); -} - -/* rpc functions' implementation: */ - -/** - * heirfund rpc call implementation - * creates tx for initial funds deposit on cryptocondition address which locks funds for spending by either of address. - * and also for setting spending plan for the funds' owner and heir - * @return fundingtxid handle for subsequent references to this heir funding plan - */ -template UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - struct CCcontract_info *cp, C; - - cp = CCinit(&C, Helper::getMyEval()); - if (txfee == 0) - txfee = 10000; - - int64_t markerfee = 10000; - - //std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl; - - CPubKey myPubkey = pubkey2pk(Mypubkey()); - - if (!tokenid.IsNull()) // add normals only for tokens - { - if (AddNormalinputs(mtx, myPubkey, txfee + markerfee, 4) < txfee + markerfee) - { - std::cerr << "HeirFund() could not find normal inputs for txfee" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "could not find normal inputs for txfee")); - return result; - } - } - - int64_t inputs; - int64_t addAmount = tokenid.IsNull() ? (txfee + markerfee + amount) : amount; // for coins add txfee markerfee amount in one call - if ((inputs=Helper::addOwnerInputs(tokenid, mtx, myPubkey, addAmount, (int32_t)64)) >= addAmount) - { - mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey)); - - // add a marker for finding all plans in HeirList() - // TODO: change marker either to cc or normal txidaddr unspendable - struct CCcontract_info *cpHeir, heirC; - cpHeir = CCinit(&heirC, EVAL_HEIR); - CPubKey heirUnspendablePubKey = GetUnspendable(cpHeir, 0); - // mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); <-- bad marker cause it was spendable by anyone - mtx.vout.push_back(MakeCC1vout(EVAL_HEIR, markerfee, heirUnspendablePubKey)); // this marker spending is disabled in the validation code - - if (!tokenid.IsNull()) - { - int64_t ccChange = 0; - // calc and add token change vout: - if (inputs > amount) - ccChange = (inputs - amount); // -txfee <-- txfee pays user - - //std::cerr << "HeirFund() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - - if (ccChange != 0) - mtx.vout.push_back(Helper::makeUserVout(ccChange, myPubkey)); - } - - // check owner pubkey in vins - bool hasMypubkey = false; - bool hasNotMypubkey = false; - - CheckVinPubkey(mtx.vin, myPubkey, hasMypubkey, hasNotMypubkey); - - // for initial funding do not allow to sign by non-owner key: - if (hasNotMypubkey) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "using non-owner inputs not allowed")); - return result; - } - - // add 1of2 vout token validation pubkeys - used only for tokens - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(myPubkey); - voutTokenPubkeys.push_back(heirPubkey); - - // add change for txfee and opreturn vouts and sign tx: - std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName, memo)); - if (!rawhextx.empty()) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", rawhextx)); - } - else { - std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "sign error")); - } - } - else { // TODO: need result return unification with heiradd and claim - std::cerr << "HeirFund() could not find owner inputs for amount (normal inputs for coins, cc inputs for tokens)" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "could not find owner inputs")); - } - return result; -} - -// if no these callers - it could not link -UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo){ - return _HeirFund(txfee, coins, heirName, heirPubkey, inactivityTimeSec, memo, zeroid); -} - -UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) { - return _HeirFund(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, memo, tokenid); -} - -/** - * heiradd rpc call implementation - * creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir - * @return result object with raw tx or error text - */ -template UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - struct CCcontract_info *cp, C; - std::string rawhex; - - cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! - - if (txfee == 0) - txfee = 10000; - - int64_t markerfee = 10000; - - CPubKey myPubkey = pubkey2pk(Mypubkey()); - - // check if it is the owner - if (myPubkey != ownerPubkey) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "adding funds is only allowed for the owner of this contract")); - return result; - } - - if (!tokenid.IsNull()) // add normals only for tokens - { - if (AddNormalinputs(mtx, myPubkey, txfee + markerfee, 4) < txfee + markerfee) - { - std::cerr << "HeirFund() could not find normal inputs for txfee" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "could not find normal inputs for txfee")); - return result; - } - } - - int64_t inputs; - int64_t addAmount = tokenid.IsNull() ? (txfee + markerfee + amount) : amount; // for coins add txfee markerfee amount in one call - if ((inputs = Helper::addOwnerInputs(tokenid, mtx, myPubkey, addAmount, 64)) >= addAmount) { // TODO: why 64 max inputs? - - // we do not use markers anymore - storing data in opreturn is better - // add marker vout: - /* char markeraddr[64]; - CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners - std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ - - // add cryptocondition to spend this funded amount for either pk - mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); - - char markeraddr[64]; - CPubKey markerPubkey = CCtxidaddr(markeraddr, fundingtxid); - mtx.vout.push_back(CTxOut(markerfee, CScript() << ParseHex(HexStr(markerPubkey)) << OP_CHECKSIG)); // marker to prevent archiving of the funds add vouts - - if (!tokenid.IsNull()) - { - int64_t ccChange = 0; - - if (inputs > amount) - ccChange = (inputs - amount); // -txfee <-- txfee pays user - //std::cerr << "HeirAdd() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - - if (ccChange != 0) - mtx.vout.push_back(Helper::makeUserVout(ccChange, myPubkey)); - } - - // check owner pubkey in vins - bool hasMypubkey = false; - bool hasNotMypubkey = false; - - CheckVinPubkey(mtx.vin, myPubkey, hasMypubkey, hasNotMypubkey); - - // for additional funding do not allow to sign by both owner and non-owner keys (is this a donation or not?): - if (hasMypubkey && hasNotMypubkey) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "using both owner and non-owner inputs is not allowed")); - return result; - } - - // warn the user he's making a donation if this is all non-owner keys: - if (hasNotMypubkey) { - result.push_back(Pair("result", "warning")); - result.push_back(Pair("warning", "you are about to make a donation to heir fund")); - } - else { - result.push_back(Pair("result", "success")); - } - - // add 1of2 vout validation pubkeys - needed only for tokens: - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(ownerPubkey); - voutTokenPubkeys.push_back(heirPubkey); - - // add opreturn 'A' and sign tx: - std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); - - if (!rawhextx.empty()) { - result.push_back(Pair("hex", rawhextx)); - } - else { - std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; - result.clear(); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "sign error")); - } - } - else { - std::cerr << "HeirAdd cannot find owner inputs for amount (normal inputs for coins, cc inputs for tokens)" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find owner inputs")); - } - return result; -} - - -UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount) { - - CPubKey ownerPubkey, heirPubkey; - int64_t inactivityTimeSec; - - uint256 latesttxid, tokenid = zeroid; - uint8_t funcId; - std::string heirName, memo; - uint8_t hasHeirSpendingBegun = 0; - - // get latest tx to see if it is a token or coin - if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) - { - if (tokenid == zeroid) { - int64_t amount = 0; - if (!ParseFixedPoint(strAmount, 8, &amount) || amount <= 0 ) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "invalid amount")); - return result; - } - return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); - } - else - { - int64_t amount = atoll(strAmount.c_str()); - if (amount <= 0) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "invalid amount")); - return result; - } - return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); - } - } - else { - UniValue result(UniValue::VOBJ); - - fprintf(stderr, "HeirAdd() can't find any heir CC funding tx's\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find any heir CC funding transactions")); - return result; - } -} - - -/** - * heirclaim rpc call implementation - * creates tx to spend funds from cryptocondition address by either funds' owner or heir - * @return result object with raw tx or error text - */ -template UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey myPubkey; - int64_t inputs, change = 0; - struct CCcontract_info *cp, C; - - cp = CCinit(&C, EVAL_HEIR); - if (txfee == 0) - txfee = 10000; - - int32_t numblocks; - uint64_t durationSec = 0; - - // we do not need to find duration if spending already has begun - if (!hasHeirSpendingBegun) { - durationSec = CCduration(numblocks, latesttxid); - std::cerr << "HeirClaim() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << std::endl; - } - - // spending is allowed if there is already spending tx or inactivity time - //bool isAllowedToHeir = (funcId == 'C' || durationSec > inactivityTimeSec) ? true : false; - bool isAllowedToHeir = (hasHeirSpendingBegun || durationSec > inactivityTimeSec) ? true : false; - myPubkey = pubkey2pk(Mypubkey()); - - // if it is the heir, check if spending not allowed to heir yet - if (myPubkey == heirPubkey && !isAllowedToHeir) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "spending is not allowed yet for the heir")); - return result; - } - - // we do not use markers any more: - // we allow owner to spend funds at any time: - // if it is the owner, check if spending already allowed to heir - /* if (myPubkey == ownerPubkey && isAllowedToHeir) { - result.push_back(Pair("result", "spending is not already allowed for the owner")); - return result; - } */ - - // add spending txfee from the calling user - if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { - - // add spending from cc 1of2 address - if ((inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, amount, 60)) >= amount) // TODO: why only 60 inputs? - { - /*if (inputs < amount) { - std::cerr << "HeirClaim() cant find enough HeirCC 1of2 inputs, found=" << inputs << " required=" << amount << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find heir CC funding")); - - return result; - }*/ - - // add vout with amount to claiming address - mtx.vout.push_back(Helper::makeUserVout(amount, myPubkey)); // vout[0] - - // calc and add change vout: - if (inputs > amount) - change = (inputs - amount); // -txfee <-- txfee pays user - - //std::cerr << "HeirClaim() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - - // change to 1of2 funding addr: - if (change != 0) { // vout[1] - mtx.vout.push_back(Helper::make1of2Vout(change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! - } - - // add marker vout: - /*char markeraddr[64]; - CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); - // NOTE: amount = 0 is not working: causes error code: -26, error message : 64 : dust - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners - std::cerr << "HeirClaim() adding markeraddr=" << markeraddr << '\n'; */ - - // get address of 1of2 cond - char coinaddr[64]; - Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); - - // retrieve priv key addresses for FinalizeCCtx: - uint8_t myprivkey[32]; - Myprivkey(myprivkey); - - // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: - Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); - - // add 1of2 vout validation pubkeys (this is for tokens): - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(ownerPubkey); - voutTokenPubkeys.push_back(heirPubkey); - - // add opreturn 'C' and sign tx: // this txfee will be ignored - std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : hasHeirSpendingBegun)); // forward isHeirSpending to the next latest tx - - memset(myprivkey,0,sizeof(myprivkey)); - if (!rawhextx.empty()) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", rawhextx)); - } - else { - std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "sign error")); - } - - } else { - fprintf(stderr, "HeirClaim() cant find Heir CC inputs\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find heir CC funding")); - } - } else { - fprintf(stderr, "HeirClaim() cant find sufficient user inputs for tx fee\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find sufficient user inputs to pay transaction fee")); - } - - - return result; -} - -UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount) { - - CPubKey ownerPubkey, heirPubkey; - int64_t inactivityTimeSec; - - uint256 latesttxid, tokenid = zeroid; - uint8_t funcId; - std::string heirName, memo; - uint8_t hasHeirSpendingBegun = 0; - - // find latest tx to see if it is a token or coin: - if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) - { - if (tokenid == zeroid) - { - int64_t amount = 0; - if (!ParseFixedPoint(strAmount, 8, &amount) || amount <= 0) { // using ParseFixedPoint instead atof to avoid round errors - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "invalid amount")); - return result; - } - return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); - } - else { - int64_t amount = atoll(strAmount.c_str()); - if (amount <= 0) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "invalid amount")); - return result; - } - return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); - } - - } - else { - UniValue result(UniValue::VOBJ); - - fprintf(stderr, "HeirClaim() can't find any heir CC funding tx's\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find any heir CC funding transactions")); - return result; - } -} - - -/** - * heirinfo rpc call implementation - * returns some information about heir CC contract plan by a handle of initial fundingtxid: - * plan name, owner and heir pubkeys, funds deposited and available, flag if spending is enabled for the heir - * @return heir info data - */ -UniValue HeirInfo(uint256 fundingtxid) -{ - UniValue result(UniValue::VOBJ); - - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CTransaction fundingtx; - uint256 hashBlock; - const bool allowSlow = false; - - //char markeraddr[64]; - //CCtxidaddr(markeraddr, fundingtxid); - //SetCCunspents(unspentOutputs, markeraddr,true); - - // get initial funding tx and set it as initial lasttx: - if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { - - CPubKey ownerPubkey, heirPubkey; - uint256 dummyTokenid, tokenid = zeroid; // important to clear tokenid - std::string heirName, memo; - int64_t inactivityTimeSec; - const bool noLogging = false; - uint8_t funcId; - - /*CScript opret = fundingtx.vout.size() > 0 ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); - if (funcId == 0) { - std::cerr << "HeirInfo() this fundingtx is incorrect" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "initial tx F not found")); - return result; - }*/ - - struct CCcontract_info *cp, C; - cp = CCinit(&C, EVAL_HEIR); - - uint8_t hasHeirSpendingBegun = 0; - - uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun); - - if (latestFundingTxid != zeroid) { - int32_t numblocks; - uint64_t durationSec = 0; - - //std::cerr << "HeirInfo() latesttxid=" << latestFundingTxid.GetHex() << '\n'; - - std::ostringstream stream; - std::string msg; - - //sleep(10); - - result.push_back(Pair("fundingtxid", fundingtxid.GetHex())); - result.push_back(Pair("name", heirName.c_str())); - - if (tokenid != zeroid) { // tokens - stream << tokenid.GetHex(); - msg = "tokenid"; - result.push_back(Pair(msg, stream.str().c_str())); - stream.str(""); - stream.clear(); - } - - char hexbuf[67]; - stream << pubkey33_str(hexbuf, (uint8_t*)ownerPubkey.begin()); - result.push_back(Pair("owner", stream.str().c_str())); - stream.str(""); - stream.clear(); - - stream << pubkey33_str(hexbuf, (uint8_t*)heirPubkey.begin()); - result.push_back(Pair("heir", stream.str().c_str())); - stream.str(""); - stream.clear(); - - int64_t total; - if (tokenid == zeroid) - total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); - else - total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); - - msg = "type"; - if (tokenid == zeroid) { - stream << "coins"; - } - else { - stream << "tokens"; - } - result.push_back(Pair(msg, stream.str().c_str())); - stream.str(""); - stream.clear(); - - msg = "lifetime"; - if (tokenid == zeroid) { - stream << std::fixed << std::setprecision(8) << (double)total / COIN; - } - else { - stream << total; - } - result.push_back(Pair(msg, stream.str().c_str())); - stream.str(""); - stream.clear(); - - int64_t inputs; - if (tokenid == zeroid) - inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); //NOTE: amount = 0 means all unspent inputs - else - inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); - - msg = "available"; - if (tokenid == zeroid) { - stream << std::fixed << std::setprecision(8) << (double)inputs / COIN; - } - else { - stream << inputs; - } - result.push_back(Pair(msg, stream.str().c_str())); - stream.str(""); - stream.clear(); - - if (tokenid != zeroid) { - int64_t ownerInputs = TokenHelper::addOwnerInputs(tokenid, mtx, ownerPubkey, 0, (int32_t)64); - stream << ownerInputs; - msg = "OwnerRemainderTokens"; - result.push_back(Pair(msg, stream.str().c_str())); - stream.str(""); - stream.clear(); - } - - stream << inactivityTimeSec; - result.push_back(Pair("InactivityTimeSetting", stream.str().c_str())); - stream.str(""); - stream.clear(); - - if (!hasHeirSpendingBegun) { // we do not need find duration if the spending already has begun - durationSec = CCduration(numblocks, latestFundingTxid); - std::cerr << "HeirInfo() duration (sec)=" << durationSec << " inactivityTime (sec)=" << inactivityTimeSec << " numblocks=" << numblocks << '\n'; - } - - stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec); - result.push_back(Pair("IsHeirSpendingAllowed", stream.str().c_str())); - stream.str(""); - stream.clear(); - - // adding owner current inactivity time: - if (!hasHeirSpendingBegun && durationSec <= inactivityTimeSec) { - stream << durationSec; - result.push_back(Pair("InactivityTime", stream.str().c_str())); - stream.str(""); - stream.clear(); - } - - result.push_back(Pair("memo", memo.c_str())); - - result.push_back(Pair("result", "success")); - } - else { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "could not find heir cc plan for this txid")); - } - } - else { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "could not find heir cc plan for this txid (no initial tx)")); - } - return (result); -} - -/** - * heirlist rpc call implementation - * @return list of heir plan handles (fundingtxid) - */ - -void _HeirList(struct CCcontract_info *cp, UniValue &result) -{ - std::vector> unspentOutputs; - char markeraddr[64]; - - GetCCaddress(cp, markeraddr, GetUnspendable(cp, NULL)); - SetCCunspents(unspentOutputs, markeraddr,true); - - //std::cerr << "HeirList() finding heir marker from unspendable addr=" << markeraddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; - - // TODO: move marker to special cc addr to prevent checking all tokens - for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { - uint256 hashBlock; - uint256 txid = it->first.txhash; - uint256 tokenid; - int32_t vout = (int32_t)it->first.index; - - //std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n'; - - CTransaction fundingtx; - if (myGetTransaction(txid, fundingtx, hashBlock)) { - CPubKey ownerPubkey, heirPubkey; - std::string heirName, memo; - int64_t inactivityTimeSec; - const bool noLogging = true; - uint256 tokenid; - - CScript opret = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, true); - - // note: if it is not Heir token funcId would be equal to 0 - if (funcId == 'F') { - //result.push_back(Pair("fundingtxid kind name", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName)); - result.push_back( txid.GetHex() ); - } - else { - std::cerr << "HeirList() this is not the initial F transaction=" << txid.GetHex() << std::endl; - } - } - else { - std::cerr << "HeirList() could not load transaction=" << txid.GetHex() << std::endl; - } - } -} - - -UniValue HeirList() -{ - UniValue result(UniValue::VARR); - //result.push_back(Pair("result", "success")); - //result.push_back(Pair("name", "Heir List")); - - struct CCcontract_info *cpHeir, heirC; - - cpHeir = CCinit(&heirC, EVAL_HEIR); - _HeirList(cpHeir, result); - - return result; -} diff --git a/src/cc/oracles.cpp b/src/cc/oracles.cpp deleted file mode 100644 index e1307810b..000000000 --- a/src/cc/oracles.cpp +++ /dev/null @@ -1,1233 +0,0 @@ -// Copyright (c) 2016-2023 The Hush developers -// Distributed under the GPLv3 software license, see the accompanying -// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "CCOracles.h" -#include - -/* - An oracles CC has the purpose of converting offchain data into onchain data - simplest would just be to have a pubkey(s) that are trusted to provide such data, but this wont need to have a CC involved at all and can just be done by convention - - That begs the question, "what would an oracles CC do?" - A couple of things come to mind, ie. payments to oracles for future offchain data and maybe some sort of dispute/censoring ability - - first step is to define the data that the oracle is providing. A simple name:description tx can be created to define the name and description of the oracle data. - linked to this txid would be two types of transactions: - a) oracle providers - b) oracle data users - - In order to be resistant to sybil attacks, the feedback mechanism needs to have a cost. combining with the idea of payments for data, the oracle providers will be ranked by actual payments made to each oracle for each data type. - - Implementation notes: - In order to maintain good performance even under heavy usage, special marker utxo are used. Actually a pair of them. When a provider registers to be a data provider, a special unspendable normal output is created to allow for quick scanning. Since the marker is based on the oracletxid, it becomes a single address where all the providers can be found. - - A convention is used so that the datafee can be changed by registering again. it is assumed that there wont be too many of these datafee changes. if more than one from the same provider happens in the same block, the lower price is used. - - The other efficiency issue is finding the most recent data point. We want to create a linked list of all data points, going back to the first one. In order to make this efficient, a special and unique per provider/oracletxid baton utxo is used. This should have exactly one utxo, so the search would be a direct lookup and it is passed on from one data point to the next. There is some small chance that the baton utxo is spent in a non-data transaction, so provision is made to allow for recreating a baton utxo in case it isnt found. The baton utxo is a convenience and doesnt affect validation - - Required transactions: - 0) create oracle description -> just needs to create txid for oracle data - 1) register as oracle data provider with price -> become a registered oracle data provider - 2) pay provider for N oracle data points -> lock funds for oracle provider - 3) publish oracle data point -> publish data and collect payment - - The format string is a set of chars with the following meaning: - 's' -> <256 char string - 'S' -> <65536 char string - 'd' -> <256 binary data - 'D' -> <65536 binary data - 'c' -> 1 byte signed little endian number, 'C' unsigned - 't' -> 2 byte signed little endian number, 'T' unsigned - 'i' -> 4 byte signed little endian number, 'I' unsigned - 'l' -> 8 byte signed little endian number, 'L' unsigned - 'h' -> 32 byte hash - - create: - vins.*: normal inputs - vout.0: txfee tag to oracle normal address - vout.1: change, if any - vout.n-1: opreturn with name and description and format for data - - register: - vins.*: normal inputs - vout.0: txfee tag to normal marker address - vout.1: baton CC utxo - vout.2: change, if any - vout.n-1: opreturn with oracletxid, pubkey and price per data point - - subscribe: - vins.*: normal inputs - vout.0: subscription fee to publishers CC address - vout.1: change, if any - vout.n-1: opreturn with oracletxid, registered provider's pubkey, amount - - data: - vin.0: normal input - vin.1: baton CC utxo (most of the time) - vin.2+: subscription or data vout.0 - vout.0: change to publishers CC address - vout.1: baton CC utxo - vout.2: payment for dataprovider - vout.3: change, if any - vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format - - data (without payment) this is not needed as publisher can pay themselves! - vin.0: normal input - vin.1: baton CC utxo - vout.0: txfee to publishers normal address - vout.1: baton CC utxo - vout.2: change, if any - vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format - -*/ -extern int32_t hush_get_current_height(); -#define PUBKEY_SPOOFING_FIX_ACTIVATION 1563148800 -#define CC_MARKER_VALUE 10000 - -// start of consensus code -CScript EncodeOraclesCreateOpRet(uint8_t funcid,std::string name,std::string description,std::string format) -{ - CScript opret; uint8_t evalcode = EVAL_ORACLES; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << name << format << description); - return(opret); -} - -uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format) -{ - std::vector vopret; uint8_t *script,e,f,funcid; - GetOpReturnData(scriptPubKey,vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && script[0] == EVAL_ORACLES ) - { - if ( script[1] == 'C' ) - { - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> name; ss >> format; ss >> description) != 0 ) - { - return(script[1]); - } else fprintf(stderr,"DecodeOraclesCreateOpRet unmarshal error for C\n"); - } - } - return(0); -} - -CScript EncodeOraclesOpRet(uint8_t funcid,uint256 oracletxid,CPubKey pk,int64_t num) -{ - CScript opret; uint8_t evalcode = EVAL_ORACLES; - - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << pk << num); - return(opret); -} - -uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num) -{ - std::vector vopret; uint8_t *script,e,f; - - GetOpReturnData(scriptPubKey,vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && script[0] == EVAL_ORACLES ) - { - if (script[0] == EVAL_ORACLES && (script[1]== 'R' || script[1] == 'S' || script[1] == 'F') && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> pk; ss >> num)!=0) - return(f); - else return(script[1]); - } - return(0); -} - -CScript EncodeOraclesData(uint8_t funcid,uint256 oracletxid,uint256 batontxid,CPubKey pk,std::vector data) -{ - CScript opret; uint8_t evalcode = EVAL_ORACLES; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << batontxid << pk << data); - return(opret); -} - -uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data) -{ - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey,vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> batontxid; ss >> pk; ss >> data) != 0 ) - { - if ( e == EVAL_ORACLES && f == 'D' ) - return(f); - //else fprintf(stderr,"DecodeOraclesData evalcode.%d f.%c\n",e,f); - } //else fprintf(stderr,"DecodeOraclesData not enough opereturn data\n"); - return(0); -} - -CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp) -{ - static secp256k1_context *ctx; - size_t clen = CPubKey::PUBLIC_KEY_SIZE; - secp256k1_pubkey pubkey; CPubKey batonpk; uint8_t priv[32]; int32_t i; - if ( ctx == 0 ) - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - Myprivkey(priv); - cp->unspendableEvalcode2 = EVAL_ORACLES; - for (i=0; i<32; i++) - cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]); - while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 ) - { - for (i=0; i<32; i++) - fprintf(stderr,"%02x",cp->unspendablepriv2[i]); - fprintf(stderr," invalid privkey\n"); - if ( secp256k1_ec_privkey_tweak_add(ctx,cp->unspendablepriv2,priv) != 0 ) - break; - } - if ( secp256k1_ec_pubkey_create(ctx,&pubkey,cp->unspendablepriv2) != 0 ) - { - secp256k1_ec_pubkey_serialize(ctx,(unsigned char*)batonpk.begin(),&clen,&pubkey,SECP256K1_EC_COMPRESSED); - cp->unspendablepk2 = batonpk; - Getscriptaddress(batonaddr,MakeCC1vout(cp->evalcode,0,batonpk).scriptPubKey); - //fprintf(stderr,"batonpk.(%s) -> %s\n",(char *)HexStr(batonpk).c_str(),batonaddr); - strcpy(cp->unspendableaddr2,batonaddr); - } else fprintf(stderr,"error creating pubkey\n"); - memset(priv,0,sizeof(priv)); - return(batonpk); -} - -int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publisher) -{ - uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; - std::vector > unspentOutputs; - SetCCunspents(unspentOutputs,markeraddr,false); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - height = (int32_t)it->second.blockHeight; - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) - { - if ( DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R' ) - { - if ( oracletxid == reforacletxid && pk == publisher ) - { - if ( height > dheight || (height == dheight && dfee < datafee) ) - { - dheight = height; - datafee = dfee; - if ( 0 && dheight != 0 ) - fprintf(stderr,"set datafee %.8f height.%d\n",(double)datafee/COIN,height); - } - } - } - } - } - return(datafee); -} - -int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher) -{ - CTransaction oracletx; char markeraddr[64]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0; - if ( myGetTransaction(oracletxid,oracletx,hashBlock) != 0 && (numvouts= oracletx.vout.size()) > 0 ) - { - if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) - { - CCtxidaddr(markeraddr,oracletxid); - datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher); - } - else - { - fprintf(stderr,"Could not decode op_ret from transaction %s\nscriptPubKey: %s\n", oracletxid.GetHex().c_str(), oracletx.vout[numvouts-1].scriptPubKey.ToString().c_str()); - } - } - return(datafee); -} - -static uint256 myIs_baton_spentinmempool(uint256 batontxid,int32_t batonvout) -{ - std::vector tmp_txs; - myGet_mempool_txs(tmp_txs,EVAL_ORACLES,'D'); - for (std::vector::const_iterator it=tmp_txs.begin(); it!=tmp_txs.end(); it++) - { - const CTransaction &tx = *it; - if ( tx.vout.size() > 0 && tx.vin.size() > 1 && batontxid == tx.vin[1].prevout.hash && batonvout == tx.vin[1].prevout.n ) - { - const uint256 &txid = tx.GetHash(); - //char str[65]; fprintf(stderr,"found baton spent in mempool %s\n",uint256_str(str,txid)); - return(txid); - } - } - return(batontxid); -} - -uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher,std::vector &dataarg) -{ - uint256 txid,oracletxid,hashBlock,btxid,batontxid = zeroid; int64_t dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; uint8_t *ptr; std::vector vopret,data; - std::vector > unspentOutputs; - SetCCunspents(unspentOutputs,batonaddr,true); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - height = (int32_t)it->second.blockHeight; - if ( it->second.satoshis != txfee ) - { - fprintf(stderr,"it->second.satoshis %llu != %llu txfee\n",(long long)it->second.satoshis,(long long)txfee); - continue; - } - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) - { - GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); - if ( vopret.size() > 2 ) - { - ptr = (uint8_t *)vopret.data(); - if ( (ptr[1] == 'D' && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D') || (ptr[1] == 'R' && DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R') ) - { - if ( oracletxid == reforacletxid && pk == publisher ) - { - if ( height > dheight ) - { - dheight = height; - batontxid = txid; - if ( ptr[1] == 'D' ) - dataarg = data; - //char str[65]; fprintf(stderr,"set batontxid %s height.%d\n",uint256_str(str,batontxid),height); - } - } - } - } - } - } - while ( myIsutxo_spentinmempool(ignoretxid,ignorevin,batontxid,1) != 0 ) - batontxid = myIs_baton_spentinmempool(batontxid,1); - return(batontxid); -} - -uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk) -{ - std::vector > unspentOutputs; - CTransaction regtx; uint256 hash,txid,batontxid,oracletxid; CPubKey pk; int32_t numvouts,height,maxheight=0; int64_t datafee; char markeraddr[64],batonaddr[64]; std::vector data; struct CCcontract_info *cp,C; - batontxid = zeroid; - cp = CCinit(&C,EVAL_ORACLES); - CCtxidaddr(markeraddr,reforacletxid); - SetCCunspents(unspentOutputs,markeraddr,false); - //char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk)); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - //fprintf(stderr,"check %s\n",uint256_str(str,txid)); - height = (int32_t)it->second.blockHeight; - if ( myGetTransaction(txid,regtx,hash) != 0 ) - { - if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid && pk == refpk ) - { - Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey); - batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); - break; - } - } - } - return(batontxid); -} - -int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen) -{ - char _str[65]; int32_t sflag = 0,i,val32,len = 0,slen = 0,dlen = 0; uint32_t uval32; uint16_t uval16; int16_t val16; int64_t val = 0; uint64_t uval = 0; - *valp = 0; - *hashp = zeroid; - if ( str != 0 ) - str[0] = 0; - switch ( fmt ) - { - case 's': slen = data[offset++]; break; - case 'S': slen = data[offset++]; slen |= ((int32_t)data[offset++] << 8); break; - case 'd': dlen = data[offset++]; break; - case 'D': dlen = data[offset++]; dlen |= ((int32_t)data[offset++] << 8); break; - case 'c': len = 1; sflag = 1; break; - case 'C': len = 1; break; - case 't': len = 2; sflag = 1; break; - case 'T': len = 2; break; - case 'i': len = 4; sflag = 1; break; - case 'I': len = 4; break; - case 'l': len = 8; sflag = 1; break; - case 'L': len = 8; break; - case 'h': len = 32; break; - default: return(-1); break; - } - if ( slen != 0 ) - { - if ( str != 0 ) - { - if ( slen < DRAGON_MAXSCRIPTSIZE && offset+slen <= datalen ) - { - for (i=0; i data,std::string format) -{ - int64_t offset=0,len=0; char fmt; - - for (int i=0; idata.size()-offset) return (0); - if (fmt=='S' || fmt=='s') - { - for (int j=offset;j127) return (0); - } - offset+=len; - } - if (offset!=data.size()) return (0); - else return (offset); -} - -int64_t _correlate_price(int64_t *prices,int32_t n,int64_t price) -{ - int32_t i,count = 0; int64_t diff,threshold = (price >> 8); - for (i=0; i> 1) ) - return(0); - else return(price); -} - -int64_t correlate_price(int32_t height,int64_t *prices,int32_t n) -{ - int32_t i,j; int64_t price = 0; - if ( n == 1 ) - return(prices[0]); - for (i=0; i %llu ht.%d\n",(long long)price,height); - return(price); -} - -int64_t OracleCorrelatedPrice(int32_t height,std::vector origprices) -{ - std::vector sorted; int32_t i,n; int64_t *prices,price; - if ( (n= origprices.size()) == 1 ) - return(origprices[0]); - std::sort(origprices.begin(), origprices.end()); - prices = (int64_t *)calloc(n,sizeof(*prices)); - i = 0; - for (std::vector::const_iterator it=sorted.begin(); it!=sorted.end(); it++) - prices[i++] = *it; - price = correlate_price(height,prices,i); - free(prices); - return(price); -} - -int32_t oracleprice_add(std::vector &publishers,CPubKey pk,int32_t height,std::vector data,int32_t maxheight) -{ - struct oracleprice_info item; int32_t flag = 0; - for (std::vector::iterator it=publishers.begin(); it!=publishers.end(); it++) - { - if ( pk == it->pk ) - { - flag = 1; - if ( height > it->height ) - { - it->height = height; - it->data = data; - return(height); - } - } - } - if ( flag == 0 ) - { - item.pk = pk; - item.data = data; - item.height = height; - publishers.push_back(item); - return(height); - } else return(0); -} - -/*int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format) -{ - std::vector > unspentOutputs; - CTransaction regtx; uint256 hash,txid,oracletxid,batontxid; CPubKey pk; int32_t i,ht,maxheight=0; int64_t datafee,price; char batonaddr[64]; std::vector data; struct CCcontract_info *cp,C; std::vector publishers; std::vector prices; - if ( format[0] != 'L' ) - return(0); - cp = CCinit(&C,EVAL_ORACLES); - SetCCunspents(unspentOutputs,markeraddr,false); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - ht = (int32_t)it->second.blockHeight; - if ( myGetTransaction(txid,regtx,hash) != 0 ) - { - if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid ) - { - Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey); - batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); - if ( batontxid != zeroid && (ht= oracleprice_add(publishers,pk,ht,data,maxheight)) > maxheight ) - maxheight = ht; - } - } - } - if ( maxheight > 10 ) - { - for (std::vector::const_iterator it=publishers.begin(); it!=publishers.end(); it++) - { - if ( it->height >= maxheight-10 ) - { - oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size()); - if ( price != 0 ) - prices.push_back(price); - } - } - return(OracleCorrelatedPrice(height,prices)); - } - return(0); -}*/ - -int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) -{ - //char destaddr[64]; - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - //if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - } - return(0); -} - -bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,uint256 oracletxid,CPubKey publisher,int64_t datafee) -{ - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; CScript scriptPubKey; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - if ( OracleDatafee(scriptPubKey,oracletxid,publisher) != datafee ) - return eval->Invalid("mismatched datafee"); - scriptPubKey = MakeCC1vout(cp->evalcode,0,publisher).scriptPubKey; - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - if ( i == 0 ) - return eval->Invalid("unexpected vin.0 is CC"); - //fprintf(stderr,"vini.%d check mempool\n",i); - else if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - //if ( hashBlock == zerohash ) - // return eval->Invalid("cant Oracles from mempool"); - if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - { - if ( i == 1 && vinTx.vout[1].scriptPubKey != tx.vout[1].scriptPubKey ) - return eval->Invalid("baton violation"); - else if ( i != 1 && scriptPubKey == vinTx.vout[tx.vin[i].prevout.n].scriptPubKey ) - inputs += assetoshis; - } - } - } - } - for (i=0; iInvalid("invalid CC vout CC destination"); - } - } - } - } - if ( inputs != outputs+datafee ) - { - fprintf(stderr,"inputs %llu vs outputs %llu + datafee %llu\n",(long long)inputs,(long long)outputs,(long long)datafee); - return eval->Invalid("mismatched inputs != outputs + datafee"); - } - else return(true); -} - -/*nt32_t GetLatestTimestamp(int32_t height) -{ - if ( HUSH_NSPV_SUPERLITE ) return (NSPV_blocktime(height)); - return(hush_heightstamp(height)); -} */ - -bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) -{ - uint256 oracletxid,batontxid,txid; uint64_t txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts; int64_t amount; uint256 hashblock; - uint8_t *script; std::vector vopret,data; CPubKey publisher,tmppk,oraclespk; char tmpaddress[64],vinaddress[64],oraclesaddr[64]; - CTransaction tmptx; std::string name,desc,format; - - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); - if ( vopret.size() > 2 ) - { - oraclespk=GetUnspendable(cp,0); - Getscriptaddress(oraclesaddr,CScript() << ParseHex(HexStr(oraclespk)) << OP_CHECKSIG); - script = (uint8_t *)vopret.data(); - switch ( script[1] ) - { - case 'C': // create - // vins.*: normal inputs - // vout.0: txfee tag to oracle normal address - // vout.1: change, if any - // vout.n-1: opreturn with name and description and format for data - return eval->Invalid("unexpected OraclesValidate for create"); - break; - case 'F': // fund (activation on Jul 15th 2019 00:00) - // vins.*: normal inputs - // vout.0: txfee to oracle CC address of users pubkey - // vout.1: change, if any - // vout.n-1: opreturn with createtxid, pubkey and amount - return eval->Invalid("unexpected OraclesValidate for create"); - break; - case 'R': // register - // vin.0: normal inputs - // vin.n-1: CC input from pubkeys oracle CC addres - to prove that register came from pubkey that is registred (activation on Jul 15th 2019 00:00) - // vout.0: txfee tag to normal marker address - // vout.1: baton CC utxo - // vout.2: marker from oraclesfund tx to normal pubkey address (activation on Jul 15th 2019 00:00) - // vout.n-2: change, if any - // vout.n-1: opreturn with createtxid, pubkey and price per data point - if (GetLatestTimestamp(eval->GetCurrentHeight())>PUBKEY_SPOOFING_FIX_ACTIVATION) - { - if ((numvouts=tx.vout.size()) < 1 || DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,tmppk,amount)!='R') - return eval->Invalid("invalid oraclesregister OP_RETURN data!"); - else if (myGetTransaction(oracletxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid oraclescreate txid!"); - else if ((numvouts=tmptx.vout.size()) < 1 || DecodeOraclesCreateOpRet(tmptx.vout[numvouts-1].scriptPubKey,name,desc,format)!='C') - return eval->Invalid("invalid oraclescreate OP_RETURN data!"); - else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for oraclescreate!"); - else if (ConstrainVout(tmptx.vout[0],0,oraclesaddr,txfee)==0) - return eval->Invalid("invalid marker for oraclescreate!"); - else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for oraclesregister!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 && (*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0) - return eval->Invalid("there is no CC vin from oraclesfund tx"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 1 && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || DecodeOraclesOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,txid,tmppk,amount)!='F' - || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE || !Getscriptaddress(vinaddress,tmptx.vout[tx.vin[1].prevout.n].scriptPubKey) - || !GetCCaddress(cp,tmpaddress,tmppk) || strcmp(tmpaddress,vinaddress)!=0) || oracletxid!=txid) - return eval->Invalid("invalid vin.1 for oraclesregister, it must be CC vin or pubkey not same as vin pubkey, register and fund tx must be done from owner of pubkey that registers to oracle!!"); - else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 1 && (myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || DecodeOraclesOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,txid,tmppk,amount)!='F' - || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE || !Getscriptaddress(vinaddress,tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].scriptPubKey) - || !GetCCaddress(cp,tmpaddress,tmppk) || strcmp(tmpaddress,vinaddress)!=0) || oracletxid!=txid) - return eval->Invalid("invalid vin."+std::to_string(tx.vin.size()-1)+" for oraclesregister, it must be CC vin or pubkey not same as vin pubkey, register and fund tx must be done from owner of pubkey that registers to oracle!!"); - else if (CCtxidaddr(tmpaddress,oracletxid).IsValid() && ConstrainVout(tx.vout[0],0,tmpaddress,txfee)==0) - return eval->Invalid("invalid marker for oraclesregister!"); - else if (!Getscriptaddress(tmpaddress,CScript() << ParseHex(HexStr(tmppk)) << OP_CHECKSIG) || ConstrainVout(tx.vout[2],0,tmpaddress,CC_MARKER_VALUE)==0) - return eval->Invalid("pubkey in OP_RETURN and in vout.2 not matching, register must be done from owner of pubkey that registers to oracle!"); - } - else return eval->Invalid("unexpected OraclesValidate for register"); - break; - case 'S': // subscribe - // vins.*: normal inputs - // vout.0: subscription fee to publishers CC address - // vout.1: change, if any - // vout.n-1: opreturn with createtxid, registered provider's pubkey, amount - return eval->Invalid("unexpected OraclesValidate for subscribe"); - break; - case 'D': // data - // vin.0: normal input - // vin.1: baton CC utxo (most of the time) - // vin.2+: subscription vout.0 - // vout.0: change to publishers CC address - // vout.1: baton CC utxo - // vout.2: payment for dataprovider - // vout.3: change, if any - if ( numvins >= 2 && numvouts >= 3 && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,batontxid,publisher,data) == 'D' ) - { - if ( OraclesDataValidate(cp,eval,tx,oracletxid,publisher,tx.vout[2].nValue) != 0 ) - { - return(true); - } else return(false); - } - return eval->Invalid("unexpected OraclesValidate 'D' tx invalid"); - break; - default: - fprintf(stderr,"illegal oracles funcid.(%c)\n",script[1]); - return eval->Invalid("unexpected OraclesValidate funcid"); - break; - } - } else return eval->Invalid("unexpected oracles missing funcid"); - return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); - } - return(true); -} -// end of consensus code - -// helper functions for rpc calls in rpcwallet.cpp - -int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,uint256 oracletxid,CPubKey pk,int64_t total,int32_t maxinputs) -{ - char coinaddr[64],funcid; int64_t nValue,price,totalinputs = 0; uint256 tmporacletxid,tmpbatontxid,txid,hashBlock; std::vector origpubkey,data; CTransaction vintx; int32_t numvouts,vout,n = 0; - std::vector > unspentOutputs; CPubKey tmppk; int64_t tmpnum; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr,true); - //fprintf(stderr,"addoracleinputs from (%s)\n",coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - //char str[65]; fprintf(stderr,"oracle check %s/v%d\n",uint256_str(str,txid),vout); - if ( myGetTransaction(txid,vintx,hashBlock) != 0 && (numvouts=vintx.vout.size()-1)>0) - { - if ((funcid=DecodeOraclesOpRet(vintx.vout[numvouts].scriptPubKey,tmporacletxid,tmppk,tmpnum))!=0 && (funcid=='S' || funcid=='D')) - { - if (funcid=='D' && DecodeOraclesData(vintx.vout[numvouts].scriptPubKey,tmporacletxid,tmpbatontxid,tmppk,data)==0) - fprintf(stderr,"invalid oraclesdata transaction \n"); - else if (tmporacletxid==oracletxid) - { - // get valid CC payments - if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) - { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; - } //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN); - } - } - } else fprintf(stderr,"couldnt find transaction\n"); - } - return(totalinputs); -} - -int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey publisher) -{ - char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx; - std::vector txids; - GetCCaddress(cp,coinaddr,publisher); - SetCCtxids(txids,coinaddr,true,cp->evalcode,oracletxid,'S'); - //fprintf(stderr,"scan lifetime of %s\n",coinaddr); - for (std::vector::const_iterator it=txids.begin(); it!=txids.end(); it++) - { - txid = *it; - if ( myGetTransaction(txid,subtx,hashBlock) != 0 ) - { - if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && pk == publisher ) - { - total += subtx.vout[0].nValue; - } - } - } - return(total); -} - -int64_t AddMyOraclesFunds(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 oracletxid) -{ - char coinaddr[64],funcid; int64_t nValue,tmpamount; uint256 tmporacletxid,txid,hashBlock,ignoretxid; int32_t numvouts,vout,ignorevin; - std::vector > unspentOutputs; CTransaction vintx; CPubKey tmppk; - - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr,true); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - nValue = it->second.satoshis; - if ( myGetTransaction(txid,vintx,hashBlock) != 0 && (numvouts=vintx.vout.size())>0) - { - if ((funcid=DecodeOraclesOpRet(vintx.vout[numvouts-1].scriptPubKey,tmporacletxid,tmppk,tmpamount))!=0 && funcid=='F' && tmppk==pk - && tmporacletxid==oracletxid && tmpamount==nValue && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout)==0) - { - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - return (nValue); - } - } else fprintf(stderr,"couldnt find transaction\n"); - } - - std::vector tmp_txs; - myGet_mempool_txs(tmp_txs,EVAL_ORACLES,'F'); - for (std::vector::const_iterator it=tmp_txs.begin(); it!=tmp_txs.end(); it++) - { - const CTransaction &txmempool = *it; - const uint256 &hash = txmempool.GetHash(); - nValue=txmempool.vout[0].nValue; - - if ((funcid=DecodeOraclesOpRet(txmempool.vout[txmempool.vout.size()-1].scriptPubKey,tmporacletxid,tmppk,tmpamount))!=0 && funcid=='F' - && tmppk==pk && tmporacletxid==oracletxid && tmpamount==nValue && myIsutxo_spentinmempool(ignoretxid,ignorevin,hash,0)==0) - { - mtx.vin.push_back(CTxIn(hash,0,CScript())); - return (nValue); - } - } - return (0); -} - -UniValue OracleCreate(const CPubKey& pk, int64_t txfee,std::string name,std::string description,std::string format) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C; char fmt; - - cp = CCinit(&C,EVAL_ORACLES); - if ( name.size() > 32) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "name."<< (int32_t)name.size() << " must be less then 32"); - if (description.size() > 4096) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "description."<< (int32_t)description.size() << " must be less then 4096"); - if (format.size() > 4096 ) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "format."<< (int32_t)format.size() << " must be less then 4096"); - if ( name.size() == 0 ) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "name must not be empty"); - for(int i = 0; i < format.size(); i++) - { - fmt=format[i]; - switch (fmt) - { - case 's': case 'S': case 'd': case 'D': - case 'c': case 'C': case 't': case 'T': - case 'i': case 'I': case 'l': case 'L': - case 'h': break; - default: CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "invalid format type"); - } - } - if ( txfee == 0 ) - txfee = 10000; - mypk = pk.IsValid()?pk:pubkey2pk(Mypubkey()); - Oraclespk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,2*txfee,3,pk.IsValid()) > 0 ) - { - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(Oraclespk)) << OP_CHECKSIG)); - return(FinalizeCCTxExt(pk.IsValid(),0,cp,mtx,mypk,txfee,EncodeOraclesCreateOpRet('C',name,description,format))); - } - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "error adding normal inputs"); -} - -UniValue OracleFund(const CPubKey& pk, int64_t txfee,uint256 oracletxid) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); CTransaction tx; - CPubKey mypk,oraclespk; struct CCcontract_info *cp,C; std::string name,desc,format; int32_t numvouts; uint256 hashBlock; - - if (GetLatestTimestamp(hush_currentheight())evalcode,CC_MARKER_VALUE,mypk)); - return(FinalizeCCTxExt(pk.IsValid(),0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('F',oracletxid,mypk,CC_MARKER_VALUE))); - } - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "error adding normal inputs"); -} - -UniValue OracleRegister(const CPubKey& pk, int64_t txfee,uint256 oracletxid,int64_t datafee) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,markerpubkey,batonpk,oraclespk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64]; - std::string name,desc,format; int32_t numvouts; uint256 hashBlock; CTransaction tx; - - cp = CCinit(&C,EVAL_ORACLES); - if ( txfee == 0 ) - txfee = 10000; - if (myGetTransaction(oracletxid,tx,hashBlock)==0 || (numvouts=tx.vout.size())<=0) - CCERR_RESULT("oraclecc",CCLOG_INFO, stream << "cant find oracletxid " << oracletxid.GetHex()); - if (DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,desc,format)!='C') - CCERR_RESULT("oraclecc",CCLOG_INFO, stream << "invalid oracletxid " << oracletxid.GetHex()); - if ( datafee < txfee ) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "datafee must be txfee or more"); - mypk = pk.IsValid()?pk:pubkey2pk(Mypubkey()); - oraclespk = GetUnspendable(cp,0); - batonpk = OracleBatonPk(batonaddr,cp); - markerpubkey = CCtxidaddr(markeraddr,oracletxid); - if (AddNormalinputs(mtx,mypk,3*txfee,4,pk.IsValid())) - { - if (GetLatestTimestamp(hush_currentheight())>PUBKEY_SPOOFING_FIX_ACTIVATION && AddMyOraclesFunds(cp,mtx,mypk,oracletxid)!=CC_MARKER_VALUE) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "error adding inputs from your Oracles CC address, please fund it first with oraclesfund rpc!"); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk)); - if (GetLatestTimestamp(hush_get_current_height())>PUBKEY_SPOOFING_FIX_ACTIVATION) mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTxExt(pk.IsValid(),0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee))); - } - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "error adding normal inputs"); -} - -UniValue OracleSubscribe(const CPubKey& pk, int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); CTransaction tx; - CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64]; std::string name,desc,format; int32_t numvouts; uint256 hashBlock; - cp = CCinit(&C,EVAL_ORACLES); - if ( txfee == 0 ) - txfee = 10000; - if (myGetTransaction(oracletxid,tx,hashBlock)==0 || (numvouts=tx.vout.size())<=0) - CCERR_RESULT("oraclecc",CCLOG_INFO, stream << "cant find oracletxid " << oracletxid.GetHex()); - if (DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,desc,format)!='C') - CCERR_RESULT("oraclecc",CCLOG_INFO, stream << "invalid oracletxid " << oracletxid.GetHex()); - mypk = pk.IsValid()?pk:pubkey2pk(Mypubkey()); - markerpubkey = CCtxidaddr(markeraddr,oracletxid); - if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,64,pk.IsValid()) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); - return(FinalizeCCTxExt(pk.IsValid(),0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('S',oracletxid,mypk,amount))); - } - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "error adding normal inputs"); -} - -UniValue OracleData(const CPubKey& pk, int64_t txfee,uint256 oracletxid,std::vector data) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CScript pubKey; CPubKey mypk,batonpk; int64_t offset,datafee,inputs,CCchange = 0; struct CCcontract_info *cp,C; uint256 batontxid,hashBlock; - char coinaddr[64],batonaddr[64]; std::vector prevdata; CTransaction tx; std::string name,description,format; int32_t len,numvouts; - - cp = CCinit(&C,EVAL_ORACLES); - mypk = pk.IsValid()?pk:pubkey2pk(Mypubkey()); - if ( data.size() > 8192 ) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "datasize " << (int32_t)data.size() << " is too big"); - if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 ) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "datafee " << (double)datafee/COIN << "is illegal"); - if ( myGetTransaction(oracletxid,tx,hashBlock) != 0 && (numvouts=tx.vout.size()) > 0 ) - { - if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) - { - if (oracle_parse_data_format(data,format)==0) - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "data does not match length or content format specification"); - } - else - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "invalid oracle txid opret data"); - } - else - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "invalid oracle txid"); - if ( txfee == 0 ) - txfee = 10000; - GetCCaddress(cp,coinaddr,mypk); - if ( AddNormalinputs(mtx,mypk,2*txfee,3,pk.IsValid()) > 0 ) // have enough funds even if baton utxo not there - { - batonpk = OracleBatonPk(batonaddr,cp); - batontxid = OracleBatonUtxo(txfee,cp,oracletxid,batonaddr,mypk,prevdata); - if ( batontxid != zeroid ) // not impossible to fail, but hopefully a very rare event - mtx.vin.push_back(CTxIn(batontxid,1,CScript())); - else fprintf(stderr,"warning: couldnt find baton utxo %s\n",batonaddr); - if ( (inputs= AddOracleInputs(cp,mtx,oracletxid,mypk,datafee,60)) > 0 ) - { - if ( inputs > datafee ) - CCchange = (inputs - datafee); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk)); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CC_MARKER_VALUE,batonpk)); - mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTxExt(pk.IsValid(),0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data))); - } else - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "couldnt find enough oracle inputs " << coinaddr << ", limit 1 per utxo"); - } - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "couldnt add normal inputs"); -} - -UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen) -{ - UniValue obj(UniValue::VARR); uint256 hash; int32_t i,j=0; int64_t val; char str[DRAGON_MAXSCRIPTSIZE*2+1]; - for (i=0; i= datalen ) - break; - } - return(obj); -} - -UniValue OracleDataSample(uint256 reforacletxid,uint256 txid) -{ - UniValue result(UniValue::VOBJ); CTransaction tx,oracletx; uint256 hashBlock,btxid,oracletxid; std::string error; - CPubKey pk; std::string name,description,format; int32_t numvouts; std::vector data; char str[67], *formatstr = 0; - - result.push_back(Pair("result","success")); - if ( myGetTransaction(reforacletxid,oracletx,hashBlock) != 0 && (numvouts=oracletx.vout.size()) > 0 ) - { - if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) - { - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts=tx.vout.size()) > 0 ) - { - if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid ) - { - if ( (formatstr= (char *)format.c_str()) == 0 ) - formatstr = (char *)""; - result.push_back(Pair("txid",uint256_str(str,txid))); - result.push_back(Pair("data",OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()))); - return(result); - } - else error="invalid data tx"; - } - else error="cannot find data txid"; - } - else error="invalid oracles txid"; - } - else error="cannot find oracles txid"; - result.push_back(Pair("result","error")); - result.push_back(Pair("error",error)); - return(result); -} - -UniValue OracleDataSamples(uint256 reforacletxid,char* batonaddr,int32_t num) -{ - UniValue result(UniValue::VOBJ),b(UniValue::VARR); CTransaction tx,oracletx; uint256 txid,hashBlock,btxid,oracletxid; - CPubKey pk; std::string name,description,format; int32_t numvouts,n=0,vout; std::vector data; char *formatstr = 0, addr[64]; - std::vector txids; int64_t nValue; - - result.push_back(Pair("result","success")); - if ( myGetTransaction(reforacletxid,oracletx,hashBlock) != 0 && (numvouts=oracletx.vout.size()) > 0 ) - { - if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) - { - std::vector tmp_txs; - myGet_mempool_txs(tmp_txs,EVAL_ORACLES,'D'); - for (std::vector::const_iterator it=tmp_txs.begin(); it!=tmp_txs.end(); it++) - { - const CTransaction &txmempool = *it; - const uint256 &hash = txmempool.GetHash(); - if ((numvouts=txmempool.vout.size())>0 && txmempool.vout[1].nValue==CC_MARKER_VALUE && DecodeOraclesData(txmempool.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid ) - { - Getscriptaddress(addr,txmempool.vout[1].scriptPubKey); - if (strcmp(addr,batonaddr)!=0) continue; - if ( (formatstr= (char *)format.c_str()) == 0 ) - formatstr = (char *)""; - UniValue a(UniValue::VOBJ); - a.push_back(Pair("txid",hash.GetHex())); - a.push_back(Pair("data",OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()))); - b.push_back(a); - if ( ++n >= num && num != 0) - { - result.push_back(Pair("samples",b)); - return(result); - } - } - } - SetCCtxids(txids,batonaddr,true,EVAL_ORACLES,reforacletxid,'D'); - if (txids.size()>0) - { - for (std::vector::const_iterator it=txids.end()-1; it!=txids.begin(); it--) - { - txid=*it; - if (myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts=tx.vout.size()) > 0 ) - { - if ( tx.vout[1].nValue==CC_MARKER_VALUE && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid ) - { - if ( (formatstr= (char *)format.c_str()) == 0 ) - formatstr = (char *)""; - UniValue a(UniValue::VOBJ); - a.push_back(Pair("txid",txid.GetHex())); - a.push_back(Pair("data",OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()))); - b.push_back(a); - if ( ++n >= num && num != 0) - { - result.push_back(Pair("samples",b)); - return(result); - } - } - } - } - } - } - else - CCERR_RESULT("pegscc",CCLOG_INFO, stream << "invalid oracletxid " << oracletxid.GetHex()); - } - else - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "cant find oracletxid " << oracletxid.GetHex()); - result.push_back(Pair("samples",b)); - return(result); -} - -UniValue OracleInfo(uint256 origtxid) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); - std::vector > unspentOutputs; int32_t height; - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CTransaction tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; - struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector data; - std::map> publishers; - - cp = CCinit(&C,EVAL_ORACLES); - CCtxidaddr(markeraddr,origtxid); - if ( myGetTransaction(origtxid,tx,hashBlock) == 0 ) - { - fprintf(stderr,"cant find oracleid\n"); - result.push_back(Pair("result","error")); - result.push_back(Pair("error","cant find oracleid")); - return(result); - } - if ( myGetTransaction(origtxid,tx,hashBlock) != 0 ) - { - if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("txid",uint256_str(str,origtxid))); - result.push_back(Pair("name",name)); - result.push_back(Pair("description",description)); - result.push_back(Pair("format",format)); - result.push_back(Pair("marker",markeraddr)); - SetCCunspents(unspentOutputs,markeraddr,false); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - height = (int32_t)it->second.blockHeight; - if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && - DecodeOraclesOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid ) - { - if (publishers.find(pk)==publishers.end() || height>publishers[pk].second) - { - publishers[pk].first=txid; - publishers[pk].second=height; - } - } - } - for (std::map>::iterator it = publishers.begin(); it != publishers.end(); ++it) - { - if ( myGetTransaction(it->second.first,tx,hashBlock) != 0 && DecodeOraclesOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R') - { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin()))); - Getscriptaddress(batonaddr,tx.vout[1].scriptPubKey); - batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); - obj.push_back(Pair("baton",batonaddr)); - obj.push_back(Pair("batontxid",uint256_str(str,batontxid))); - funding = LifetimeOraclesFunds(cp,oracletxid,pk); - sprintf(numstr,"%.8f",(double)funding/COIN); - obj.push_back(Pair("lifetime",numstr)); - funding = AddOracleInputs(cp,mtx,oracletxid,pk,0,0); - sprintf(numstr,"%.8f",(double)funding/COIN); - obj.push_back(Pair("funds",numstr)); - sprintf(numstr,"%.8f",(double)datafee/COIN); - obj.push_back(Pair("datafee",numstr)); - a.push_back(obj); - } - } - result.push_back(Pair("registered",a)); - } - else - CCERR_RESULT("pegscc",CCLOG_INFO, stream << "invalid oracletxid " << oracletxid.GetHex()); - } - else - CCERR_RESULT("oraclescc",CCLOG_INFO, stream << "cant find oracletxid " << oracletxid.GetHex()); - return(result); -} - -UniValue OraclesList() -{ - UniValue result(UniValue::VARR); std::vector txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65]; - cp = CCinit(&C,EVAL_ORACLES); - SetCCtxids(txids,cp->normaladdr,false,cp->evalcode,zeroid,'C'); - for (std::vector::const_iterator it=txids.begin(); it!=txids.end(); it++) - { - txid = *it; - if ( myGetTransaction(txid,createtx,hashBlock) != 0 ) - { - if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) - { - result.push_back(uint256_str(str,txid)); - } - } - } - return(result); -} diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index ee1826cdd..4cb86d676 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -376,13 +376,7 @@ static const CRPCCommand vRPCCommands[] = { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false }, #endif - // fsm - { "FSM", "FSMaddress", &FSMaddress, true }, - { "FSM", "FSMcreate", &FSMcreate, true }, - { "FSM", "FSMlist", &FSMlist, true }, - { "FSM", "FSMinfo", &FSMinfo, true }, - - // fsm + // nspv { "nSPV", "nspv_getinfo", &nspv_getinfo, true }, { "nSPV", "nspv_login", &nspv_login, true }, { "nSPV", "nspv_listunspent", &nspv_listunspent, true }, @@ -397,10 +391,6 @@ static const CRPCCommand vRPCCommands[] = { "nSPV", "nspv_logout", &nspv_logout, true }, { "nSPV", "nspv_listccmoduleunspent", &nspv_listccmoduleunspent, true }, - { "CClib", "cclibaddress", &cclibaddress, true }, - { "CClib", "cclibinfo", &cclibinfo, true }, - { "CClib", "cclib", &cclib, true }, - /* Address index */ { "addressindex", "getaddressmempool", &getaddressmempool, true }, { "addressindex", "getaddressutxos", &getaddressutxos, false }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 766957e9f..bbce095f5 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -243,16 +243,6 @@ extern UniValue channelsaddress(const UniValue& params, bool fHelp, const CPubKe extern UniValue cclibaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue cclibinfo(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue cclib(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue channelslist(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue channelsinfo(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue channelsopen(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue channelspayment(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue channelsclose(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue channelsrefund(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue FSMaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue FSMcreate(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue FSMlist(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue FSMinfo(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp //extern UniValue getnewaddress64(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ede7fb87e..78dbb1908 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -52,6 +52,8 @@ #include "hush_defs.h" #include #include "rpchushwallet.h" +#include "cc/utils.h" +#include "cc/CCinclude.h" using namespace std; using namespace libzcash; @@ -6092,101 +6094,8 @@ int32_t hush_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33, void *pT return(siglen); } -#include "../cc/CCassets.h" -#include "../cc/CCfsm.h" - int32_t ensure_CCrequirements(uint8_t evalcode) { - CCerror = ""; - if ( ASSETCHAINS_CCDISABLES[evalcode] != 0 || (evalcode == EVAL_MARMARA && ASSETCHAINS_MARMARA == 0) ) - { - // check if a height activation has been set. - fprintf(stderr, "evalcode.%i activates at height. %i current height.%i\n", evalcode, mapHeightEvalActivate[evalcode], hush_currentheight()); - if ( mapHeightEvalActivate[evalcode] == 0 || hush_currentheight() == 0 || mapHeightEvalActivate[evalcode] > hush_currentheight() ) - { - fprintf(stderr,"evalcode %d disabled\n",evalcode); - return(-1); - } - } - if ( NOTARY_PUBKEY33[0] == 0 ) - { - fprintf(stderr,"no -pubkey set\n"); - return(-1); - } else if ( GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) == 0 ) { - fprintf(stderr,"no -addressindex\n"); - return(-1); - } else if ( GetBoolArg("-spentindex", DEFAULT_SPENTINDEX) == 0 ) { - fprintf(stderr,"no -spentindex\n"); - return(-1); - } - else return(0); -} - -UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector &pubkey) -{ - UniValue result(UniValue::VOBJ); char destaddr[64],str[64]; CPubKey mypk,pk; - pk = GetUnspendable(cp,0); - GetCCaddress(cp,destaddr,pk); - if ( strcmp(destaddr,cp->unspendableCCaddr) != 0 ) - { - uint8_t priv[32]; - Myprivkey(priv); // it is assumed the CC's normal address'es -pubkey was used - fprintf(stderr,"fix mismatched CCaddr %s -> %s\n",cp->unspendableCCaddr,destaddr); - strcpy(cp->unspendableCCaddr,destaddr); - memset(priv,0,32); - } - result.push_back(Pair("result", "success")); - sprintf(str,"%sCCAddress",name); - result.push_back(Pair(str,cp->unspendableCCaddr)); - sprintf(str,"%sCCBalance",name); - result.push_back(Pair(str,ValueFromAmount(CCaddress_balance(cp->unspendableCCaddr,1)))); - sprintf(str,"%sNormalAddress",name); - result.push_back(Pair(str,cp->normaladdr)); - sprintf(str,"%sNormalBalance",name); - result.push_back(Pair(str,ValueFromAmount(CCaddress_balance(cp->normaladdr,0)))); - if (strcmp(name,"Gateways")==0) result.push_back(Pair("GatewaysPubkey","03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40")); - if ((strcmp(name,"Channels")==0 || strcmp(name,"Heir")==0) && pubkey.size() == 33) - { - sprintf(str,"%sCC1of2Address",name); - mypk = pubkey2pk(Mypubkey()); - GetCCaddress1of2(cp,destaddr,mypk,pubkey2pk(pubkey)); - result.push_back(Pair(str,destaddr)); - if (GetTokensCCaddress1of2(cp,destaddr,mypk,pubkey2pk(pubkey))>0) - { - sprintf(str,"%sCC1of2TokensAddress",name); - result.push_back(Pair(str,destaddr)); - } - } - else if (strcmp(name,"Tokens")!=0) - { - if (GetTokensCCaddress(cp,destaddr,pk)>0) - { - sprintf(str,"%sCCTokensAddress",name); - result.push_back(Pair(str,destaddr)); - } - } - if ( pubkey.size() == 33 ) - { - if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 ) - { - sprintf(str,"PubkeyCCaddress(%s)",name); - result.push_back(Pair(str,destaddr)); - sprintf(str,"PubkeyCCbalance(%s)",name); - result.push_back(Pair(str,ValueFromAmount(CCaddress_balance(destaddr,0)))); - } - } - if ( GetCCaddress(cp,destaddr,pubkey2pk(Mypubkey())) != 0 ) - { - sprintf(str,"myCCAddress(%s)",name); - result.push_back(Pair(str,destaddr)); - sprintf(str,"myCCbalance(%s)",name); - result.push_back(Pair(str,ValueFromAmount(CCaddress_balance(destaddr,1)))); - } - if ( Getscriptaddress(destaddr,(CScript() << Mypubkey() << OP_CHECKSIG)) != 0 ) - { - result.push_back(Pair("myaddress",destaddr)); - result.push_back(Pair("mybalance",ValueFromAmount(CCaddress_balance(destaddr,0)))); - } - return(result); + return -1; } bool pubkey2addr(char *destaddr,uint8_t *pubkey33); @@ -6253,142 +6162,6 @@ UniValue setpubkey(const UniValue& params, bool fHelp, const CPubKey& mypk) return result; } -UniValue cclibaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - struct CCcontract_info *cp,C; std::vector pubkey; uint8_t evalcode = EVAL_FIRSTUSER; - if ( fHelp || params.size() > 2 ) - throw runtime_error("cclibaddress [evalcode] [pubkey]\n"); - if ( params.size() >= 1 ) - { - evalcode = atoi(params[0].get_str().c_str()); - if ( evalcode < EVAL_FIRSTUSER || evalcode > EVAL_LASTUSER ) - throw runtime_error("evalcode not between EVAL_FIRSTUSER and EVAL_LASTUSER\n"); - if ( params.size() == 2 ) - pubkey = ParseHex(params[1].get_str().c_str()); - } - cp = CCinit(&C,evalcode); - if ( ensure_CCrequirements(cp->evalcode) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - if ( cp == 0 ) - throw runtime_error("error creating *cp\n"); - return(CCaddress(cp,(char *)"CClib",pubkey)); -} - -UniValue cclibinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - struct CCcontract_info *cp,C; uint8_t evalcode = EVAL_FIRSTUSER; - if ( fHelp || params.size() > 0 ) - throw runtime_error("cclibinfo\n"); - if ( ensure_CCrequirements(0) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - cp = CCinit(&C,evalcode); - return(CClib_info(cp)); -} - -UniValue cclib(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - struct CCcontract_info *cp,C; char *method,*jsonstr=0; uint8_t evalcode = EVAL_FIRSTUSER; - std::string vobjJsonSerialized; - - if ( fHelp || params.size() > 3 ) - throw runtime_error("cclib method [evalcode] [JSON params]\n"); - if ( ASSETCHAINS_CCLIB.size() == 0 ) - throw runtime_error("no -ac_cclib= specified\n"); - if ( ensure_CCrequirements(0) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - method = (char *)params[0].get_str().c_str(); - if ( params.size() >= 2 ) - { - evalcode = atoi(params[1].get_str().c_str()); - if ( evalcode < EVAL_FIRSTUSER || evalcode > EVAL_LASTUSER ) - { - //printf("evalcode.%d vs (%d, %d)\n",evalcode,EVAL_FIRSTUSER,EVAL_LASTUSER); - throw runtime_error("evalcode not between EVAL_FIRSTUSER and EVAL_LASTUSER\n"); - } - if ( params.size() == 3 ) - { - if (params[2].getType() == UniValue::VOBJ) { - vobjJsonSerialized = params[2].write(0, 0); - jsonstr = (char *)vobjJsonSerialized.c_str(); - } - else // VSTR assumed - jsonstr = (char *)params[2].get_str().c_str(); - //fprintf(stderr,"params.(%s %s %s)\n",params[0].get_str().c_str(),params[1].get_str().c_str(),jsonstr); - } - } - cp = CCinit(&C,evalcode); - return(CClib(cp,method,jsonstr)); -} - -UniValue FSMaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - struct CCcontract_info *cp,C; std::vector pubkey; - cp = CCinit(&C,EVAL_FSM); - if ( fHelp || params.size() > 1 ) - throw runtime_error("FSMaddress [pubkey]\n"); - if ( ensure_CCrequirements(cp->evalcode) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - if ( params.size() == 1 ) - pubkey = ParseHex(params[0].get_str().c_str()); - return(CCaddress(cp,(char *)"FSM",pubkey)); -} - -UniValue assetsaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - struct CCcontract_info *cp, C; std::vector pubkey; - cp = CCinit(&C, EVAL_ASSETS); - if (fHelp || params.size() > 1) - throw runtime_error("assetsaddress [pubkey]\n"); - if (ensure_CCrequirements(cp->evalcode) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - if (params.size() == 1) - pubkey = ParseHex(params[0].get_str().c_str()); - return(CCaddress(cp, (char *)"Assets", pubkey)); -} - -UniValue FSMcreate(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); std::string name,states,hex; - if ( fHelp || params.size() != 2 ) - throw runtime_error("FSMcreate name states\n"); - if ( ensure_CCrequirements(EVAL_FSM) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - name = params[0].get_str(); - states = params[1].get_str(); - hex = FSMCreate(0,name,states); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else result.push_back(Pair("error", "couldnt create FSM transaction")); - return(result); -} - -UniValue FSMlist(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 tokenid; - if ( fHelp || params.size() > 0 ) - throw runtime_error("FSMlist\n"); - if ( ensure_CCrequirements(EVAL_FSM) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - return(FSMList()); -} - -UniValue FSMinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 FSMtxid; - if ( fHelp || params.size() != 1 ) - throw runtime_error("FSMinfo fundingtxid\n"); - if ( ensure_CCrequirements(EVAL_FSM) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - FSMtxid = Parseuint256((char *)params[0].get_str().c_str()); - return(FSMInfo(FSMtxid)); -} - UniValue getbalance64(const UniValue& params, bool fHelp, const CPubKey& mypk) { set setAddress; vector vecOutputs;