forked from hush/hush3
Duke
5 months ago
13 changed files with 16 additions and 3825 deletions
@ -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; |
|||
} |
@ -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; i<numvins; i++) |
|||
{ |
|||
//fprintf(stderr,"vini.%d\n",i);
|
|||
if ( (*cp->ismyvin)(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; i<numvouts; i++) |
|||
{ |
|||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
|||
if ( (assetoshis= IsAuctionvout(cp,tx,i)) != 0 ) |
|||
outputs += assetoshis; |
|||
} |
|||
if ( inputs != outputs+COIN+txfee ) |
|||
{ |
|||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); |
|||
return eval->Invalid("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; i<numvins; i++) |
|||
{ |
|||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) |
|||
{ |
|||
fprintf(stderr,"Auctionget invalid vini\n"); |
|||
return eval->Invalid("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<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0; |
|||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; |
|||
GetCCaddress(cp,coinaddr,pk); |
|||
SetCCunspents(unspentOutputs,coinaddr,true); |
|||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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(""); |
|||
} |
|||
|
|||
|
@ -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 <cryptoconditions.h> |
|||
|
|||
#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<CC*> BetProtocol::PlayerConditions() |
|||
{ |
|||
std::vector<CC*> subs; |
|||
for (int i=0; i<players.size(); i++) |
|||
subs.push_back(CCNewSecp256k1(players[i])); |
|||
return subs; |
|||
} |
|||
|
|||
|
|||
CC* BetProtocol::MakeDisputeCond() |
|||
{ |
|||
CC *disputePoker = CCNewEval(E_MARSHAL( |
|||
ss << disputeCode << VARINT(waitBlocks) << vmParams; |
|||
)); |
|||
|
|||
CC *anySig = CCNewThreshold(1, PlayerConditions()); |
|||
|
|||
return CCNewThreshold(2, {disputePoker, anySig}); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
* spendFee is the amount assigned to each output, for the purposes of posting |
|||
* dispute / evidence. |
|||
*/ |
|||
CMutableTransaction BetProtocol::MakeSessionTx(CAmount spendFee) |
|||
{ |
|||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); |
|||
|
|||
CC *disputeCond = MakeDisputeCond(); |
|||
mtx.vout.push_back(CTxOut(spendFee, CCPubKey(disputeCond))); |
|||
cc_free(disputeCond); |
|||
|
|||
for (int i=0; i<players.size(); i++) { |
|||
CC *cond = CCNewSecp256k1(players[i]); |
|||
mtx.vout.push_back(CTxOut(spendFee, CCPubKey(cond))); |
|||
cc_free(cond); |
|||
} |
|||
return mtx; |
|||
} |
|||
|
|||
|
|||
CMutableTransaction BetProtocol::MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash) |
|||
{ |
|||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); |
|||
|
|||
CC *disputeCond = MakeDisputeCond(); |
|||
mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CScript())); |
|||
|
|||
std::vector<unsigned char> 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<unsigned char> 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<CTxOut> 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<CTxOut> 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<unsigned char> 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<uint8_t> 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<unsigned char> 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<CTxOut> 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<uint8_t> 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<uint8_t> 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<CTransaction> 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<spends.size(); i++) |
|||
{ |
|||
std::vector<unsigned char> 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"); |
|||
} |
@ -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; i<numvins; i++) |
|||
{ |
|||
//fprintf(stderr,"vini.%d\n",i);
|
|||
if ( (*cp->ismyvin)(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; i<numvouts; i++) |
|||
{ |
|||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
|||
if ( (assetoshis= IsFaucetvout(cp,tx,i)) != 0 ) |
|||
outputs += assetoshis; |
|||
} |
|||
if ( inputs != outputs+FAUCETSIZE+txfee ) |
|||
{ |
|||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); |
|||
return eval->Invalid("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<std::pair<CAddressIndexKey, CAmount> > txids; |
|||
numvins = tx.vin.size(); |
|||
numvouts = tx.vout.size(); |
|||
preventCCvins = preventCCvouts = -1; |
|||
if ( numvouts < 1 ) |
|||
return eval->Invalid("no vouts"); |
|||
else |
|||
{ |
|||
for (i=0; i<numvins; i++) |
|||
{ |
|||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) |
|||
{ |
|||
fprintf(stderr,"faucetget invalid vini\n"); |
|||
return eval->Invalid("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<std::pair<CAddressIndexKey, CAmount> >::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<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0; |
|||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > 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<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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); |
|||
} |
@ -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; i<numvins; i++) |
|||
{ |
|||
//fprintf(stderr,"vini.%d\n",i);
|
|||
if ( (*cp->ismyvin)(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; i<numvouts; i++) |
|||
{ |
|||
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
|
|||
if ( (assetoshis= IsFSMvout(cp,tx,i)) != 0 ) |
|||
outputs += assetoshis; |
|||
} |
|||
if ( inputs != outputs+COIN+txfee ) |
|||
{ |
|||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); |
|||
return eval->Invalid("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; i<numvins; i++) |
|||
{ |
|||
if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) |
|||
{ |
|||
fprintf(stderr,"fsmget invalid vini\n"); |
|||
return eval->Invalid("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<uint8_t> origpubkey; CTransaction vintx; int32_t n = 0; |
|||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; |
|||
GetCCaddress(cp,coinaddr,pk); |
|||
SetCCunspents(unspentOutputs,coinaddr,true); |
|||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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(""); |
|||
} |
|||
|
|||
|
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue