From 3a3c67e0fccfb71dad570863f2c8f71454f8177f Mon Sep 17 00:00:00 2001 From: Duke Date: Sat, 13 Jan 2024 00:06:09 -0500 Subject: [PATCH] Delete many things we do not want or need --- src/Makefile.am | 5 - src/cc/CCcustom.cpp | 9 +- src/cc/CCtokens.cpp | 1059 ----------------- src/cc/assets.cpp | 442 +------ src/cc/cclib.cpp | 43 +- src/cc/eval.cpp | 3 +- src/cc/gamescc.cpp | 1813 ----------------------------- src/cc/heir.cpp | 4 +- src/cc/heir_validate.h | 3 + src/cc/import.cpp | 764 ------------ src/cc/importgateway.cpp | 1288 -------------------- src/cc/makeprices | 8 - src/cc/maketetris | 7 - src/coins.cpp | 14 +- src/crosschain.cpp | 132 --- src/crosschain.h | 2 - src/importcoin.cpp | 425 ------- src/main.cpp | 26 +- src/miner.cpp | 14 +- src/primitives/transaction.h | 3 +- src/rpc/crosschain.cpp | 1185 ------------------- src/rpc/rawtransaction.cpp | 9 +- src/rpc/server.cpp | 30 - src/rpc/server.h | 17 - src/test-hush/test_coinimport.cpp | 260 ----- src/wallet/rpcwallet.cpp | 505 -------- 26 files changed, 52 insertions(+), 8018 deletions(-) delete mode 100644 src/cc/CCtokens.cpp delete mode 100644 src/cc/gamescc.cpp delete mode 100644 src/cc/import.cpp delete mode 100644 src/cc/importgateway.cpp delete mode 100755 src/cc/makeprices delete mode 100755 src/cc/maketetris delete mode 100644 src/importcoin.cpp delete mode 100644 src/test-hush/test_coinimport.cpp diff --git a/src/Makefile.am b/src/Makefile.am index d08f0d49e..2e890ebd7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -272,13 +272,10 @@ libbitcoin_server_a_SOURCES = \ asyncrpcqueue.cpp \ bloom.cpp \ cc/eval.cpp \ - cc/import.cpp \ - cc/importgateway.cpp \ cc/CCassetsCore.cpp \ cc/CCcustom.cpp \ cc/CCtx.cpp \ cc/CCutils.cpp \ - cc/CCtokens.cpp \ cc/assets.cpp \ cc/faucet.cpp \ cc/fsm.cpp \ @@ -339,7 +336,6 @@ libbitcoin_wallet_a_SOURCES = \ zcash/Note.cpp \ transaction_builder.cpp \ wallet/rpcdump.cpp \ - cc/CCtokens.cpp \ cc/CCassetsCore.cpp \ cc/CCassetstx.cpp \ cc/CCtx.cpp \ @@ -406,7 +402,6 @@ libbitcoin_common_a_SOURCES = \ core_read.cpp \ core_write.cpp \ hash.cpp \ - importcoin.cpp \ key.cpp \ key_io.cpp \ keystore.cpp \ diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index fb3ff024a..28e15b148 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -27,7 +27,6 @@ #include "CCPrices.h" #include "CCPegs.h" #include "CCtokens.h" -#include "CCImportGateway.h" /* CCcustom has most of the functions that need to be extended to create a new CC contract. @@ -409,16 +408,16 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) strcpy(cp->normaladdr, TokensNormaladdr); strcpy(cp->CChexstr, TokensCChexstr); memcpy(cp->CCpriv, TokensCCpriv, 32); - cp->validate = TokensValidate; - cp->ismyvin = IsTokensInput; + //cp->validate = TokensValidate; + //cp->ismyvin = IsTokensInput; break; case EVAL_IMPORTGATEWAY: strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr); strcpy(cp->normaladdr, ImportGatewayNormaladdr); strcpy(cp->CChexstr, ImportGatewayCChexstr); memcpy(cp->CCpriv, ImportGatewayCCpriv, 32); - cp->validate = ImportGatewayValidate; - cp->ismyvin = IsImportGatewayInput; + //cp->validate = ImportGatewayValidate; + //cp->ismyvin = IsImportGatewayInput; break; default: if ( CClib_initcp(cp,evalcode) < 0 ) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp deleted file mode 100644 index 236b4c3ed..000000000 --- a/src/cc/CCtokens.cpp +++ /dev/null @@ -1,1059 +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 "CCtokens.h" -#include "importcoin.h" - -/* TODO: correct this: ------------------------------ - The SetTokenFillamounts() and ValidateTokenRemainder() work in tandem to calculate the vouts for a fill and to validate the vouts, respectively. - - This pair of functions are critical to make sure the trading is correct and is the trickiest part of the tokens contract. - - //vin.0: normal input - //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - //vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue - //vout.0: remaining amount of bid to unspendable - //vout.1: vin.1 value to signer of vin.2 - //vout.2: vin.2 tokenoshis to original pubkey - //vout.3: CC output for tokenoshis change (if any) - //vout.4: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [tokenid] [remaining token required] [origpubkey] - ValidateTokenRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits); - - Yes, this is quite confusing... - - In ValidateTokenRemainder the naming convention is nValue is the coin/token with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or tokens, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits. - - We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it. - ------------------------------ -*/ - - - -// tx validation -bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn) -{ - static uint256 zero; - CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2; - int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts; - int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore; - std::vector> oprets; - vscript_t /*vopretExtra,*/ tmporigpubkey, ignorepubkey; - uint8_t funcid, evalCodeInOpret; - char destaddr[64], origaddr[64], CCaddr[64]; - std::vector voutTokenPubkeys, vinTokenPubkeys; - - if (strcmp(SMART_CHAIN_SYMBOL, "ROGUE") == 0 && chainActive.Height() <= 12500) - return true; - - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - outputs = inputs = 0; - preventCCvins = preventCCvouts = -1; - - // check boundaries: - if (numvouts < 1) - return eval->Invalid("no vouts"); - - if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets)) == 0) - return eval->Invalid("TokenValidate: invalid opreturn payload"); - - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokensValidate funcId=" << (char)(funcid?funcid:' ') << " evalcode=" << std::hex << (int)cp->evalcode << std::endl); - - if (eval->GetTxUnconfirmed(tokenid, createTx, hashBlock) == 0) - return eval->Invalid("cant find token create txid"); - //else if (IsCCInput(tx.vin[0].scriptSig) != 0) - // return eval->Invalid("illegal token vin0"); // <-- this validation was removed because some token tx might not have normal vins - else if (funcid != 'c') - { - if (tokenid == zeroid) - return eval->Invalid("illegal tokenid"); - else if (!TokensExactAmounts(true, cp, inputs, outputs, eval, tx, tokenid)) { - if (!eval->Valid()) - return false; //TokenExactAmounts must call eval->Invalid()! - else - return eval->Invalid("tokens cc inputs != cc outputs"); - } - } - - // validate spending from token cc addr: allowed only for burned non-fungible tokens: - if (ExtractTokensCCVinPubkeys(tx, vinTokenPubkeys) && std::find(vinTokenPubkeys.begin(), vinTokenPubkeys.end(), GetUnspendable(cp, NULL)) != vinTokenPubkeys.end()) { - // validate spending from token unspendable cc addr: - int64_t burnedAmount = HasBurnedTokensvouts(cp, eval, tx, tokenid); - if (burnedAmount > 0) { - vscript_t vopretNonfungible; - GetNonfungibleData(tokenid, vopretNonfungible); - if( vopretNonfungible.empty() ) - return eval->Invalid("spending cc marker not supported for fungible tokens"); - } - } - - switch (funcid) - { - case 'c': // token create should not be validated as it has no CC inputs, so return 'invalid' - // token tx structure for 'c': - //vin.0: normal input - //vout.0: issuance tokenoshis to CC - //vout.1: normal output for change (if any) - //vout.n-1: opreturn EVAL_TOKENS 'c' - return eval->Invalid("incorrect token funcid"); - - case 't': // transfer - // token tx structure for 't' - //vin.0: normal input - //vin.1 .. vin.n-1: valid CC outputs - //vout.0 to n-2: tokenoshis output to CC - //vout.n-2: normal output for change (if any) - //vout.n-1: opreturn EVAL_TOKENS 't' tokenid - if (inputs == 0) - return eval->Invalid("no token inputs for transfer"); - - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "token transfer preliminarily validated inputs=" << inputs << "->outputs=" << outputs << " preventCCvins=" << preventCCvins<< " preventCCvouts=" << preventCCvouts << std::endl); - break; // breaking to other contract validation... - - default: - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "illegal tokens funcid=" << (char)(funcid?funcid:' ') << std::endl); - return eval->Invalid("unexpected token funcid"); - } - - return true; -} - -// helper funcs: - -// extract cc token vins' pubkeys: -bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector &vinPubkeys) { - - bool found = false; - CPubKey pubkey; - struct CCcontract_info *cpTokens, tokensC; - - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - vinPubkeys.clear(); - - for (int32_t i = 0; i < tx.vin.size(); i++) - { - // check for cc token vins: - if( (*cpTokens->ismyvin)(tx.vin[i].scriptSig) ) - { - - auto findEval = [](CC *cond, struct CCVisitor _) { - bool r = false; - - if (cc_typeId(cond) == CC_Secp256k1) { - *(CPubKey*)_.context = buf2pk(cond->publicKey); - //std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl; - r = true; - } - // false for a match, true for continue - return r ? 0 : 1; - }; - - CC *cond = GetCryptoCondition(tx.vin[i].scriptSig); - - if (cond) { - CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey }; - bool out = !cc_visit(cond, visitor); - cc_free(cond); - - if (pubkey.IsValid()) { - vinPubkeys.push_back(pubkey); - found = true; - } - } - } - } - return found; -} - -// this is just for log messages indentation fur debugging recursive calls: -thread_local uint32_t tokenValIndentSize = 0; - -// validates opret for token tx: -uint8_t ValidateTokenOpret(CTransaction tx, uint256 tokenid) { - - uint256 tokenidOpret = zeroid; - uint8_t funcid; - uint8_t dummyEvalCode; - std::vector voutPubkeysDummy; - std::vector> opretsDummy; - - // this is just for log messages indentation fur debugging recursive calls: - std::string indentStr = std::string().append(tokenValIndentSize, '.'); - - if (tx.vout.size() == 0) - return (uint8_t)0; - - if ((funcid = DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeysDummy, opretsDummy)) == 0) - { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl); - return (uint8_t)0; - } - else if (funcid == 'c') - { - if (tokenid != zeroid && tokenid == tx.GetHash()) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl); - return funcid; - } - else { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my tokenbase txid=" << tx.GetHash().GetHex() << std::endl); - } - } - else if (funcid == 'i') - { - if (tokenid != zeroid && tokenid == tx.GetHash()) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is import 'i' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl); - return funcid; - } - else { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my import txid=" << tx.GetHash().GetHex() << std::endl); - } - } - else if (funcid == 't') - { - //std::cerr << indentStr << "ValidateTokenOpret() tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; - if (tokenid != zeroid && tokenid == tokenidOpret) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " returning true" << std::endl); - return funcid; - } - else { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not my tokenid=" << tokenidOpret.GetHex() << std::endl); - } - } - else { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "ValidateTokenOpret() not supported funcid=" << (char)funcid << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl); - } - return (uint8_t)0; -} - -// remove token->unspendablePk (it is only for marker usage) -void FilterOutTokensUnspendablePk(const std::vector &sourcePubkeys, std::vector &destPubkeys) { - struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - CPubKey tokensUnspendablePk = GetUnspendable(cpTokens, NULL); - destPubkeys.clear(); - - for (auto pk : sourcePubkeys) - if (pk != tokensUnspendablePk) - destPubkeys.push_back(pk); - -} - -void FilterOutNonCCOprets(const std::vector> &oprets, vscript_t &vopret) { - - vopret.clear(); - - if (oprets.size() > 2) - LOGSTREAM("cctokens", CCLOG_INFO, stream << "FilterOutNonCCOprets() warning!! oprets.size > 2 currently not supported" << oprets.size() << std::endl); - - for (auto o : oprets) { - if (o.first < OPRETID_FIRSTNONCCDATA) { // skip burn, import, etc opret data - vopret = o.second; // return first contract opret (more than 1 is not supported yet) - break; - } - } -} - -// Checks if the vout is a really Tokens CC vout -// also checks tokenid in opret or txid if this is 'c' tx -// goDeeper is true: the func also validates amounts of the passed transaction: -// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx -// checkPubkeys is true: validates if the vout is token vout1 or token vout1of2. Should always be true! -int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true*/, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid) -{ - - // this is just for log messages indentation fur debugging recursive calls: - std::string indentStr = std::string().append(tokenValIndentSize, '.'); - - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl); - - int32_t n = tx.vout.size(); - // just check boundaries: - if (n == 0 || v < 0 || v >= n-1) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "isTokensvout() incorrect params: (n == 0 or v < 0 or v >= n-1)" << " v=" << v << " n=" << n << " returning 0" << std::endl); - return(0); - } - - if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition()) - { - if (goDeeper) { - //validate all tx - int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0; - - tokenValIndentSize++; - // false --> because we already at the 1-st level ancestor tx and do not need to dereference ancestors of next levels - bool isEqual = TokensExactAmounts(false, cp, myCCVinsAmount, myCCVoutsAmount, eval, tx, reftokenid); - tokenValIndentSize--; - - if (!isEqual) { - // if ccInputs != ccOutputs and it is not the tokenbase tx - // this means it is possibly a fake tx (dimxy): - if (reftokenid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy) - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() warning: for the verified tx detected a bad vintx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx, skipping the verified tx" << std::endl); - return 0; - } - } - } - - // token opret most important checks (tokenid == reftokenid, tokenid is non-zero, tx is 'tokenbase'): - const uint8_t funcId = ValidateTokenOpret(tx, reftokenid); - //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; - if (funcId != 0) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null funcId=" << (char)(funcId ? funcId : ' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); - - uint8_t dummyEvalCode; - uint256 tokenIdOpret; - std::vector voutPubkeys, voutPubkeysInOpret; - vscript_t vopretExtra, vopretNonfungible; - std::vector> oprets; - - uint8_t evalCodeNonfungible = 0; - uint8_t evalCode1 = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim - uint8_t evalCode2 = 0; // will be checked if zero or not - - // test vouts for possible token use-cases: - std::vector> testVouts; - - DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysInOpret, oprets); - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "IsTokensvout() oprets.size()=" << oprets.size() << std::endl); - - // get assets/channels/gateways token data: - FilterOutNonCCOprets(oprets, vopretExtra); // NOTE: only 1 additional evalcode in token opret is currently supported - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "IsTokensvout() vopretExtra=" << HexStr(vopretExtra) << std::endl); - - // get non-fungible data - GetNonfungibleData(reftokenid, vopretNonfungible); - FilterOutTokensUnspendablePk(voutPubkeysInOpret, voutPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there) - - // NOTE: evalcode order in vouts is important: - // non-fungible-eval -> EVAL_TOKENS -> assets-eval - - if (vopretNonfungible.size() > 0) - evalCodeNonfungible = evalCode1 = vopretNonfungible.begin()[0]; - if (vopretExtra.size() > 0) - evalCode2 = vopretExtra.begin()[0]; - - if (evalCode1 == EVAL_TOKENS && evalCode2 != 0) { - evalCode1 = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...) - evalCode2 = 0; - } - - if( /*checkPubkeys &&*/ funcId != 'c' ) { // for 'c' there is no pubkeys - // verify that the vout is token by constructing vouts with the pubkeys in the opret: - - // maybe this is dual-eval 1 pubkey or 1of2 pubkey vout? - if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { - // check dual/three-eval 1 pubkey vout with the first pubkey - testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0]")) ); - if (evalCode2 != 0) - // also check in backward evalcode order - testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0] backward-eval")) ); - - if(voutPubkeys.size() == 2) { - // check dual/three eval 1of2 pubkeys vout - testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2")) ); - // check dual/three eval 1 pubkey vout with the second pubkey - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1]"))); - if (evalCode2 != 0) { - // also check in backward evalcode order: - // check dual/three eval 1of2 pubkeys vout - testVouts.push_back(std::make_pair(MakeTokensCC1of2vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2 backward-eval"))); - // check dual/three eval 1 pubkey vout with the second pubkey - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1] backward-eval"))); - } - } - - // maybe this is like gatewayclaim to single-eval token? - if( evalCodeNonfungible == 0 ) // do not allow to convert non-fungible to fungible token - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]), std::string("single-eval cc1 pk[0]"))); - - // maybe this is like FillSell for non-fungible token? - if( evalCode1 != 0 ) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval-token cc1 pk[0]"))); - if( evalCode2 != 0 ) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval2-token cc1 pk[0]"))); - - // the same for pk[1]: - if (voutPubkeys.size() == 2) { - if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]), std::string("single-eval cc1 pk[1]"))); - if (evalCode1 != 0) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval-token cc1 pk[1]"))); - if (evalCode2 != 0) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval2-token cc1 pk[1]"))); - } - } - - //special check for tx when spending from 1of2 CC address and one of pubkeys is global CC pubkey - struct CCcontract_info *cpEvalCode1,CEvalCode1; - cpEvalCode1 = CCinit(&CEvalCode1,evalCode1); - CPubKey pk=GetUnspendable(cpEvalCode1,0); - testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode1, tx.vout[v].nValue, voutPubkeys[0], pk), std::string("dual-eval1 pegscc cc1of2 pk[0] globalccpk")) ); - if (voutPubkeys.size() == 2) testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode1, tx.vout[v].nValue, voutPubkeys[1], pk), std::string("dual-eval1 pegscc cc1of2 pk[1] globalccpk")) ); - if (evalCode2!=0) - { - struct CCcontract_info *cpEvalCode2,CEvalCode2; - cpEvalCode2 = CCinit(&CEvalCode2,evalCode2); - CPubKey pk=GetUnspendable(cpEvalCode2,0); - testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode2, tx.vout[v].nValue, voutPubkeys[0], pk), std::string("dual-eval2 pegscc cc1of2 pk[0] globalccpk")) ); - if (voutPubkeys.size() == 2) testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode2, tx.vout[v].nValue, voutPubkeys[1], pk), std::string("dual-eval2 pegscc cc1of2 pk[1] globalccpk")) ); - } - - // maybe it is single-eval or dual/three-eval token change? - std::vector vinPubkeys, vinPubkeysUnfiltered; - ExtractTokensCCVinPubkeys(tx, vinPubkeysUnfiltered); - FilterOutTokensUnspendablePk(vinPubkeysUnfiltered, vinPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there) - - for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { - if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk"))); - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk"))); - - if (evalCode2 != 0) - // also check in backward evalcode order: - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk backward-eval"))); - } - - // try all test vouts: - for (auto t : testVouts) { - if (t.first == tx.vout[v]) { // test vout matches - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() valid amount=" << tx.vout[v].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode1 << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl); - return tx.vout[v].nValue; - } - } - - } - else { // funcid == 'c' - - if (!tx.IsCoinImport()) { - - vscript_t vorigPubkey; - std::string dummyName, dummyDescription; - std::vector> oprets; - - if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); - return 0; - } - - CPubKey origPubkey = pubkey2pk(vorigPubkey); - - - // TODO: add voutPubkeys for 'c' tx - - /* this would not work for imported tokens: - // for 'c' recognize the tokens only to token originator pubkey (but not to unspendable <-- closed sec violation) - // maybe this is like gatewayclaim to single-eval token? - if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, origPubkey), std::string("single-eval cc1 orig-pk"))); - // maybe this is like FillSell for non-fungible token? - if (evalCode1 != 0) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, origPubkey), std::string("dual-eval-token cc1 orig-pk"))); */ - - // note: this would not work if there are several pubkeys in the tokencreator's wallet (AddNormalinputs does not use pubkey param): - // for tokenbase tx check that normal inputs sent from origpubkey > cc outputs - int64_t ccOutputs = 0; - for (auto vout : tx.vout) - if (vout.scriptPubKey.IsPayToCryptoCondition() //TODO: add voutPubkey validation - && !IsTokenMarkerVout(vout)) // should not be marker here - ccOutputs += vout.nValue; - - int64_t normalInputs = TotalPubkeyNormalInputs(tx, origPubkey); // check if normal inputs are really signed by originator pubkey (someone not cheating with originator pubkey) - LOGSTREAM("cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() normalInputs=" << normalInputs << " ccOutputs=" << ccOutputs << " for tokenbase=" << reftokenid.GetHex() << std::endl); - - if (normalInputs >= ccOutputs) { - LOGSTREAM("cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() assured normalInputs >= ccOutputs" << " for tokenbase=" << reftokenid.GetHex() << std::endl); - if (!IsTokenMarkerVout(tx.vout[v])) // exclude marker - return tx.vout[v].nValue; - else - return 0; // vout is good, but do not take marker into account - } - else { - LOGSTREAM("cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() skipping vout not fulfilled normalInputs >= ccOutput" << " for tokenbase=" << reftokenid.GetHex() << " normalInputs=" << normalInputs << " ccOutputs=" << ccOutputs << std::endl); - } - } - else { - // imported tokens are checked in the eval::ImportCoin() validation code - if (!IsTokenMarkerVout(tx.vout[v])) // exclude marker - return tx.vout[v].nValue; - else - return 0; // vout is good, but do not take marker into account - } - } - LOGSTREAM("cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() no valid vouts evalCode=" << (int)evalCode1 << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); - } - //std::cerr << indentStr; fprintf(stderr,"IsTokensvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str()); - } - //std::cerr << indentStr; fprintf(stderr,"IsTokensvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN); - return(0); -} - -bool IsTokenMarkerVout(CTxOut vout) { - struct CCcontract_info *cpTokens, CCtokens_info; - cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS); - return vout == MakeCC1vout(EVAL_TOKENS, vout.nValue, GetUnspendable(cpTokens, NULL)); -} - -// compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs) -bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cp, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 reftokenid) -{ - CTransaction vinTx; - uint256 hashBlock; - int64_t tokenoshis; - - struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - - int32_t numvins = tx.vin.size(); - int32_t numvouts = tx.vout.size(); - inputs = outputs = 0; - - // this is just for log messages indentation for debugging recursive calls: - std::string indentStr = std::string().append(tokenValIndentSize, '.'); - - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "TokensExactAmounts() entered for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); - - for (int32_t i = 0; iismyvin)(tx.vin[i].scriptSig) /*|| IsVinAllowed(tx.vin[i].scriptSig) != 0*/) - { - //std::cerr << indentStr << "TokensExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl; - // we are not inside the validation code -- dimxy - if ((eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock))) - { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "TokensExactAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl); - return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt"); - } - else { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "TokenExactAmounts() checking vintx.vout for tx.vin[" << i << "] nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl); - - // validate vouts of vintx - tokenValIndentSize++; - tokenoshis = IsTokensvout(goDeeper, true, cpTokens, eval, vinTx, tx.vin[i].prevout.n, reftokenid); - tokenValIndentSize--; - if (tokenoshis != 0) - { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "TokensExactAmounts() adding vintx.vout for tx.vin[" << i << "] tokenoshis=" << tokenoshis << std::endl); - inputs += tokenoshis; - } - } - } - } - - for (int32_t i = 0; i < numvouts-1; i ++) // 'numvouts-1' <-- do not check opret - { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << indentStr << "TokenExactAmounts() recursively checking tx.vout[" << i << "] nValue=" << tx.vout[i].nValue << std::endl); - - // Note: we pass in here IsTokenvout(false,...) because we don't need to call TokenExactAmounts() recursively from IsTokensvout here - // indeed, if we pass 'true' we'll be checking this tx vout again - tokenValIndentSize++; - tokenoshis = IsTokensvout(false /*<--do not recursion here*/, true /*<--exclude non-tokens vouts*/, cpTokens, eval, tx, i, reftokenid); - tokenValIndentSize--; - - if (tokenoshis != 0) - { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "TokensExactAmounts() adding tx.vout[" << i << "] tokenoshis=" << tokenoshis << std::endl); - outputs += tokenoshis; - } - } - - //std::cerr << indentStr << "TokensExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; - - if (inputs != outputs) { - if (tx.GetHash() != reftokenid) - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "TokenExactAmounts() found unequal token cc inputs=" << inputs << " vs cc outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << " and this is not the create tx" << std::endl); - //fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); - return false; // do not call eval->Invalid() here! - } - else - return true; -} - - -// get non-fungible data from 'tokenbase' tx (the data might be empty) -void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible) -{ - CTransaction tokenbasetx; - uint256 hashBlock; - - if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "GetNonfungibleData() cound not load token creation tx=" << tokenid.GetHex() << std::endl); - return; - } - - vopretNonfungible.clear(); - // check if it is non-fungible tx and get its second evalcode from non-fungible payload - if (tokenbasetx.vout.size() > 0) { - std::vector origpubkey; - std::string name, description; - std::vector> oprets; - - if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, oprets) == 'c') { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - } - } -} - - -// overload, adds inputs from token cc addr -int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs) { - vscript_t vopretNonfungibleDummy; - return AddTokenCCInputs(cp, mtx, pk, tokenid, total, maxinputs, vopretNonfungibleDummy); -} - -// adds inputs from token cc addr and returns non-fungible opret payload if present -// also sets evalcode in cp, if needed -int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, vscript_t &vopretNonfungible) -{ - char tokenaddr[64], destaddr[64]; - int64_t threshold, nValue, price, totalinputs = 0; - int32_t n = 0; - std::vector > unspentOutputs; - - GetNonfungibleData(tokenid, vopretNonfungible); - if (vopretNonfungible.size() > 0) - cp->additionalTokensEvalcode2 = vopretNonfungible.begin()[0]; - - GetTokensCCaddress(cp, tokenaddr, pk); - SetCCunspents(unspentOutputs, tokenaddr,true); - - - if (unspentOutputs.empty()) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() no utxos for token dual/three eval addr=" << tokenaddr << " evalcode=" << (int)cp->evalcode << " additionalTokensEvalcode2=" << (int)cp->additionalTokensEvalcode2 << std::endl); - } - - threshold = total / (maxinputs != 0 ? maxinputs : CC_MAXVINS); - - for (std::vector >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) - { - CTransaction vintx; - uint256 hashBlock; - uint256 vintxid = it->first.txhash; - int32_t vout = (int32_t)it->first.index; - - if (it->second.satoshis < threshold) // this should work also for non-fungible tokens (there should be only 1 satoshi for non-fungible token issue) - continue; - - int32_t ivin; - for (ivin = 0; ivin < mtx.vin.size(); ivin ++) - if (vintxid == mtx.vin[ivin].prevout.hash && vout == mtx.vin[ivin].prevout.n) - break; - if (ivin != mtx.vin.size()) // that is, the tx.vout is already added to mtx.vin (in some previous calls) - continue; - - if (myGetTransaction(vintxid, vintx, hashBlock) != 0) - { - Getscriptaddress(destaddr, vintx.vout[vout].scriptPubKey); - if (strcmp(destaddr, tokenaddr) != 0 && - strcmp(destaddr, cp->unspendableCCaddr) != 0 && // TODO: check why this. Should not we add token inputs from unspendable cc addr if mypubkey is used? - strcmp(destaddr, cp->unspendableaddr2) != 0) // or the logic is to allow to spend all available tokens (what about unspendableaddr3)? - continue; - - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "AddTokenCCInputs() check vintx vout destaddress=" << destaddr << " amount=" << vintx.vout[vout].nValue << std::endl); - - if ((nValue = IsTokensvout(true, true/*<--add only valid token uxtos */, cp, NULL, vintx, vout, tokenid)) > 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,vintxid, vout) == 0) - { - //for non-fungible tokens check payload: - if (!vopretNonfungible.empty()) { - vscript_t vopret; - - // check if it is non-fungible token: - GetNonfungibleData(tokenid, vopret); - if (vopret != vopretNonfungible) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() found incorrect non-fungible opret payload for vintxid=" << vintxid.GetHex() << std::endl); - continue; - } - // non-fungible evalCode2 cc contract should also check if there exists only one non-fungible vout with amount = 1 - } - - - if (total != 0 && maxinputs != 0) // if it is not just to calc amount... - mtx.vin.push_back(CTxIn(vintxid, vout, CScript())); - - nValue = it->second.satoshis; - totalinputs += nValue; - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "AddTokenCCInputs() adding input nValue=" << nValue << std::endl); - n++; - - if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) - break; - } - } - } - - //std::cerr << "AddTokenCCInputs() found totalinputs=" << totalinputs << std::endl; - return(totalinputs); -} - -// checks if any token vouts are sent to 'dead' pubkey -int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid) -{ - uint8_t dummyEvalCode; - uint256 tokenIdOpret; - std::vector voutPubkeys, voutPubkeysDummy; - std::vector> oprets; - vscript_t vopretExtra, vopretNonfungible; - - uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim - uint8_t evalCode2 = 0; // will be checked if zero or not - - // test vouts for possible token use-cases: - std::vector> testVouts; - - int32_t n = tx.vout.size(); - // just check boundaries: - if (n == 0) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "HasBurnedTokensvouts() incorrect params: tx.vout.size() == 0, txid=" << tx.GetHash().GetHex() << std::endl); - return(0); - } - - - if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, dummyEvalCode, tokenIdOpret, voutPubkeysDummy, oprets) == 0) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "HasBurnedTokensvouts() cannot parse opret DecodeTokenOpRet returned 0, txid=" << tx.GetHash().GetHex() << std::endl); - return 0; - } - - // get assets/channels/gateways token data: - FilterOutNonCCOprets(oprets, vopretExtra); // NOTE: only 1 additional evalcode in token opret is currently supported - - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "HasBurnedTokensvouts() vopretExtra=" << HexStr(vopretExtra) << std::endl); - - GetNonfungibleData(reftokenid, vopretNonfungible); - - if (vopretNonfungible.size() > 0) - evalCode = vopretNonfungible.begin()[0]; - if (vopretExtra.size() > 0) - evalCode2 = vopretExtra.begin()[0]; - - if (evalCode == EVAL_TOKENS && evalCode2 != 0) { - evalCode = evalCode2; - evalCode2 = 0; - } - - voutPubkeys.push_back(pubkey2pk(ParseHex(CC_BURNPUBKEY))); - - int64_t burnedAmount = 0; - - for (int i = 0; i < tx.vout.size(); i++) { - - if (tx.vout[i].scriptPubKey.IsPayToCryptoCondition()) - { - // make all possible token vouts for dead pk: - for (std::vector::iterator it = voutPubkeys.begin(); it != voutPubkeys.end(); it++) { - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[i].nValue, *it), std::string("single-eval cc1 burn pk"))); - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[i].nValue, *it), std::string("three-eval cc1 burn pk"))); - - if (evalCode2 != 0) - // also check in backward evalcode order: - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[i].nValue, *it), std::string("three-eval cc1 burn pk backward-eval"))); - } - - // try all test vouts: - for (auto t : testVouts) { - if (t.first == tx.vout[i]) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "HasBurnedTokensvouts() burned amount=" << tx.vout[i].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl); - burnedAmount += tx.vout[i].nValue; - } - } - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "HasBurnedTokensvouts() total burned=" << burnedAmount << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); - } - } - - return burnedAmount; -} - -CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey) { - - uint8_t funcId, evalCode; - uint256 tokenid; - std::vector voutTokenPubkeys; - std::vector> oprets; - - if ((funcId = DecodeTokenOpRet(scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets)) != 0) { - CTransaction tokenbasetx; - uint256 hashBlock; - - if (myGetTransaction(tokenid, tokenbasetx, hashBlock) && tokenbasetx.vout.size() > 0) { - vscript_t vorigpubkey; - std::string name, desc; - if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, desc) != 0) - return pubkey2pk(vorigpubkey); - } - } - return CPubKey(); //return invalid pubkey -} - -// returns token creation signed raw tx -std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, std::string description, vscript_t nonfungibleData) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk; struct CCcontract_info *cp, C; - if (tokensupply < 0) { - CCerror = "negative tokensupply"; - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() =" << CCerror << "=" << tokensupply << std::endl); - return std::string(""); - } - if (!nonfungibleData.empty() && tokensupply != 1) { - CCerror = "for non-fungible tokens tokensupply should be equal to 1"; - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() " << CCerror << std::endl); - return std::string(""); - } - - - cp = CCinit(&C, EVAL_TOKENS); - if (name.size() > 32 || description.size() > 4096) // this is also checked on rpc level - { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl); - CCerror = "name should be <= 32, description should be <= 4096"; - return(""); - } - if (txfee == 0) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - - if (AddNormalinputs2(mtx, tokensupply + 2 * txfee, 64) > 0) // add normal inputs only from mypk - { - int64_t mypkInputs = TotalPubkeyNormalInputs(mtx, mypk); - if (mypkInputs < tokensupply) { // check that tokens amount are really issued with mypk (because in the wallet there maybe other privkeys) - CCerror = "some inputs signed not with -pubkey=pk"; - return std::string(""); - } - - uint8_t destEvalCode = EVAL_TOKENS; - if( nonfungibleData.size() > 0 ) - destEvalCode = nonfungibleData.begin()[0]; - - // NOTE: we should prevent spending fake-tokens from this marker in IsTokenvout(): - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cp, NULL))); // new marker to token cc addr, burnable and validated, vout pos now changed to 0 (from 1) - mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, tokensupply, mypk)); - //mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(cp->CChexstr) << OP_CHECKSIG)); // old marker (non-burnable because spending could not be validated) - //mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cp, NULL))); // ...moved to vout=0 for matching with rogue-game token - - return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), name, description, nonfungibleData))); - } - - CCerror = "cant find normal inputs"; - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "CreateToken() " << CCerror << std::endl); - return std::string(""); -} - -// transfer tokens to another pubkey -// param additionalEvalCode allows transfer of dual-eval non-fungible tokens -std::string TokenTransfer(int64_t txfee, uint256 tokenid, vscript_t destpubkey, int64_t total) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk; uint64_t mask; int64_t CCchange = 0, inputs = 0; struct CCcontract_info *cp, C; - vscript_t vopretNonfungible, vopretEmpty; - - if (total < 0) { - CCerror = strprintf("negative total"); - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << CCerror << "=" << total << std::endl); - return(""); - } - - cp = CCinit(&C, EVAL_TOKENS); - - if (txfee == 0) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - /*if ( cp->tokens1of2addr[0] == 0 ) - { - GetTokensCCaddress(cp, cp->tokens1of2addr, mypk); - fprintf(stderr,"set tokens1of2addr <- %s\n",cp->tokens1of2addr); - }*/ - if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) - { - mask = ~((1LL << mtx.vin.size()) - 1); // seems, mask is not used anymore - - if ((inputs = AddTokenCCInputs(cp, mtx, mypk, tokenid, total, 60, vopretNonfungible)) > 0) // NOTE: AddTokenCCInputs might set cp->additionalEvalCode which is used in FinalizeCCtx! - { - if (inputs < total) { //added dimxy - CCerror = strprintf("insufficient token inputs"); - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << std::endl); - return std::string(""); - } - - uint8_t destEvalCode = EVAL_TOKENS; - if (vopretNonfungible.size() > 0) - destEvalCode = vopretNonfungible.begin()[0]; - - if (inputs > total) - CCchange = (inputs - total); - mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, total, pubkey2pk(destpubkey))); // if destEvalCode == EVAL_TOKENS then it is actually MakeCC1vout(EVAL_TOKENS,...) - if (CCchange != 0) - mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, CCchange, mypk)); - - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout - - return FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, std::make_pair((uint8_t)0, vopretEmpty))); - } - else { - CCerror = strprintf("no token inputs"); - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << " for amount=" << total << std::endl); - } - //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size()); - } - else { - CCerror = strprintf("insufficient normal inputs for tx fee"); - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << std::endl); - } - return(""); -} - - -int64_t GetTokenBalance(CPubKey pk, uint256 tokenid) -{ - uint256 hashBlock; - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CTransaction tokentx; - - // CCerror = strprintf("obsolete, cannot return correct value without eval"); - // return 0; - - if (myGetTransaction(tokenid, tokentx, hashBlock) == 0) - { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "cant find tokenid" << std::endl); - CCerror = strprintf("cant find tokenid"); - return 0; - } - - struct CCcontract_info *cp, C; - cp = CCinit(&C, EVAL_TOKENS); - return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0)); -} - -UniValue TokenInfo(uint256 tokenid) -{ - UniValue result(UniValue::VOBJ); - uint256 hashBlock; - CTransaction tokenbaseTx; - std::vector origpubkey; - std::vector> oprets; - vscript_t vopretNonfungible; - std::string name, description; - struct CCcontract_info *cpTokens, tokensCCinfo; - - cpTokens = CCinit(&tokensCCinfo, EVAL_TOKENS); - - if( !myGetTransaction(tokenid, tokenbaseTx, hashBlock) ) - { - fprintf(stderr, "TokenInfo() cant find tokenid\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "cant find tokenid")); - return(result); - } - if ( HUSH_NSPV_FULLNODE && hashBlock.IsNull()) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "the transaction is still in mempool")); - return(result); - } - - if (tokenbaseTx.vout.size() > 0 && DecodeTokenCreateOpRet(tokenbaseTx.vout[tokenbaseTx.vout.size() - 1].scriptPubKey, origpubkey, name, description, oprets) != 'c') - { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenInfo() passed tokenid isnt token creation txid" << std::endl); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "tokenid isnt token creation txid")); - return result; - } - result.push_back(Pair("result", "success")); - result.push_back(Pair("tokenid", tokenid.GetHex())); - result.push_back(Pair("owner", HexStr(origpubkey))); - result.push_back(Pair("name", name)); - - int64_t supply = 0, output; - for (int v = 0; v < tokenbaseTx.vout.size() - 1; v++) - if ((output = IsTokensvout(false, true, cpTokens, NULL, tokenbaseTx, v, tokenid)) > 0) - supply += output; - result.push_back(Pair("supply", supply)); - result.push_back(Pair("description", description)); - - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - if( !vopretNonfungible.empty() ) - result.push_back(Pair("data", HexStr(vopretNonfungible))); - - if (tokenbaseTx.IsCoinImport()) { // if imported token - ImportProof proof; - CTransaction burnTx; - std::vector payouts; - CTxDestination importaddress; - - std::string sourceSymbol = "can't decode"; - std::string sourceTokenId = "can't decode"; - - if (UnmarshalImportTx(tokenbaseTx, proof, burnTx, payouts)) - { - // extract op_return to get burn source chain. - std::vector burnOpret; - std::string targetSymbol; - uint32_t targetCCid; - uint256 payoutsHash; - std::vector rawproof; - if (UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) { - if (rawproof.size() > 0) { - CTransaction tokenbasetx; - E_UNMARSHAL(rawproof, ss >> sourceSymbol; - if (!ss.eof()) - ss >> tokenbasetx); - - if (!tokenbasetx.IsNull()) - sourceTokenId = tokenbasetx.GetHash().GetHex(); - } - } - } - result.push_back(Pair("IsImported", "yes")); - result.push_back(Pair("sourceChain", sourceSymbol)); - result.push_back(Pair("sourceTokenId", sourceTokenId)); - } - - return result; -} - -UniValue TokenList() -{ - UniValue result(UniValue::VARR); - std::vector txids; - std::vector > addressIndexCCMarker; - - struct CCcontract_info *cp, C; uint256 txid, hashBlock; - CTransaction vintx; std::vector origpubkey; - std::string name, description; - - cp = CCinit(&C, EVAL_TOKENS); - - auto addTokenId = [&](uint256 txid) { - if (myGetTransaction(txid, vintx, hashBlock) != 0) { - if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description) != 0) { - result.push_back(txid.GetHex()); - } - } - }; - - SetCCtxids(txids, cp->normaladdr,false,cp->evalcode,zeroid,'c'); // find by old normal addr marker - for (std::vector::const_iterator it = txids.begin(); it != txids.end(); it++) { - addTokenId(*it); - } - - SetCCunspents(addressIndexCCMarker, cp->unspendableCCaddr,true); // find by burnable validated cc addr marker - for (std::vector >::const_iterator it = addressIndexCCMarker.begin(); it != addressIndexCCMarker.end(); it++) { - addTokenId(it->first.txhash); - } - - return(result); -} diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index d2ec4f21b..32e3482d3 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -19,448 +19,8 @@ #include "CCassets.h" #include "CCtokens.h" -/* - Assets can be created or transferred. - - native coins are also locked in the EVAL_ASSETS address, so we need a strict rule on when utxo in the special address are native coins and when they are assets. The specific rule that must not be violated is that vout0 for 'b'/'B' funcid are native coins. All other utxo locked in the special address are assets. - - To create an asset use CC EVAL_ASSETS to create a transaction where vout[0] funds the assets. Externally each satoshi can be interpreted to represent 1 asset, or 100 million satoshis for one asset with 8 decimals, and the other decimals in between. The interpretation of the number of decimals is left to the higher level usages. - - Once created, the assetid is the txid of the create transaction and using the assetid/0 it can spend the assets to however many outputs it creates. The restriction is that the last output must be an opreturn with the assetid. The sum of all but the first output needs to add up to the total assetoshis input. The first output is ignored and used for change from txfee. - - What this means is that vout 0 of the creation txid and vouts 1 ... n-2 for transfer vouts are assetoshi outputs. - - There is a special type of transfer to an unspendable address, that locks the asset and creates an offer for all. The details specified in the opreturn. In order to be compatible with the signing restrictions, the "unspendable" address is actually an address whose privkey is known to all. Funds sent to this address can only be spent if the swap parameters are fulfilled, or if the original pubkey cancels the offer by spending it. - - Types of transactions: - create name:description -> txid for assetid - transfer -> [{address:amount}, ... ] // like withdraw api - selloffer -> cancel or fillsell -> mempool txid or rejected, might not confirm - buyoffer -> cancelbuy or fillbuy -> mempool txid or rejected, might not confirm - exchange -> cancel or fillexchange -> mempool txid or rejected, might not confirm - - assetsaddress // all assets end up in a special address for each pubkey - assetbalance - assetutxos - assetsbalances - asks - bids - swaps - - valid CC output: create or transfer or buyoffer or selloffer or exchange or cancel or fill - - - buyoffer: - vins.*: normal inputs (bid + change) - vout.0: amount of bid to unspendable - vout.1: CC output for marker - vout.2: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey] - - cancelbuy: - vin.0: normal input - vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - vin.2: CC marker from buyoffer for txfee - vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] - vout.1: vin.2 back to users pubkey - vout.2: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid] 0 0 [origpubkey] - - fillbuy: - vin.0: normal input - vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue - vout.0: remaining amount of bid to unspendable - vout.1: vin.1 value to signer of vin.2 - vout.2: vin.2 assetoshis to original pubkey - vout.3: CC output for assetoshis change (if any) - vout.4: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey] - - selloffer: - vin.0: normal input - vin.1+: valid CC output for sale - vout.0: vin.1 assetoshis output to CC to unspendable - vout.1: CC output for marker - vout.2: CC output for change (if any) - vout.3: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey] - - exchange: - vin.0: normal input - vin.1+: valid CC output - vout.0: vin.1 assetoshis output to CC to unspendable - vout.1: CC output for change (if any) - vout.2: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] - - cancel: - vin.0: normal input - vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx - vin.2: CC marker from selloffer for txfee - vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] - vout.1: vin.2 back to users pubkey - vout.2: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - - fillsell: - vin.0: normal input - vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0] - vin.2+: normal output that satisfies selloffer (*tx.vin[2])->nValue - vout.0: remaining assetoshis -> unspendable - vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any - vout.2: vin.2 value to original pubkey [origpubkey] - vout.3: CC asset for change (if any) - vout.4: CC asset2 for change (if any) 'E' only - vout.5: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - - fillexchange: - vin.0: normal input - vin.1: unspendable.(vout.0 assetoshis from exchange) exchangeTx.vout[0] - vin.2+: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue - vout.0: remaining assetoshis -> unspendable - vout.1: vin.1 assetoshis to signer of vin.2 exchangeTx.vout[0].nValue -> any - vout.2: vin.2 assetoshis2 to original pubkey [origpubkey] - vout.3: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey] -*/ - - - - // tx validation bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn) { - static uint256 zero; - CTxDestination address; - CTransaction vinTx, createTx; - uint256 hashBlock, assetid, assetid2; - int32_t i,starti, numvins, numvouts, preventCCvins, preventCCvouts; - int64_t remaining_price, nValue, assetoshis, outputsDummy,inputs,tmpprice,totalunits,ignore; - std::vector origpubkey, tmporigpubkey, ignorepubkey, vopretNonfungible, vopretNonfungibleDummy; - uint8_t funcid, evalCodeInOpret; - char destaddr[64], origNormalAddr[64], origTokensCCaddr[64], origCCaddrDummy[64]; - char tokensDualEvalUnspendableCCaddr[64], origAssetsCCaddr[64]; - - //return true; - - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - outputsDummy = inputs = 0; - preventCCvins = preventCCvouts = -1; - - if (numvouts == 0) - return eval->Invalid("AssetValidate: no vouts"); - - if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) - return eval->Invalid("AssetValidate: invalid opreturn payload"); - - // non-fungible tokens support: - GetNonfungibleData(assetid, vopretNonfungible); - if (vopretNonfungible.size() > 0) - cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0]; - - // find dual-eval tokens unspendable addr: - GetTokensCCaddress(cpAssets, tokensDualEvalUnspendableCCaddr, GetUnspendable(cpAssets, NULL)); - // this is for marker validation: - GetCCaddress(cpAssets, origAssetsCCaddr, origpubkey); - - // we need this for validating single-eval tokens' vins/vous: - struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - - // find single-eval token user cc addr: - //GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey)); - - //fprintf(stderr,"AssetValidate (%c)\n",funcid); - - if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 ) - return eval->Invalid("cant find asset create txid"); - else if( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2, createTx, hashBlock) == 0 ) - return eval->Invalid("cant find asset2 create txid"); - else if( IsCCInput(tx.vin[0].scriptSig) != 0 ) // vin0 should be normal vin - return eval->Invalid("illegal asset vin0"); - else if( numvouts < 2 ) - return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below - else if( funcid != 'c' ) - { - /* if( funcid == 't' ) - starti = 0; - else - starti = 1; */ - - if( assetid == zero ) - return eval->Invalid("illegal assetid"); - - else if (!AssetCalcAmounts(cpAssets, inputs, outputsDummy/*outputsDummy is calculated incorrectly but not used*/, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs - return false; // returns false if some problems with reading vintxes - } - } - - switch( funcid ) - { - case 'c': // create wont be called to be verified as it has no CC inputs - //vin.0: normal input - //vout.0: issuance assetoshis to CC - //vout.1: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"":""}] - //if (evalCodeInOpret == EVAL_ASSETS) - // return eval->Invalid("unexpected AssetValidate for createasset"); - // return - return eval->Invalid("invalid asset funcid \'c\'"); - break; - case 't': // transfer - //vin.0: normal input - //vin.1 .. vin.n-1: valid CC outputs - //vout.0 to n-2: assetoshis output to CC - //vout.n-2: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid] - //if (inputs == 0) - // return eval->Invalid("no asset inputs for transfer"); - //fprintf(stderr,"transfer preliminarily validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts); - return eval->Invalid("invalid asset funcid \'t\'"); - break; - - case 'b': // buyoffer - //vins.*: normal inputs (bid + change) - //vout.0: amount of bid to unspendable - //vout.1: CC output for marker - //vout.2: normal output for change (if any) - // vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey] - - // as we don't use tokenconvert we should not be here: - return eval->Invalid("invalid asset funcid (b)"); - - if( remaining_price == 0 ) - return eval->Invalid("illegal null amount for buyoffer"); - else if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr,0) == 0 ) // coins to assets unspendable cc addr - return eval->Invalid("invalid vout for buyoffer"); - preventCCvins = 1; - preventCCvouts = 1; - fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cpAssets->unspendableCCaddr); - break; - - case 'o': // cancelbuy - //vin.0: normal input - //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - //vin.2: CC marker from buyoffer for txfee - //vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] - //vout.1: vin.2 back to users pubkey - //vout.2: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['o'] - if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, origCCaddrDummy, origNormalAddr, tx, assetid)) == 0 ) - return(false); - else if( ConstrainVout(tx.vout[0],0, origNormalAddr, nValue) == 0 ) - return eval->Invalid("invalid refund for cancelbuy"); - preventCCvins = 3; - preventCCvouts = 0; - //fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origNormalAddr); - break; - - case 'B': // fillbuy: - //vin.0: normal input - //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - //vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue - //vout.0: remaining amount of bid to unspendable - //vout.1: vin.1 value to signer of vin.2 - //vout.2: vin.2 assetoshis to original pubkey - //vout.3: CC output for assetoshis change (if any) - //vout.4: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey] - preventCCvouts = 4; - - if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) - return(false); - else if( numvouts < 4 ) - return eval->Invalid("not enough vouts for fillbuy"); - else if( tmporigpubkey != origpubkey ) - return eval->Invalid("mismatched origpubkeys for fillbuy"); - else - { - if( nValue != tx.vout[0].nValue + tx.vout[1].nValue ) - return eval->Invalid("locked value doesnt match vout0+1 fillbuy"); - else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change present - { - if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals) - return eval->Invalid("vout2 doesnt go to origpubkey fillbuy"); - else if ( inputs != tx.vout[2].nValue + tx.vout[4].nValue ) - return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy"); - preventCCvouts ++; - } - else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals) - return eval->Invalid("vout2 doesnt match inputs fillbuy"); - else if( ConstrainVout(tx.vout[1], 0, NULL, 0) == 0 ) - return eval->Invalid("vout1 is CC for fillbuy"); - else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to asset cc addr - return eval->Invalid("invalid marker for original pubkey"); - else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) - return eval->Invalid("mismatched remainder for fillbuy"); - else if( remaining_price != 0 ) - { - if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins to asset unspendable cc addr - return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy"); - } - } - //fprintf(stderr,"fillbuy validated\n"); - break; - //case 'e': // selloffer - // break; // disable swaps - case 's': // selloffer - //vin.0: normal input - //vin.1+: valid CC output for sale - //vout.0: vin.1 assetoshis output to CC to unspendable - //vout.1: CC output for marker - //vout.2: CC output for change (if any) - //vout.3: normal output for change (if any) - //'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey] - //'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] - - // as we don't use tokenconvert we should not be here: - return eval->Invalid("invalid asset funcid (s)"); - - preventCCvouts = 2; - if( remaining_price == 0 ) - return eval->Invalid("illegal null remaining_price for selloffer"); - if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("invalid normal vout1 for sellvin"); - if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change presents - { - preventCCvouts++; - if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // tokens to tokens unspendable cc addr. TODO: this in incorrect, should be assets if we got here! - return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); - else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs ) - return eval->Invalid("mismatched vout0+vout2 total for selloffer"); - } - // no cc change: - else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // tokens to tokens unspendable cc addr TODO: this in incorrect, should be assets if got here! - return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); - //fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price); - break; - - case 'x': // cancel sell - //vin.0: normal input - //vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx - //vin.2: CC marker from selloffer for txfee - //vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] - //vout.1: vin.2 back to users pubkey - //vout.2: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - - if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) // NOTE: - return(false); - else if( ConstrainVout(tx.vout[0], 1, origTokensCCaddr, assetoshis) == 0 ) // tokens returning to originator cc addr - return eval->Invalid("invalid vout for cancel"); - preventCCvins = 3; - preventCCvouts = 1; - break; - - case 'S': // fillsell - //vin.0: normal input - //vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0] - //'S'.vin.2+: normal output that satisfies selloffer (*tx.vin[2])->nValue - //vout.0: remaining assetoshis -> unspendable - //vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any - //'S'.vout.2: vin.2 value to original pubkey [origpubkey] - //vout.3: normal output for change (if any) - //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - - if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) - return(false); - else if( numvouts < 4 ) - return eval->Invalid("not enough vouts for fillask"); - else if( tmporigpubkey != origpubkey ) - return eval->Invalid("mismatched origpubkeys for fillask"); - else - { - if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue ) - return eval->Invalid("locked value doesnt match vout0+1 fillask"); - if( ValidateAskRemainder(remaining_price, tx.vout[0].nValue, assetoshis, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) - return eval->Invalid("mismatched remainder for fillask"); - else if( ConstrainVout(tx.vout[1], 1, NULL, 0) == 0 ) // do not check token buyer's cc addr - return eval->Invalid("normal vout1 for fillask"); - else if( ConstrainVout(tx.vout[2], 0, origNormalAddr, 0) == 0 ) // coins to originator normal addr - return eval->Invalid("normal vout1 for fillask"); - else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to originator asset cc addr - return eval->Invalid("invalid marker for original pubkey"); - else if( remaining_price != 0 ) - { - if ( ConstrainVout(tx.vout[0], 1, tokensDualEvalUnspendableCCaddr, 0) == 0 ) - return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell"); - } - } - //fprintf(stderr,"fill validated\n"); - break; - case 'E': // fillexchange - ////////// not implemented yet //////////// - return eval->Invalid("unexpected assets fillexchange funcid"); - break; // disable asset swaps - //vin.0: normal input - //vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0] - //vin.2+: valid CC assetid2 output that satisfies exchange (*tx.vin[2])->nValue - //vout.0: remaining assetoshis -> unspendable - //vout.1: vin.1 assetoshis to signer of vin.2 sellTx.vout[0].nValue -> any - //vout.2: vin.2+ assetoshis2 to original pubkey [origpubkey] - //vout.3: CC output for asset2 change (if any) - //vout.3/4: normal output for change (if any) - //vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey] - - //if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false ) - // eval->Invalid("asset2 inputs != outputs"); - - ////////// not implemented yet //////////// - if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) - return(false); - else if( numvouts < 3 ) - return eval->Invalid("not enough vouts for fillex"); - else if( tmporigpubkey != origpubkey ) - return eval->Invalid("mismatched origpubkeys for fillex"); - else - { - if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue ) - return eval->Invalid("locked value doesnt match vout0+1 fillex"); - else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) - ////////// not implemented yet //////////// - { - if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 ) - return eval->Invalid("vout2 doesnt go to origpubkey fillex"); - else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) - { - fprintf(stderr,"inputs %.8f != %.8f + %.8f\n",(double)inputs/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN); - return eval->Invalid("asset inputs doesnt match vout2+3 fillex"); - } - } - ////////// not implemented yet //////////// - else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 ) - return eval->Invalid("vout2 doesnt match inputs fillex"); - else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 ) - return eval->Invalid("vout1 is CC for fillex"); - fprintf(stderr,"assets vout0 %llu, vin1 %llu, vout2 %llu -> orig, vout1 %llu, total %llu\n",(long long)tx.vout[0].nValue,(long long)assetoshis,(long long)tx.vout[2].nValue,(long long)tx.vout[1].nValue,(long long)totalunits); - if( ValidateSwapRemainder(remaining_price, tx.vout[0].nValue, assetoshis,tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) - return eval->Invalid("mismatched remainder for fillex"); - else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 ) - ////////// not implemented yet //////////// - return eval->Invalid("normal vout1 for fillex"); - else if( remaining_price != 0 ) - { - if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) // TODO: unsure about this, but this is not impl yet anyway - return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex"); - } - } - ////////// not implemented yet //////////// - //fprintf(stderr,"fill validated\n"); - break; - - default: - fprintf(stderr,"illegal assets funcid.(%c)\n",funcid); - return eval->Invalid("unexpected assets funcid"); - //break; - } - - // what does this do? - bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts); // seems we do not need this call as we already checked vouts well - //std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl; - return (bPrevent); + return false; } - - diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index b807f8113..e35ec8c9d 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -26,7 +26,6 @@ #include "main.h" #include "chain.h" #include "core_io.h" -#include "crosschain.h" #define FAUCET2SIZE COIN #define EVAL_FAUCET2 EVAL_FIRSTUSER #ifdef BUILD_ROGUE @@ -642,50 +641,10 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len) } else return(-1); } -#ifdef BUILD_ROGUE -#include "rogue_rpc.cpp" -#include "rogue/cursesd.c" -#include "rogue/vers.c" -#include "rogue/extern.c" -#include "rogue/armor.c" -#include "rogue/chase.c" -#include "rogue/command.c" -#include "rogue/daemon.c" -#include "rogue/daemons.c" -#include "rogue/fight.c" -#include "rogue/init.c" -#include "rogue/io.c" -#include "rogue/list.c" -#include "rogue/mach_dep.c" -#include "rogue/rogue.c" -#include "rogue/xcrypt.c" -#include "rogue/mdport.c" -#include "rogue/misc.c" -#include "rogue/monsters.c" -#include "rogue/move.c" -#include "rogue/new_level.c" -#include "rogue/options.c" -#include "rogue/pack.c" -#include "rogue/passages.c" -#include "rogue/potions.c" -#include "rogue/rings.c" -#include "rogue/rip.c" -#include "rogue/rooms.c" -#include "rogue/save.c" -#include "rogue/scrolls.c" -#include "rogue/state.c" -#include "rogue/sticks.c" -#include "rogue/things.c" -#include "rogue/weapons.c" -#include "rogue/wizard.c" -#elif BUILD_CUSTOMCC +#if BUILD_CUSTOMCC #include "customcc.cpp" -#elif BUILD_GAMESCC -#include "rogue/cursesd.c" -#include "gamescc.cpp" - #else #include "musig.cpp" #include "dilithium.c" diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index e490781b2..c4b3cde79 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -103,6 +103,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) switch ( ecode ) { + /* case EVAL_IMPORTPAYOUT: return ImportPayout(vparams, txTo, nIn); break; @@ -110,7 +111,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) case EVAL_IMPORTCOIN: return ImportCoin(vparams, txTo, nIn); break; - + */ default: return(ProcessCC(cp,this, vparams, txTo, nIn)); break; diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp deleted file mode 100644 index ad1364c11..000000000 --- a/src/cc/gamescc.cpp +++ /dev/null @@ -1,1813 +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 "gamescc.h" -#ifdef BUILD_PRICES -#include "games/prices.c" -#else -#include "games/tetris.c" -#endif - -int32_t GAMEDATA(struct games_player *P,void *ptr); - -uint64_t _games_rngnext(uint64_t initseed) -{ - uint16_t seeds[4]; int32_t i; - seeds[0] = initseed; - seeds[1] = (initseed >> 16); - seeds[2] = (initseed >> 32); - seeds[3] = (initseed >> 48); - seeds[0] = (seeds[0]*GAMES_RNGMULT + GAMES_RNGOFFSET); - seeds[1] = ((seeds[0] ^ seeds[1])*GAMES_RNGMULT + GAMES_RNGOFFSET); - seeds[2] = ((seeds[0] ^ seeds[1] ^ seeds[2])*GAMES_RNGMULT + GAMES_RNGOFFSET); - seeds[3] = ((seeds[0] ^ seeds[1] ^ seeds[2] ^ seeds[3])*GAMES_RNGMULT + GAMES_RNGOFFSET); - return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); -} - -gamesevent games_revendian(gamesevent revx) -{ - int32_t i; gamesevent x = 0; - //fprintf(stderr,"%04x -> ",revx); - for (i=0; iguiflag == 0 ) - { - static uint32_t counter; - if ( rs->ind < rs->numkeys ) - { - ch = rs->keystrokes[rs->ind++]; - if ( 0 ) - { - static FILE *fp; static int32_t counter; - if ( fp == 0 ) - fp = fopen("log","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); - fflush(fp); - counter++; - } - } - return(ch); - } - if ( rs->replaydone != 0 && counter++ < 3 ) - fprintf(stderr,"replay finished but readchar called\n"); - rs->replaydone = (uint32_t)time(NULL); - return(0); - } - if ( rs == 0 || rs->guiflag != 0 ) - { - c = getch(); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } - ch = c; - if (ch == 3) - { - //_quit(); - return(27); - } - } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(ch); -} - -int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) -{ - struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; - rs = (struct games_state *)calloc(1,sizeof(*rs)); - rs->seed = rs->origseed = seed; - rs->keystrokes = keystrokes; - rs->numkeys = num; - rs->sleeptime = sleepmillis * 1000; - if ( player != 0 ) - { - rs->P = *player; - rs->restoring = 1; - if ( rs->P.packsize > MAXPACK ) - rs->P.packsize = MAXPACK; - } - globalR = *rs; - uint32_t starttime = (uint32_t)time(NULL); - ptr = gamesiterate(rs); - if ( 0 ) - { - fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); - sleep(2); - starttime = (uint32_t)time(NULL); - for (i=0; i<10000; i++) - { - memset(rs,0,sizeof(*rs)); - rs->seed = rs->origseed = seed; - rs->keystrokes = keystrokes; - rs->numkeys = num; - rs->sleeptime = 0; - gamesiterate(rs); - } - fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL)-starttime); - sleep(3); - } - // extract playerdata - - /*if ( (fp= fopen("checkfile","wb")) != 0 ) - { - //save_file(rs,fp,0); - if ( newdata != 0 && rs->playersize > 0 ) - memcpy(newdata,rs->playerdata,rs->playersize); - }*/ - if ( ptr != 0 ) - { - // extract data from ptr - if ( GAMEDATA(&rs->P,ptr) < 0 ) - memset(&rs->P,0,sizeof(rs->P)); - else - { - rs->playersize = sizeof(rs->P); - if ( newdata != 0 ) - memcpy(newdata,&rs->P,rs->playersize); - } - free(ptr); - } - n = rs->playersize; - //fprintf(stderr,"gold.%d\n",rs->P.gold); sleep(3); - free(rs); - return(n); -} - -#ifndef STANDALONE -#ifdef BUILD_PRICES -#include "games/prices.cpp" -#else -#include "games/tetris.cpp" -#endif - -void GAMEJSON(UniValue &obj,struct games_player *P); - -/* -./c cclib rng 17 \"[%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,250]\" -{ - "playerid": 250, - "seed": 1398876319979341887, - "rng": 14565767519458298868, - "lastrng": 15075236803740723044, - "maxrngs": 10000, - "result": "success" -} - - ./c cclib rngnext 17 \"[14565767519458298868]\" - { - "seed": 14565767519458297856, - "rng": 4253087318999719449, - "result": "success" - } - - The idea is for a game to start with a near future blockhash, so the lobby gets players signed up until just prior to the designated height. then that blockhash can be used to create a stream of rngs. - - the same initial rng can be used for all players, if the identical starting condition is required. up to 255 different initial rng can be derived from a single blockhash. (Actually any number is possible, for simplicity rng rpc limits to 255). - - you will notice maxrngs and lastrng, the lastrng is the rng value that will happen after maxrng iterations of calling rngnext with the current rng. This allows making time based multiplayer games where all the nodes can validate all the other nodes rng, even without realtime synchronization of all user input events. - - Every time period, all players would set their rng value to the lastrng value. The only thing to be careful of is it not exceed the maxrng calls to rngnext in a single time period. otherwise the same set of rng numbers will be repeated. - - events rpc is called after each user event and broadcasts to the network the tuple (gametxid, pk, eventid, payload). This allows the network to verify realtime user events from a specific pk/gametxid and also to make sure no user events were changed. In the event the events were changed, then the guilty pk will be blacklisted. If no realtime events, then the guilty pk would be penalized. - - ./c cclib events 17 \"[%226c%22,%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,0]\" - ./c cclib events 17 \"[%226d%22,%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,1]\" -*/ - - -CScript games_newgameopret(int64_t buyin,int32_t maxplayers) -{ - CScript opret; uint8_t evalcode = EVAL_GAMES; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'G' << buyin << maxplayers); - return(opret); -} - -uint8_t games_newgameopreturndecode(int64_t &buyin,int32_t &maxplayers,CScript scriptPubKey) -{ - std::vector vopret; uint8_t e,f; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> buyin; ss >> maxplayers) != 0 && e == EVAL_GAMES && f == 'G' ) - { - return(f); - } - return(0); -} - -CScript games_registeropret(uint256 gametxid,uint256 playertxid) -{ - CScript opret; uint8_t evalcode = EVAL_GAMES; - //fprintf(stderr,"opret.(%s %s).R\n",gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << gametxid << playertxid); - return(opret); -} - -CScript games_keystrokesopret(uint256 gametxid,uint256 batontxid,CPubKey pk,std::vectorkeystrokes) -{ - CScript opret; uint8_t evalcode = EVAL_GAMES; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'K' << gametxid << batontxid << pk << keystrokes); - return(opret); -} - -uint8_t games_keystrokesopretdecode(uint256 &gametxid,uint256 &batontxid,CPubKey &pk,std::vector &keystrokes,CScript scriptPubKey) -{ - std::vector vopret; uint8_t e,f; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> batontxid; ss >> pk; ss >> keystrokes) != 0 && e == EVAL_GAMES && f == 'K' ) - { - return(f); - } - return(0); -} - -uint8_t games_registeropretdecode(uint256 &gametxid,uint256 &tokenid,uint256 &playertxid,CScript scriptPubKey) -{ - std::string name, description; std::vector vorigPubkey; - std::vector> oprets; - std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; - uint8_t e, f,*script; std::vector voutPubkeys; - tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,oprets)) == 'c' ) - { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - vopret = vopretNonfungible; - } - else if ( script[1] != 'R' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, oprets)) != 0 ) - { - GetOpretBlob(oprets, OPRETID_ROGUEGAMEDATA, vopretDummy); // blob from non-creation tx opret - vopret = vopretDummy; - } - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> playertxid) != 0 && e == EVAL_GAMES && f == 'R' ) - { - return(f); - } - //fprintf(stderr,"e.%d f.%c game.%s playertxid.%s\n",e,f,gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - return(0); -} - -CScript games_finishopret(uint8_t funcid,uint256 gametxid,int32_t regslot,CPubKey pk,std::vectorplayerdata,std::string pname) -{ - CScript opret; uint8_t evalcode = EVAL_GAMES; std::string symbol(SMART_CHAIN_SYMBOL); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << gametxid << symbol << pname << regslot << pk << playerdata ); - return(opret); -} - -uint8_t games_finishopretdecode(uint256 &gametxid, uint256 &tokenid, int32_t ®slot, CPubKey &pk, std::vector &playerdata, std::string &symbol, std::string &pname,CScript scriptPubKey) -{ - std::string name, description; std::vector vorigPubkey; - std::vector> oprets, opretsDummy; - std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; - uint8_t e, f,*script; std::vector voutPubkeys; - tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description, oprets)) == 'c' ) - { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - vopret = vopretNonfungible; - } - else if ( script[1] != 'H' && script[1] != 'Q' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, opretsDummy)) != 0 ) - { - //fprintf(stderr,"decode opret %c tokenid.%s\n",script[1],tokenid.GetHex().c_str()); - GetNonfungibleData(tokenid, vopretNonfungible); //load nonfungible data from the 'tokenbase' tx - vopret = vopretNonfungible; - } - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> gametxid; ss >> symbol; ss >> pname; ss >> regslot; ss >> pk; ss >> playerdata) != 0 && e == EVAL_GAMES && (f == 'H' || f == 'Q') ) - { - return(f); - } - fprintf(stderr,"SKIP obsolete: e.%d f.%c game.%s regslot.%d psize.%d\n",e,f,gametxid.GetHex().c_str(),regslot,(int32_t)playerdata.size()); - return(0); -} - -CScript games_eventopret(uint32_t timestamp,CPubKey pk,std::vector sig,std::vector payload) -{ - CScript opret; uint8_t evalcode = EVAL_GAMES; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'E' << timestamp << pk << sig << payload); - return(opret); -} - -uint8_t games_eventdecode(uint32_t ×tamp,CPubKey &pk,std::vector &sig,std::vector &payload,std::vector vopret) -{ - uint8_t e,f; - timestamp = 0; - if ( vopret.size() > 6 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> timestamp; ss >> pk; ss >> sig; ss >> payload) != 0 && e == EVAL_GAMES ) - { - return(f); - } - fprintf(stderr,"ERROR e.%d f.%d pk.%d sig.%d payload.%d\n",e,f,(int32_t)pk.size(),(int32_t)sig.size(),(int32_t)payload.size()); - return(0); -} - -UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag) -{ - CTransaction tx; - if ( rawtx.size() > 0 ) - { - result.push_back(Pair("hex",rawtx)); - if ( DecodeHexTx(tx,rawtx) != 0 ) - { - if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) - RelayTransaction(tx); - result.push_back(Pair("txid",tx.GetHash().ToString())); - result.push_back(Pair("result","success")); - } else result.push_back(Pair("error","decode hex")); - } else result.push_back(Pair("error","couldnt finalize CCtx")); - return(result); -} - -UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); int32_t n; uint64_t seed; - if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) - { - seed = jdouble(jitem(params,0),0); - result.push_back(Pair("seed",seed)); - seed = _games_rngnext(seed); - result.push_back(Pair("rng",seed)); - result.push_back(Pair("result","success")); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","not enough params")); - } - return(result); -} - -UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); int32_t i,n,playerid=0; uint64_t seed=0,initseed; bits256 hash; - if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) ) - { - hash = jbits256(jitem(params,0),0); - if ( n == 2 ) - { - playerid = juint(jitem(params,1),0); - if ( playerid >= 0xff ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","playerid too big")); - return(result); - } - } - playerid++; - for (i=0; i<8; i++) - { - if ( ((1 << i) & playerid) != 0 ) - seed ^= (uint64_t)hash.uints[i] << ((i&1)*32); - } - initseed = seed; - seed = _games_rngnext(initseed); - result.push_back(Pair("playerid",(int64_t)(playerid - 1))); - result.push_back(Pair("seed",initseed)); - result.push_back(Pair("rng",seed)); - for (i=0; i &sig,std::vector payload,CPubKey pk) -{ - static secp256k1_context *ctx; - size_t siglen = 74; secp256k1_pubkey pubkey; secp256k1_ecdsa_signature signature; int32_t len,verifyflag = 1,retval=-100; uint8_t privkey[32]; uint256 hash; uint32_t t; - if ( ctx == 0 ) - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - if ( ctx != 0 ) - { - Myprivkey(privkey); - len = payload.size(); - payload.resize(len + 4); - if ( timestamp == 0 ) - { - timestamp = (uint32_t)time(NULL); - verifyflag = 0; - } - t = timestamp; - payload[len++] = t, t >>= 8; - payload[len++] = t, t >>= 8; - payload[len++] = t, t >>= 8; - payload[len++] = t; - vcalc_sha256(0,(uint8_t *)&hash,&payload[0],len); - if ( verifyflag == 0 ) - { - if ( secp256k1_ecdsa_sign(ctx,&signature,(uint8_t *)&hash,privkey,NULL,NULL) > 0 ) - { - sig.resize(siglen); - if ( secp256k1_ecdsa_signature_serialize_der(ctx,&sig[0],&siglen,&signature) > 0 ) - { - if ( siglen != sig.size() ) - sig.resize(siglen); - retval = 0; - } else retval = -3; - } else retval = -2; - } - else - { - if ( secp256k1_ec_pubkey_parse(ctx,&pubkey,pk.begin(),33) > 0 ) - { - if ( secp256k1_ecdsa_signature_parse_der(ctx,&signature,&sig[0],sig.size()) > 0 ) - { - if ( secp256k1_ecdsa_verify(ctx,&signature,(uint8_t *)&hash,&pubkey) > 0 ) - retval = 0; - else retval = -4; - } else retval = -3; - } else retval = -2; - } - } else retval = -1; - memset(privkey,0,sizeof(privkey)); - return(retval); -} - -int32_t games_event(uint32_t timestamp,uint256 gametxid,int32_t eventid,std::vector payload) -{ - std::vector sig,vopret; CPubKey mypk; uint32_t x; int32_t i,len = payload.size(); - payload.resize(len + 4 + 32); - for (i=0; i<32; i++) - payload[len++] = ((uint8_t *)&gametxid)[i]; - x = eventid; - payload[len++] = x, x >>= 8; - payload[len++] = x, x >>= 8; - payload[len++] = x, x >>= 8; - payload[len++] = x; - mypk = pubkey2pk(Mypubkey()); - if ( games_eventsign(timestamp,sig,payload,mypk) == 0 ) - { - GetOpReturnData(games_eventopret(timestamp,mypk,sig,payload),vopret); - games_payloadrecv(mypk,timestamp,payload); - hush_sendmessage(4,8,"events",vopret); - return(0); - } - fprintf(stderr,"games_eventsign error\n"); - return(-1); -} - -UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - static uint256 lastgametxid; static uint32_t numevents; - UniValue result(UniValue::VOBJ); std::vector payload; int32_t len,i,n; uint32_t x; CPubKey mypk; char str[67]; uint32_t eventid,timestamp = 0; uint256 gametxid; - if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 1 && n <= 3 ) - { - mypk = pubkey2pk(Mypubkey()); - if ( payments_parsehexdata(payload,jitem(params,0),0) == 0 ) - { - if ( n >= 2 ) - gametxid = juint256(jitem(params,1)); - else gametxid = zeroid; - if ( gametxid != lastgametxid ) - { - lastgametxid = gametxid; - numevents = 1; - eventid = 0; - } - if ( n == 3 ) - { - eventid = juint(jitem(params,2),0); - if ( numevents <= eventid ) - numevents = eventid+1; - } else eventid = numevents++; - if ( games_event(timestamp,gametxid,eventid,payload) == 0 ) - { - result.push_back(Pair("gametxid",gametxid.GetHex())); - result.push_back(Pair("eventid",(int64_t)eventid)); - result.push_back(Pair("payload",jstr(jitem(params,0),0))); - result.push_back(Pair("timestamp",(int64_t)timestamp)); - result.push_back(Pair("result","success")); - result.push_back(Pair("pubkey33",pubkey33_str(str,(uint8_t *)&mypk))); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","signing ereror")); - } - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt parsehexdata")); - } - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","not enough params")); - } - return(result); -} - -void hush_netevent(std::vector message) -{ - int32_t i,retval,lag,lagerr=0; uint32_t timestamp,now; CPubKey pk; std::vector sig,payload; char str[67]; - if ( games_eventdecode(timestamp,pk,sig,payload,message) == 'E' ) - { - now = (uint32_t)time(NULL); - lag = now - timestamp; - if ( lag < -3 || lag > 3 ) - { - fprintf(stderr,"LAG ERROR "); - lagerr = lag; - } - if ( (retval= games_eventsign(timestamp,sig,payload,pk)) != 0 ) - fprintf(stderr,"SIG ERROR.%d ",retval); - else if ( lagerr == 0 ) - { - if ( games_payloadrecv(pk,timestamp,payload) == 0 ) // first time this is seen - { - if ( (rand() % 10) == 0 ) - { - //fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); - hush_sendmessage(2,2,"events",message); - } - } - } - //for (i=0; i 0 ) - result.push_back(Pair("maxplayers",maxplayers)); - if ( buyin >= 0 ) - { - result.push_back(Pair("buyin",ValueFromAmount(buyin))); - if ( buyin == 0 ) - result.push_back(Pair("type","newbie")); - else result.push_back(Pair("type","buyin")); - } -} - -int32_t games_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) -{ - uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey gamespk; uint64_t txfee = 10000; - buyin = maxplayers = 0; - if ( (txid == zeroid || myGetTransaction(txid,tx,hashBlock) != 0) && (numvouts= tx.vout.size()) > 1 ) - { - if ( txid != zeroid ) - gameheight = hush_blockheight(hashBlock); - else - { - txid = tx.GetHash(); - //fprintf(stderr,"set txid %s %llu\n",txid.GetHex().c_str(),(long long)CCgettxout(txid,0,1)); - } - if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1,0) == txfee) ) - { - if ( games_newgameopreturndecode(buyin,maxplayers,tx.vout[numvouts-1].scriptPubKey) == 'G' ) - { - if ( maxplayers < 1 || maxplayers > GAMES_MAXPLAYERS || buyin < 0 ) - return(-6); - if ( numvouts > 2*maxplayers+1 ) - { - for (i=0; i= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - break; - } - txid = spenttxid; - vout = 0; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - if ( spentvini != 0 ) - break; - if ( n++ > GAMES_MAXITERATIONS ) - break; - } - if ( txid != zeroid ) - { - if ( myGetTransaction(txid,tx,hashBlock) != 0 ) - { - if ( (pindex= hush_blockindex(hashBlock)) != 0 ) - { - if ( pindex->GetHeight() <= gameht+GAMES_MAXKEYSTROKESGAP ) - alive++; - } - } - } - } - } - else if ( registration_open != 0 ) - openslots++; - } - //fprintf(stderr,"numalive.%d openslots.%d\n",alive,openslots); - return(alive); -} - -UniValue games_playerobj(std::vector playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) -{ - int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct games_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - datastr = (char *)malloc(playerdata.size()*2+1); - for (i=0; i= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - break; - } - txid = spenttxid; - vout = 0; - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) - { - for (i=0; i GAMES_MAXITERATIONS ) - break; - } - obj.push_back(Pair("gametxid",gametxid.GetHex())); - if ( txid != playertxid ) - obj.push_back(Pair("batontxid",txid.GetHex())); - obj.push_back(Pair("playertxid",playertxid.GetHex())); - if ( tokenid != zeroid ) - obj.push_back(Pair("tokenid",tokenid.GetHex())); - else obj.push_back(Pair("tokenid",playertxid.GetHex())); - if ( datastr != 0 ) - { - obj.push_back(Pair("data",datastr)); - free(datastr); - } - obj.push_back(Pair("pack",a)); - GAMEPLAYERJSON(obj,&P); - obj.push_back(Pair("chain",symbol)); - obj.push_back(Pair("pname",pname)); - return(obj); -} - -int32_t games_iterateplayer(uint256 ®istertxid,uint256 firsttxid,int32_t firstvout,uint256 lasttxid) // retrace playertxid vins to reach highlander <- this verifies player is valid and rogue_playerdataspend makes sure it can only be used once -{ - uint256 spenttxid,txid = firsttxid; int32_t spentvini,n,vout = firstvout; - registertxid = zeroid; - if ( vout < 0 ) - return(-1); - n = 0; - while ( (spentvini= myIsutxo_spent(spenttxid,txid,vout)) == 0 ) - { - txid = spenttxid; - vout = spentvini; - if ( registertxid == zeroid ) - registertxid = txid; - if ( ++n >= GAMES_MAXITERATIONS ) - { - fprintf(stderr,"games_iterateplayer n.%d, seems something is wrong\n",n); - return(-2); - } - } - if ( txid == lasttxid ) - return(0); - else - { - fprintf(stderr,"firsttxid.%s/v%d -> %s != last.%s\n",firsttxid.ToString().c_str(),firstvout,txid.ToString().c_str(),lasttxid.ToString().c_str()); - return(-1); - } -} - -int32_t games_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint256 &tokenid,CPubKey &pk,std::vector &playerdata,std::string &symbol,std::string &pname,uint256 playertxid) -{ - uint256 origplayertxid,hashBlock,gametxid,registertxid; CTransaction gametx,playertx,highlandertx; std::vector vopret; uint8_t *script,e,f; int32_t i,regslot,gameheight,numvouts,maxplayers; int64_t buyin; - if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 && (numvouts= playertx.vout.size()) > 0 ) - { - if ( (f= games_finishopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,playertx.vout[numvouts-1].scriptPubKey)) == 'H' || f == 'Q' ) - { - origplayergame = gametxid; - if ( tokenid != zeroid ) - { - playertxid = tokenid; - if ( myGetTransaction(playertxid,playertx,hashBlock) == 0 || (numvouts= playertx.vout.size()) <= 0 ) - { - fprintf(stderr,"couldnt get tokenid.%s\n",playertxid.GetHex().c_str()); - return(-2); - } - } - if ( games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) - { - //fprintf(stderr,"playertxid.%s got vin.%s/v%d gametxid.%s iterate.%d\n",playertxid.ToString().c_str(),playertx.vin[1].prevout.hash.ToString().c_str(),(int32_t)playertx.vin[1].prevout.n-maxplayers,gametxid.ToString().c_str(),games_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid)); - if ( (tokenid != zeroid || playertx.vin[1].prevout.hash == gametxid) && games_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid) == 0 ) - { - // if registertxid has vin from pk, it can be used - return(0); - } else fprintf(stderr,"hash mismatch or illegal gametxid\n"); - } else fprintf(stderr,"invalid game %s\n",gametxid.GetHex().c_str()); - } //else fprintf(stderr,"invalid player funcid.%c\n",f); - } else fprintf(stderr,"couldnt get playertxid.%s\n",playertxid.GetHex().c_str()); - return(-1); -} - -int32_t games_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx,char *mygamesaddr) -{ - int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; char destaddr[64]; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); - if ( strcmp(mygamesaddr,destaddr) == 0 ) - return(1); - //else fprintf(stderr,"myaddr.%s vs %s\n",mygamesaddr,destaddr); - } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"vout %d is unspent\n",vout); - } - return(0); -} - -int64_t games_buyins(uint256 gametxid,int32_t maxplayers) -{ - int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - if ( spenttx.vout[0].nValue > GAMES_REGISTRATIONSIZE ) - buyins += (spenttx.vout[0].nValue - GAMES_REGISTRATIONSIZE); - } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"vout %d is unspent\n",vout); - } - return(buyins); -} - -uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr) -{ - CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; - if ( myGetTransaction(gametxid,tx,hashBlock) != 0 && (pindex= hush_blockindex(hashBlock)) != 0 ) - { - ht = pindex->GetHeight(); - delay = GAMES_REGISTRATION * (maxplayers > 1); - obj.push_back(Pair("height",ht)); - obj.push_back(Pair("start",ht+delay)); - if ( hush_nextheight() > ht+delay ) - { - if ( (pindex= hush_chainactive(ht+delay)) != 0 ) - { - hashBlock = pindex->GetBlockHash(); - obj.push_back(Pair("starthash",hashBlock.ToString())); - memcpy(&seed,&hashBlock,sizeof(seed)); - seed &= (1LL << 62) - 1; - obj.push_back(Pair("seed",(int64_t)seed)); - if ( games_iamregistered(maxplayers,gametxid,tx,mygamesaddr) > 0 ) - sprintf(cmd,"cc/%s %llu %s",GAMENAME,(long long)seed,gametxid.ToString().c_str()); - else sprintf(cmd,"./hush-cli -ac_name=%s cclib register %d \"[%%22%s%%22]\"",SMART_CHAIN_SYMBOL,EVAL_GAMES,gametxid.ToString().c_str()); - obj.push_back(Pair("run",cmd)); - } - } - obj.push_back(Pair("alive",games_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); - obj.push_back(Pair("openslots",openslots)); - obj.push_back(Pair("numplayers",numplayers)); - obj.push_back(Pair("buyins",ValueFromAmount(games_buyins(gametxid,maxplayers)))); - } - obj.push_back(Pair("maxplayers",maxplayers)); - obj.push_back(Pair("buyin",ValueFromAmount(buyin))); - return(seed); -} - -UniValue games_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); std::vector playerdata; uint256 playertxid,tokenid,origplayergame;int32_t n; CPubKey pk; bits256 t; std::string symbol,pname; - result.push_back(Pair("result","success")); - games_univalue(result,"playerinfo",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - playertxid = juint256(jitem(params,0)); - if ( games_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) - return(cclib_error(result,"invalid playerdata")); - result.push_back(Pair("player",games_playerobj(playerdata,playertxid,tokenid,symbol,pname,origplayergame))); - } else return(cclib_error(result,"no playertxid")); - return(result); - } else return(cclib_error(result,"couldnt reparse params")); -} - -void disp_gamesplayerdata(std::vector playerdata) -{ - struct games_player P; int32_t i; char packitemstr[512],str[512]; - if ( playerdata.size() > 0 ) - { - for (i=0; i maxplayers+1 ) - { - r = rand() % maxplayers; - for (j=0; j &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) -{ - int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64]; gamesevent *keystrokes=0; - batonvalue = numkeys = numplayers = batonht = 0; - playertxid = batontxid = zeroid; - if ( keystrokesp != 0 ) - *keystrokesp = 0; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - numplayers++; - Getscriptaddress(ccaddr,spenttx.vout[0].scriptPubKey); - if ( strcmp(destaddr,ccaddr) == 0 ) - { - matches++; - regslot = i; - matchtx = spenttx; - } //else fprintf(stderr,"%d+1 doesnt match %s vs %s\n",i,ccaddr,destaddr); - } //else fprintf(stderr,"%d+1 couldnt find spenttx.%s\n",i,spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"%d+1 unspent\n",i); - } - if ( matches == 1 ) - { - numvouts = matchtx.vout.size(); -//fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); - if ( games_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) - { - //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - if ( tokenid != zeroid ) - active = tokenid; - else active = playertxid; - if ( active == zeroid || games_playerdata(cp,origplayergame,tid,pk,playerdata,symbol,pname,active) == 0 ) - { - txid = matchtx.GetHash(); - //fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); - n = 0; - while ( CCgettxout(txid,0,1,0) < 0 ) - { - spenttxid = zeroid; - spentvini = -1; - if ( (spentvini= myIsutxo_spent(spenttxid,txid,0)) >= 0 ) - txid = spenttxid; - else - { - if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,0) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - return(-2); - } - } - txid = spenttxid; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - if ( spentvini != 0 ) // game is over? - { - //fprintf(stderr,"gameisover n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - return(0); - } - if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) - { - uint256 g,b; CPubKey p; std::vector k; - if ( games_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) - { - //fprintf(stderr,"update keystrokes.%p[%d]\n",keystrokes,numkeys); - keystrokes = (gamesevent *)realloc(keystrokes,(int32_t)(sizeof(*keystrokes)*numkeys + k.size())); - for (i=0; i= GAMES_MAXITERATIONS ) - { - fprintf(stderr,"games_findbaton n.%d, seems something is wrong\n",n); - return(-5); - } - } - //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); - batontxid = txid; - batonvout = 0; // not vini - // how to detect timeout, bailedout, highlander - hashBlock = zeroid; - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 ) - { - if ( hashBlock == zeroid ) - batonht = hush_nextheight(); - else if ( (pindex= hush_blockindex(hashBlock)) == 0 ) - return(-4); - else batonht = pindex->GetHeight(); - batonvalue = batontx.vout[0].nValue; - //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); - return(0); - } else fprintf(stderr,"couldnt find baton\n"); - } else fprintf(stderr,"error with playerdata\n"); - } else fprintf(stderr,"findbaton opret error\n"); - } - return(-1); -} - -void games_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gametxid,CTransaction gametx,int32_t vout,int32_t maxplayers,char *mygamesaddr) -{ - // identify if bailout or quit or timed out - uint256 batontxid,spenttxid,gtxid,ptxid,tokenid,hashBlock,playertxid; CTransaction spenttx,batontx; int32_t numplayers,regslot,numkeys,batonvout,batonht,retval; int64_t batonvalue; std::vector playerdata; char destaddr[64]; std::string symbol,pname; - destaddr[0] = 0; - if ( myIsutxo_spent(spenttxid,gametxid,vout) >= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); - } - obj.push_back(Pair("slot",(int64_t)vout-1)); - if ( (retval= games_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,destaddr,numplayers,symbol,pname)) == 0 ) - { - if ( CCgettxout(gametxid,maxplayers+vout,1,0) == 10000 ) - { - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 1 ) - { - if ( games_registeropretdecode(gtxid,tokenid,ptxid,batontx.vout[batontx.vout.size()-1].scriptPubKey) == 'R' && ptxid == playertxid && gtxid == gametxid ) - obj.push_back(Pair("status","registered")); - else obj.push_back(Pair("status","alive")); - } else obj.push_back(Pair("status","error")); - } else obj.push_back(Pair("status","finished")); - obj.push_back(Pair("baton",batontxid.ToString())); - obj.push_back(Pair("tokenid",tokenid.ToString())); - obj.push_back(Pair("batonaddr",destaddr)); - obj.push_back(Pair("ismine",strcmp(mygamesaddr,destaddr)==0)); - obj.push_back(Pair("batonvout",(int64_t)batonvout)); - obj.push_back(Pair("batonvalue",ValueFromAmount(batonvalue))); - obj.push_back(Pair("batonht",(int64_t)batonht)); - if ( playerdata.size() > 0 ) - obj.push_back(Pair("player",games_playerobj(playerdata,playertxid,tokenid,symbol,pname,gametxid))); - } else fprintf(stderr,"findbaton err.%d\n",retval); -} - -UniValue games_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey gamespk,mypk; char *jsonstr; uint64_t inputsum,change,required,buyin=0; int32_t i,n,maxplayers = 1; - if ( txfee == 0 ) - txfee = 10000; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - maxplayers = juint(jitem(params,0),0); - if ( n > 1 ) - buyin = jdouble(jitem(params,1),0) * COIN + 0.0000000049; - } - } - if ( maxplayers < 1 || maxplayers > GAMES_MAXPLAYERS ) - return(cclib_error(result,"illegal maxplayers")); - mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); - games_univalue(result,"newgame",maxplayers,buyin); - required = (3*txfee + maxplayers*(GAMES_REGISTRATIONSIZE+txfee)); - if ( (inputsum= AddCClibInputs(cp,mtx,gamespk,required,16,cp->unspendableCCaddr,1)) >= required ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gamespk)); - for (i=0; ievalcode,GAMES_REGISTRATIONSIZE,gamespk,gamespk)); - for (i=0; ievalcode,txfee,gamespk,gamespk)); - if ( (change= inputsum - required) >= txfee ) - mtx.vout.push_back(MakeCC1vout(cp->evalcode,change,gamespk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,games_newgameopret(buyin,maxplayers)); - return(games_rawtxresult(result,rawtx,1)); - } - else return(cclib_error(result,"illegal maxplayers")); - return(result); -} - -UniValue games_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 txid,hashBlock; CTransaction tx; int32_t openslots,maxplayers,numplayers,gameheight,nextheight,vout,numvouts; CPubKey gamespk; char coinaddr[64]; - std::vector > unspentOutputs; - gamespk = GetUnspendable(cp,0); - GetCCaddress(cp,coinaddr,gamespk); - SetCCunspents(unspentOutputs,coinaddr,true); - nextheight = hush_nextheight(); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - if ( it->second.satoshis != txfee || vout != 0 ) // reject any that are not highlander markers - continue; - if ( games_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,1) == 0 && nextheight <= gameheight+GAMES_MAXKEYSTROKESGAP ) - { - games_playersalive(openslots,numplayers,txid,maxplayers,gameheight,tx); - if ( openslots > 0 ) - a.push_back(txid.GetHex()); - } - } - result.push_back(Pair("result","success")); - games_univalue(result,"pending",-1,-1); - result.push_back(Pair("pending",a)); - result.push_back(Pair("numpending",(int64_t)a.size())); - return(result); -} - -UniValue games_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char myaddr[64],str[64]; CPubKey mypk,gamespk; - result.push_back(Pair("name","games")); - result.push_back(Pair("method","info")); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - txid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",txid.GetHex())); - if ( games_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,0) == 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("gameheight",(int64_t)gameheight)); - mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,myaddr,gamespk,mypk); - seed = games_gamefields(result,maxplayers,buyin,txid,myaddr); - result.push_back(Pair("seed",(int64_t)seed)); - for (i=0; i GAMES_REGISTRATIONSIZE 1of2 registration baton from creategame - // vin1 -> optional nonfungible character vout @ - // vin2 -> original creation TCBOO playerdata used - // vin3+ -> buyin - // vout0 -> keystrokes/completion baton - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - UniValue result(UniValue::VOBJ); char destaddr[64],coinaddr[64]; uint256 tokenid,gametxid,origplayergame,playertxid,hashBlock; int32_t err,maxplayers,gameheight,n,numvouts,vout=1; int64_t inputsum,buyin,CCchange=0; CPubKey pk,mypk,gamespk,burnpk; CTransaction tx,playertx; std::vector playerdata; std::string rawtx,symbol,pname; bits256 t; - - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - burnpk = pubkey2pk(ParseHex(CC_BURNPUBKEY)); - gamespk = GetUnspendable(cp,0); - games_univalue(result,"register",-1,-1); - playertxid = tokenid = zeroid; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - if ( (err= games_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1)) == 0 ) - { - if ( n > 1 ) - { - playertxid = juint256(jitem(params,1)); - if ( games_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) - return(cclib_error(result,"couldnt extract valid playerdata")); - if ( tokenid != zeroid ) // if it is tokentransfer this will be 0 - vout = 1; - } - if ( hush_nextheight() > gameheight + GAMES_MAXKEYSTROKESGAP ) - return(cclib_error(result,"didnt register in time, GAMES_MAXKEYSTROKESGAP")); - games_univalue(result,0,maxplayers,buyin); - GetCCaddress1of2(cp,coinaddr,gamespk,mypk); - if ( games_iamregistered(maxplayers,gametxid,tx,coinaddr) > 0 ) - return(cclib_error(result,"already registered")); - if ( (inputsum= games_registrationbaton(mtx,gametxid,tx,maxplayers)) != GAMES_REGISTRATIONSIZE ) - return(cclib_error(result,"couldnt find available registration baton")); - else if ( playertxid != zeroid && games_playerdataspend(mtx,playertxid,vout,origplayergame) < 0 ) - return(cclib_error(result,"couldnt find playerdata to spend")); - else if ( buyin > 0 && AddNormalinputs(mtx,mypk,buyin,64) < buyin ) - return(cclib_error(result,"couldnt find enough normal funds for buyin")); - if ( tokenid != zeroid ) - { - mtx.vin.push_back(CTxIn(tokenid,0)); // spending cc marker as token is burned - char unspendableTokenAddr[64]; uint8_t tokenpriv[32]; struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - CPubKey unspPk = GetUnspendable(cpTokens, tokenpriv); - GetCCaddress(cpTokens, unspendableTokenAddr, unspPk); - CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr); - } - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,buyin + inputsum - txfee,gamespk,mypk)); - GetCCaddress1of2(cp,destaddr,gamespk,gamespk); - CCaddr1of2set(cp,gamespk,gamespk,cp->CCpriv,destaddr); - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode, 1, burnpk)); - - uint8_t e, funcid; uint256 tid; std::vector voutPubkeys, voutPubkeysEmpty; int32_t didtx = 0; - CScript opretRegister = games_registeropret(gametxid, playertxid); - if ( playertxid != zeroid ) - { - voutPubkeysEmpty.push_back(burnpk); - if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 ) - { - std::vector> oprets; - if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, oprets)) != 0) - { // if token in the opret - didtx = 1; - if ( funcid == 'c' ) - tid = tokenid == zeroid ? playertxid : tokenid; - vscript_t vopretRegister; - GetOpReturnData(opretRegister, vopretRegister); - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, - EncodeTokenOpRet(tid, voutPubkeysEmpty /*=never spent*/, std::make_pair(OPRETID_ROGUEGAMEDATA, vopretRegister))); - } - } - } - if ( didtx == 0 ) - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, opretRegister); - - return(games_rawtxresult(result,rawtx,1)); - } else return(cclib_error(result,"invalid gametxid")); - } else return(cclib_error(result,"no gametxid")); - } else return(cclib_error(result,"couldnt reparse params")); -} - -UniValue games_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - // vin0 -> baton from registration or previous keystrokes - // vout0 -> new baton - // opret -> user input chars - // being killed should auto broadcast (possible to be suppressed?) - // respawn to be prevented by including timestamps - int32_t nextheight = hush_nextheight(); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); - UniValue result(UniValue::VOBJ); CPubKey gamespk,mypk; uint256 gametxid,playertxid,batontxid; int64_t batonvalue,buyin; std::vector keystrokes,playerdata; int32_t numplayers,regslot,numkeys,batonht,batonvout,n,elapsed,gameheight,maxplayers; CTransaction tx; CTxOut txout; char *keystrokestr,destaddr[64]; std::string rawtx,symbol,pname; bits256 t; uint8_t mypriv[32]; - // if ( txfee == 0 ) - txfee = 1000; // smaller than normal on purpose - games_univalue(result,"keystrokes",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - result.push_back(Pair("keystrokes",keystrokestr)); - keystrokes = ParseHex(keystrokestr); - mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,destaddr,gamespk,mypk); - if ( games_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1) == 0 ) - { - if ( games_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,tx,maxplayers,destaddr,numplayers,symbol,pname) == 0 ) - { - result.push_back(Pair("batontxid",batontxid.GetHex())); - result.push_back(Pair("playertxid",playertxid.GetHex())); - if ( maxplayers == 1 || nextheight <= batonht+GAMES_MAXKEYSTROKESGAP ) - { - mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript())); //this validates user if pk - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,batonvalue-txfee,gamespk,mypk)); - Myprivkey(mypriv); - CCaddr1of2set(cp,gamespk,mypk,mypriv,destaddr); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,games_keystrokesopret(gametxid,batontxid,mypk,keystrokes)); - //fprintf(stderr,"KEYSTROKES.(%s)\n",rawtx.c_str()); - memset(mypriv,0,sizeof(mypriv)); - return(games_rawtxresult(result,rawtx,1)); - } else return(cclib_error(result,"keystrokes tx was too late")); - } else return(cclib_error(result,"couldnt find batontxid")); - } else return(cclib_error(result,"invalid gametxid")); - } else return(cclib_error(result,"couldnt reparse params")); -} - -gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) -{ - CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64]; gamesevent *keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; - gamespk = GetUnspendable(cp,0); - *numkeysp = 0; - seed = 0; - num = numkeys = 0; - playertxid = zeroid; - str[0] = 0; - if ( (err= games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) - { - if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) - { - UniValue obj; - //fprintf(stderr,"got baton\n"); - seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i no playerdata\n"); - newdata.resize(0); - *numkeysp = numkeys; - return(keystrokes); - } - else - { - *numkeysp = numkeys; - return(keystrokes); - } - } else num = 0; - } - else - { - fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); - if ( keystrokes != 0 ) - free(keystrokes), keystrokes = 0; - } - } else fprintf(stderr,"extractgame: invalid game\n"); - //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); - return(0); -} - -UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); CPubKey pk,gamespk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],gamesaddr[64],*pubstr,*hexstr; gamesevent *keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; - pk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); - result.push_back(Pair("name","games")); - result.push_back(Pair("method","extract")); - gamesaddr[0] = 0; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - if ( n == 2 ) - { - if ( (pubstr= jstr(jitem(params,1),0)) != 0 ) - { - if (strlen(pubstr) == 66 ) - { - decode_hex(pub33,33,pubstr); - pk = buf2pk(pub33); - } - else if ( strlen(pubstr) < 36 ) - strcpy(gamesaddr,pubstr); - } - //fprintf(stderr,"gametxid.%s %s\n",gametxid.GetHex().c_str(),pubstr); - } - if ( gamesaddr[0] == 0 ) - GetCCaddress1of2(cp,gamesaddr,gamespk,pk); - result.push_back(Pair("gamesaddr",gamesaddr)); - str[0] = 0; - if ( (keystrokes= games_extractgame(1,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) - { - result.push_back(Pair("status","success")); - flag = 1; - hexstr = (char *)calloc(1,sizeof(gamesevent)*numkeys*2 + 1); - for (i=0; i highlander vout from creategame TCBOO - //vin1 -> keystrokes baton of completed game, must be last to quit or first to win, only spent registration batons matter. If more than 60 blocks since last keystrokes, it is forfeit - //vins2+ -> rest of unspent registration utxo so all newgame vouts are spent - //vout0 -> nonfungible character with pack @ - //vout1 -> 1% ingame gold and all the buyins - - // detect if last to bailout - // vin0 -> kestrokes baton of completed game with Q - // vout0 -> playerdata marker - // vout0 -> 1% ingame gold - // get any playerdata, get all keystrokes, replay game and compare final state - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64],str[512]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; - struct CCcontract_info *cpTokens, tokensC; - - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,mygamesaddr,gamespk,mypk); - result.push_back(Pair("name","games")); - result.push_back(Pair("method",method)); - result.push_back(Pair("mygamesaddr",mygamesaddr)); - if ( strcmp(method,"bailout") == 0 ) - funcid = 'Q'; - else funcid = 'H'; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - if ( (err= games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,1)) == 0 ) - { - if ( games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,mygamesaddr,numplayers,symbol,pname) == 0 ) - { - UniValue obj; struct games_player P; - seed = games_gamefields(obj,maxplayers,buyin,gametxid,mygamesaddr); - fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i 0 ) - { - newdata.resize(num); - for (i=0; i no playerdata\n"); - newdata.resize(0); - } - else - { - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); - cashout = games_cashout(&P); - fprintf(stderr,"\ncashout %.8f extracted %s\n",(double)cashout/COIN,str); - if ( funcid == 'H' && maxplayers > 1 ) - { - /*if ( P.amulet == 0 ) - { - if ( numplayers != maxplayers ) - return(cclib_error(result,"numplayers != maxplayers")); - else if ( games_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) - return(cclib_error(result,"highlander must be a winner or last one standing")); - }*/ - cashout += games_buyins(gametxid,maxplayers);//numplayers * buyin; - } - if ( cashout > 0 ) - { - if ( (inputsum= AddCClibInputs(cp,mtx,gamespk,cashout,60,cp->unspendableCCaddr,1)) > cashout ) - CCchange = (inputsum - cashout); - else fprintf(stderr,"couldnt find enough utxos\n"); - } - mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - } - } - if ( CCchange + (batonvalue-3*txfee) >= txfee ) - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),gamespk)); - Myprivkey(mypriv); - CCaddr1of2set(cp,gamespk,mypk,mypriv,mygamesaddr); - CScript opret; - if ( pname.size() == 0 ) - pname = Games_pname; - if ( newdata.size() == 0 ) - { - opret = games_finishopret(funcid, gametxid, regslot, mypk, nodata,pname); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,opret); - //fprintf(stderr,"nodata finalizetx.(%s)\n",rawtx.c_str()); - } - else - { - opret = games_finishopret(funcid, gametxid, regslot, mypk, newdata,pname); - char seedstr[32]; - sprintf(seedstr,"%llu",(long long)seed); - std::vector vopretNonfungible; - GetOpReturnData(opret, vopretNonfungible); - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), std::string(seedstr), gametxid.GetHex(), vopretNonfungible)); - } - memset(mypriv,0,sizeof(mypriv)); - return(games_rawtxresult(result,rawtx,1)); - } - result.push_back(Pair("result","success")); - } else fprintf(stderr,"illegal game err.%d\n",err); - } else fprintf(stderr,"parameters only n.%d\n",n); - } - return(result); -} - -UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - return(games_finish(txfee,cp,params,(char *)"bailout")); -} - -UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - return(games_finish(txfee,cp,params,(char *)"highlander")); -} - -UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 tokenid,gametxid,txid,hashBlock; CTransaction playertx,tx; int32_t maxplayers,vout,numvouts; std::vector playerdata; CPubKey gamespk,mypk,pk; std::string symbol,pname; char coinaddr[64]; - std::vector > unspentOutputs; - gamespk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - GetTokensCCaddress(cp,coinaddr,mypk); - SetCCunspents(unspentOutputs,coinaddr,true); - games_univalue(result,"players",-1,-1); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - if ( it->second.satoshis != 1 || vout > 1 ) - continue; - if ( games_playerdata(cp,gametxid,tokenid,pk,playerdata,symbol,pname,txid) == 0 )//&& pk == mypk ) - { - a.push_back(txid.GetHex()); - //a.push_back(Pair("playerdata",games_playerobj(playerdata))); - } - } - result.push_back(Pair("playerdata",a)); - result.push_back(Pair("numplayerdata",(int64_t)a.size())); - return(result); -} - -UniValue games_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR),b(UniValue::VARR); uint256 txid,hashBlock,gametxid,tokenid,playertxid; int32_t vout,maxplayers,gameheight,numvouts; CPubKey gamespk,mypk; char coinaddr[64]; CTransaction tx,gametx; int64_t buyin; - std::vector txids; - gamespk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - GetCCaddress1of2(cp,coinaddr,gamespk,mypk); - SetCCtxids(txids,coinaddr,true,cp->evalcode,zeroid,'R'); - games_univalue(result,"games",-1,-1); - for (std::vector::const_iterator it=txids.begin(); it!=txids.end(); it++) - { - txid = *it; - //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) - { - if ( games_registeropretdecode(gametxid,tokenid,playertxid,tx.vout[numvouts-1].scriptPubKey) == 'R' ) - { - if ( games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) - { - if ( CCgettxout(txid,vout,1,0) < 0 ) - b.push_back(gametxid.GetHex()); - else a.push_back(gametxid.GetHex()); - } - } - } - } - result.push_back(Pair("pastgames",b)); - result.push_back(Pair("games",a)); - result.push_back(Pair("numgames",(int64_t)(a.size()+b.size()))); - return(result); -} - -UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); int32_t n; char *namestr = 0; - games_univalue(result,"setname",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - if ( (namestr= jstri(params,0)) != 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("pname",namestr)); - Games_pname = namestr; - return(result); - } - } - } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt get name")); - return(result); -} - -UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; CPubKey gamespk,mypk; CScript opret; - if ( params != 0 && cJSON_GetArraySize(params) == 1 ) - { - amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; - gamespk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( amount > GAMES_TXFEE ) - { - if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); - return(games_rawtxresult(result,rawtx,1)); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","not enough funds")); - } - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","amount too small")); - } - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt parse")); - } - return(result); -} - -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],gamesaddr[64],str2[67],fname[64]; gamesevent *keystrokes; int32_t i,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; - *cashoutp = 0; - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,gamesaddr,gamespk,pk); - if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) - { - free(keystrokes); - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - for (i=0; i int64_t Add1of2AddressInputs(struct CCcontract_info* cp, if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && isMyFuncId(funcId) && - (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid) > 0) && // token validation logic + (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)) { @@ -596,7 +596,7 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && isMyFuncId(funcId) && !isSpendingTx(funcId) && - (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid) > 0) && + (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) diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index b5c5e0c62..4e0a24668 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -68,9 +68,12 @@ class TokenHelper { public: static uint8_t getMyEval() { return EVAL_TOKENS; } static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { + /* struct CCcontract_info *cpHeir, heirC; cpHeir = CCinit(&heirC, EVAL_TOKENS); return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs); + */ + return 0; } static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { diff --git a/src/cc/import.cpp b/src/cc/import.cpp deleted file mode 100644 index 98cd3f30c..000000000 --- a/src/cc/import.cpp +++ /dev/null @@ -1,764 +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 "cc/eval.h" -#include "cc/utils.h" -#include "importcoin.h" -#include "crosschain.h" -#include "primitives/transaction.h" -#include "cc/CCinclude.h" -#include -#include "cc/CCtokens.h" - -#include "key_io.h" -#define CODA_BURN_ADDRESS "KPrrRoPfHOnNpZZQ6laHXdQDkSQDkVHaN0V+LizLlHxz7NaA59sBAAAA" -/* - * CC Eval method for import coin. - * - * This method should control every parameter of the ImportCoin transaction, since it has no signature - * to protect it from malleability. - - ##### 0xffffffff is a special CCid for single chain/dual daemon imports - */ - -extern std::string ASSETCHAINS_SELFIMPORT; -extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT; -extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; -extern uint256 HUSH_EARLYTXID; - -// utilities from gateways.cpp -uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids); -uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid); -int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid); -uint8_t DecodeImportGatewayBindOpRet(char *burnaddr,const CScript &scriptPubKey,std::string &coin,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &importgatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype); -int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 burntxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2); -char *nonportable_path(char *str); -char *portable_path(char *str); -void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep); -void *filestr(long *allocsizep,char *_fname); - -cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,char const *arg3,char const *arg4,char const *arg5) -{ - char cmdstr[5000],fname[256],*jsonstr; - long fsize; - cJSON *retjson=NULL; - - sprintf(fname,"/tmp/coda.%s",arg0); - sprintf(cmdstr,"coda.exe client %s %s %s %s %s %s > %s 2>&1",arg0,arg1,arg2,arg3,arg4,arg5,fname); - *retstr = 0; - if (system(cmdstr)<0) return (retjson); - if ( (jsonstr=(char *)filestr(&fsize,fname)) != 0 ) - { - jsonstr[strlen(jsonstr)-1]='\0'; - if ( (strncmp(jsonstr,"Merkle List of transactions:",28)!=0) || (retjson= cJSON_Parse(jsonstr+29)) == 0) - *retstr=jsonstr; - else free(jsonstr); - } - return(retjson); -} - -// makes source tx for self import tx -CMutableTransaction MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount) -{ - const int64_t txfee = 10000; - int64_t inputs, change; - CPubKey myPubKey = Mypubkey(); - struct CCcontract_info *cpDummy, C; - - cpDummy = CCinit(&C, EVAL_TOKENS); // this is just for FinalizeCCTx to work - - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - - if (AddNormalinputs(mtx, myPubKey, 2 * txfee, 4) == 0) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx() warning: cannot find normal inputs for txfee" << std::endl); - } - - CScript scriptPubKey = GetScriptForDestination(dest); - mtx.vout.push_back(CTxOut(txfee, scriptPubKey)); - - //make opret with 'burned' amount: - FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount)); - return mtx; -} - -// make sure vin is signed by pubkey33 -bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33]) -{ - CTransaction vintx; - uint256 blockHash; - char destaddr[64], pkaddr[64]; - - if (i < 0 || i >= sourcetx.vin.size()) - return false; - - if( !myGetTransaction(sourcetx.vin[i].prevout.hash, vintx, blockHash) ) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVinPubKey() could not load vintx" << sourcetx.vin[i].prevout.hash.GetHex() << std::endl); - return false; - } - if( sourcetx.vin[i].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[i].prevout.n].scriptPubKey) != 0 ) - { - pubkey2addr(pkaddr, pubkey33); - if (strcmp(pkaddr, destaddr) == 0) { - return true; - } - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVinPubKey() mismatched vin[" << i << "].prevout.n=" << sourcetx.vin[i].prevout.n << " -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl); - } - return false; -} - -// ac_import=PUBKEY support: -// prepare a tx for creating import tx and quasi-burn tx -int32_t GetSelfimportProof(const CMutableTransaction sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull) // find burnTx with hash from "other" daemon -{ - MerkleBranch newBranch; - CMutableTransaction tmpmtx; - //CTransaction sourcetx; - - tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - - /* - if (!E_UNMARSHAL(ParseHex(rawsourcetx), ss >> sourcetx)) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: could not unmarshal source tx" << std::endl); - return(-1); - } - - if (sourcetx.vout.size() == 0) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: vout size is 0" << std::endl); - return -1; - } */ - - /*if (ivout < 0) { // "ivout < 0" means "find" - // try to find vout - CPubKey myPubkey = Mypubkey(); - ivout = 0; - // skip change: - if (sourcetx.vout[ivout].scriptPubKey == (CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG)) - ivout++; - } - - if (ivout >= sourcetx.vout.size()) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: needed vout not found" << std::endl); - return -1; - } */ - - int32_t ivout = 0; - - // LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl); - - CScript scriptPubKey = sourceMtx.vout[ivout].scriptPubKey; - - //mtx is template for import tx - templateMtx = sourceMtx; - templateMtx.fOverwintered = tmpmtx.fOverwintered; - - //malleability fix for burn tx: - //mtx.nExpiryHeight = tmpmtx.nExpiryHeight; - templateMtx.nExpiryHeight = sourceMtx.nExpiryHeight; - - templateMtx.nVersionGroupId = tmpmtx.nVersionGroupId; - templateMtx.nVersion = tmpmtx.nVersion; - templateMtx.vout.clear(); - templateMtx.vout.resize(1); - - uint8_t evalCode, funcId; - int64_t burnAmount; - vscript_t vopret; - if( !GetOpReturnData(sourceMtx.vout.back().scriptPubKey, vopret) || - !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> burnAmount)) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof() could not unmarshal source tx opret" << std::endl); - return -1; - } - templateMtx.vout[0].nValue = burnAmount; - templateMtx.vout[0].scriptPubKey = scriptPubKey; - - // not sure we need this now as we create sourcetx ourselves: - /*if (sourcetx.GetHash() != sourcetxid) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl); - return(-1); - }*/ - - // check ac_pubkey: - if (!CheckVinPubKey(sourceMtx, 0, ASSETCHAINS_OVERRIDE_PUBKEY33)) { - return -1; - } - proofNull = ImportProof(std::make_pair(sourceMtx.GetHash(), newBranch)); - return 0; -} - -// make import tx with burntx and dual daemon -std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector vouts) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()),burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk; uint256 codaburntxid; std::vector dummyproof; - int32_t i,numvouts,n,m; std::string coin,error; struct CCcontract_info *cp, C; - cJSON *result,*tmp,*tmp1; unsigned char hash[SHA256_DIGEST_LENGTH+1]; - char out[SHA256_DIGEST_LENGTH*2+1],*retstr,*destaddr,*receiver; TxProof txProof; uint64_t amount; - - cp = CCinit(&C, EVAL_GATEWAYS); - if (txfee == 0) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - SHA256_CTX sha256; - SHA256_Init(&sha256); - SHA256_Update(&sha256, receipt.c_str(), receipt.size()); - SHA256_Final(hash, &sha256); - for(i = 0; i < SHA256_DIGEST_LENGTH; i++) - { - sprintf(out + (i * 2), "%02x", hash[i]); - } - out[65]='\0'; - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: hash=" << out << std::endl); - codaburntxid.SetHex(out); - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receipt=" << receipt << " codaburntxid=" << codaburntxid.GetHex().data() << " amount=" << (double)amount / COIN << std::endl); - result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),""); - if (result==0) - { - if (retstr!=0) - { - CCerror=std::string("CodaRPC: ")+retstr; - free(retstr); - } - return(""); - } - else - { - if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))!=0 && (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))!=0 && - (receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))!=0 && (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))!=0) - { - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeCodaImportTx: receiver=" << receiver << " destaddr=" << destaddr << " amount=" << amount << std::endl); - if (strcmp(receiver,CODA_BURN_ADDRESS)!=0) - { - CCerror="MakeCodaImportTx: invalid burn address, coins do not go to predefined burn address - "; - CCerror+=CODA_BURN_ADDRESS; - LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); - free(result); - return(""); - } - CTxDestination dest = DecodeDestination(destaddr); - CScript scriptPubKey = GetScriptForDestination(dest); - if (vouts[0]!=CTxOut(amount*COIN,scriptPubKey)) - { - CCerror="MakeCodaImportTx: invalid destination address, burnTx memo!=importTx destination"; - LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); - free(result); - return(""); - } - if (amount*COIN!=vouts[0].nValue) - { - CCerror="MakeCodaImportTx: invalid amount, burnTx amount!=importTx amount"; - LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); - free(result); - return(""); - } - burntx.vin.push_back(CTxIn(codaburntxid,0,CScript())); - burntx.vout.push_back(MakeBurnOutput(amount*COIN,0xffffffff,"CODA",vouts,dummyproof,srcaddr,receipt)); - return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof,burntx,vouts))); - } - else - { - CCerror="MakeCodaImportTx: invalid Coda burn tx"; - LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); - free(result); - return(""); - } - - } - CCerror="MakeCodaImportTx: error fetching Coda tx"; - LOGSTREAM("importcoin", CCLOG_INFO, stream << CCerror << std::endl); - free(result); - return(""); -} - -// use proof from the above functions to validate the import - -int32_t CheckBEAMimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) -{ - // check with dual-BEAM daemon via ASSETCHAINS_BEAMPORT for validity of burnTx - return(-1); -} - -int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector payouts,std::string srcaddr,std::string receipt) -{ - cJSON *result,*tmp,*tmp1; char *retstr,out[SHA256_DIGEST_LENGTH*2+1]; unsigned char hash[SHA256_DIGEST_LENGTH+1]; int i,n,m; - SHA256_CTX sha256; uint256 codaburntxid; char *destaddr,*receiver; uint64_t amount; - - // check with dual-CODA daemon via ASSETCHAINS_CODAPORT for validity of burnTx - SHA256_Init(&sha256); - SHA256_Update(&sha256, receipt.c_str(), receipt.size()); - SHA256_Final(hash, &sha256); - for(i = 0; i < SHA256_DIGEST_LENGTH; i++) - { - sprintf(out + (i * 2), "%02x", hash[i]); - } - out[65]='\0'; - codaburntxid.SetHex(out); - result=CodaRPC(&retstr,"prove-payment","-address",srcaddr.c_str(),"-receipt-chain-hash",receipt.c_str(),""); - if (result==0) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CodaRPC error: " << retstr << std::endl); - free(retstr); - return (-1); - } - else - { - if ((tmp=jobj(jitem(jarray(&n,result,(char *)"payments"),0),(char *)"payload"))==0 || (destaddr=jstr(jobj(tmp,(char *)"common"),(char *)"memo"))==0 || - (receiver=jstr(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"receiver"))==0 || (amount=j64bits(jitem(jarray(&m,tmp,(char *)"body"),1),(char *)"amount"))==0) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid Coda burn tx" << jprint(result,1) << std::endl); - free(result); - return (-1); - } - CTxDestination dest = DecodeDestination(destaddr); - CScript scriptPubKey = GetScriptForDestination(dest); - if (payouts[0]!=CTxOut(amount*COIN,scriptPubKey)); - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "Destination address in burn tx does not match destination in import tx" << std::endl); - free(result); - return (-1); - } - if (strcmp(receiver,CODA_BURN_ADDRESS)!=0) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid burn address " << jstr(tmp1,(char *)"receiver") << std::endl); - free(result); - return (-1); - } - if (amount*COIN!=payouts[0].nValue) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "Burn amount and import amount not matching, " << j64bits(tmp,(char *)"amount") << " - " << payouts[0].nValue/COIN << std::endl); - free(result); - return (-1); - } - if (burnTx.vin[0].prevout.hash!=codaburntxid || importTx.vin[0].prevout.hash!=burnTx.GetHash()) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "Invalid import/burn tx vin" << std::endl); - free(result); - return (-1); - } - free(result); - } - return(0); -} - -int32_t CheckGATEWAYimport(CTransaction importTx,CTransaction burnTx,std::string refcoin,std::vector proof, - uint256 bindtxid,std::vector publishers,std::vector txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount) -{ - CTransaction oracletx,bindtx,regtx; int32_t i,m,n=0,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype; - uint256 txid,oracletxid,tmporacletxid,merkleroot,mhash,hashBlock; - std::string name,desc,format,coin; std::vector vouts; CPubKey regpk; - std::vector pubkeys,tmppubkeys,tmppublishers; char markeraddr[64],deposit[64],destaddr[64],tmpdest[64]; int64_t datafee; - std::vector > unspentOutputs; - - // ASSETCHAINS_SELFIMPORT is coin - if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid import gateway. On this chain only valid import gateway is " << HUSH_EARLYTXID.GetHex() << std::endl); - return(-1); - } - // check for valid burn from external coin blockchain and if valid return(0); - if (myGetTransaction(bindtxid, bindtx, hashBlock) == 0 || (numvouts = bindtx.vout.size()) <= 0) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport cant find bindtxid=" << bindtxid.GetHex() << std::endl); - return(-1); - } - else if (DecodeImportGatewayBindOpRet(deposit,bindtx.vout[numvouts - 1].scriptPubKey,coin,oracletxid,M,N,tmppubkeys,taddr,prefix,prefix2,wiftype) != 'B') - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid bind tx. bindtxid=" << bindtxid.GetHex() << std::endl); - return(-1); - } - else if (refcoin!=coin) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid coin " << refcoin << "!=" << coin << std::endl); - return(-1); - } - else if ( N == 0 || N > 15 || M > N ) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid N or M " << std::endl); - return(-1); - } - else if (tmppubkeys.size()!=N) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport not enough pubkeys for given N " << std::endl); - return(-1); - } - else if (hush_txnotarizedconfirmed(bindtxid) == false) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport bindtx not yet confirmed/notarized" << std::endl); - return(-1); - } - else if (myGetTransaction(oracletxid, oracletx, hashBlock) == 0 || (numvouts = oracletx.vout.size()) <= 0) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl); - return(-1); - } - else if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C') - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl); - return(-1); - } - else if (name!=refcoin || format!="Ihh") - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl); - return(-1); - } - CCtxidaddr(markeraddr,oracletxid); - SetCCunspents(unspentOutputs,markeraddr,false); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - if ( myGetTransaction(txid,regtx,hashBlock) != 0 && regtx.vout.size() > 0 - && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid ) - { - pubkeys.push_back(regpk); - n++; - } - } - if (pubkeys.size()!=tmppubkeys.size()) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport different number of bind and oracle pubkeys " << tmppubkeys.size() << "!=" << pubkeys.size() << std::endl); - return(-1); - } - merkleroot = zeroid; - for (i = m = 0; i < n; i++) - { - if ((mhash = CCOraclesReverseScan("importgateway-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) - { - if (merkleroot == zeroid) - merkleroot = mhash, m = 1; - else if (mhash == merkleroot) - m ++; - tmppublishers.push_back(pubkeys[i]); - } - } - if (publishers.size()!=tmppublishers.size()) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport different number of publishers for burtx in oracle" << std::endl); - return(-1); - } - else if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); - return(-1); - } - else if ( ImportGatewayVerify(deposit,oracletxid,burnvout,refcoin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount ) - { - CCerror = strprintf("burntxid didnt validate !"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(-1); - } - else if (importTx.vout[0].nValue!=amount) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport import amount different than in burntx" << std::endl); - return(-1); - } - Getscriptaddress(destaddr,importTx.vout[0].scriptPubKey); - Getscriptaddress(tmpdest,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); - if (strcmp(destaddr,tmpdest)!=0) - { - LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport import coins destination different than in burntx" << std::endl); - return(-1); - } - return(0); -} - -int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) -{ - // if burnTx has ASSETCHAINS_PUBKEY vin, it is valid return(0); - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "proof txid=" << proof.first.GetHex() << std::endl); - - uint256 sourcetxid = proof.first, hashBlock; - CTransaction sourcetx; - - if (!myGetTransaction(sourcetxid, sourcetx, hashBlock)) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "could not load source txid=" << sourcetxid.GetHex() << std::endl); - return -1; - } - - if (sourcetx.vout.size() == 0) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "no vouts in source txid=" << sourcetxid.GetHex() << std::endl); - return -1; - } - - // might be malleable: - if (burnTx.nExpiryHeight != sourcetx.nExpiryHeight) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "burntx nExpiryHeight incorrect for source txid=" << sourcetxid.GetHex() << std::endl); - return -1; - } - - //ac_pubkey check: - if (!CheckVinPubKey(sourcetx, 0, ASSETCHAINS_OVERRIDE_PUBKEY33)) { - return -1; - } - - // get source tx opret: - std::vector vopret; - uint8_t evalCode, funcId; - int64_t amount; - - if (!GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret) || - vopret.size() == 0 || - !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || - evalCode != EVAL_IMPORTCOIN || funcId != 'A') { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "none or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl); - return -1; - } - - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "importTx amount=" << payouts[0].nValue << " burnTx amount=" << burnTx.vout[0].nValue << " opret amount=" << amount << " source txid=" << sourcetxid.GetHex() << std::endl); - - // amount malleability check with the opret from the source tx: - if (payouts[0].nValue != amount) { // assume that burntx amount is checked in the common code in Eval::ImportCoin() - LOGSTREAM("importcoin", CCLOG_INFO, stream << "importTx amount != amount in the opret of source txid=" << sourcetxid.GetHex() << std::endl); - return -1; - } - - return(0); -} - -bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector & payouts, const ImportProof &proof, const std::vector &rawproof) -{ - vscript_t vimportOpret; - if (!GetOpReturnData(importTx.vout.back().scriptPubKey, vimportOpret) || - vimportOpret.empty()) - return eval->Invalid("invalid-import-tx-no-opret"); - - - uint256 tokenid = zeroid; - if (vimportOpret.begin()[0] == EVAL_TOKENS) { // for tokens (new opret with tokens) - struct CCcontract_info *cpTokens, CCtokens_info; - std::vector> oprets; - uint8_t evalCodeInOpret; - std::vector voutTokenPubkeys; - vscript_t vnonfungibleOpret; - - cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS); - - if (DecodeTokenOpRet(importTx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) == 0) - return eval->Invalid("cannot-decode-import-tx-token-opret"); - - uint8_t nonfungibleEvalCode = EVAL_TOKENS; // init to no non-fungibles - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vnonfungibleOpret); - if (!vnonfungibleOpret.empty()) - nonfungibleEvalCode = vnonfungibleOpret.begin()[0]; - - // check if burn tx at least has cc evaltoken vins (we cannot get cc input) - bool hasTokenVin = false; - for (auto vin : burnTx.vin) - if (cpTokens->ismyvin(vin.scriptSig)) - hasTokenVin = true; - if (!hasTokenVin) - return eval->Invalid("burn-tx-has-no-token-vins"); - - // calc outputs for burn tx - CAmount ccBurnOutputs = 0; - for (auto v : burnTx.vout) - if (v.scriptPubKey.IsPayToCryptoCondition() && - CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(nonfungibleEvalCode, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey - ccBurnOutputs += v.nValue; - - // calc outputs for import tx - CAmount ccImportOutputs = 0; - for (auto v : importTx.vout) - if (v.scriptPubKey.IsPayToCryptoCondition() && - !IsTokenMarkerVout(v)) // should not be marker here - ccImportOutputs += v.nValue; - - if (ccBurnOutputs != ccImportOutputs) - return eval->Invalid("token-cc-burned-output-not-equal-cc-imported-output"); - - } - else if (vimportOpret.begin()[0] != EVAL_IMPORTCOIN) { - return eval->Invalid("import-tx-incorrect-opret-eval"); - } - - // for tokens check burn, import, tokenbase tx - if (!tokenid.IsNull()) { - - std::string sourceSymbol; - CTransaction tokenbaseTx; - if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol; ss >> tokenbaseTx)) - return eval->Invalid("cannot-unmarshal-rawproof-for-tokens"); - - uint256 sourceTokenId; - std::vector> oprets; - uint8_t evalCodeInOpret; - std::vector voutTokenPubkeys; - if (burnTx.vout.size() > 0 && DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCodeInOpret, sourceTokenId, voutTokenPubkeys, oprets) == 0) - return eval->Invalid("cannot-decode-burn-tx-token-opret"); - - if (sourceTokenId != tokenbaseTx.GetHash()) // check tokenid in burn tx opret maches the passed tokenbase tx (to prevent cheating by importing user) - return eval->Invalid("incorrect-token-creation-tx-passed"); - - std::vector> opretsSrc; - vscript_t vorigpubkeySrc; - std::string nameSrc, descSrc; - if (DecodeTokenCreateOpRet(tokenbaseTx.vout.back().scriptPubKey, vorigpubkeySrc, nameSrc, descSrc, opretsSrc) == 0) - return eval->Invalid("cannot-decode-token-creation-tx"); - - std::vector> opretsImport; - vscript_t vorigpubkeyImport; - std::string nameImport, descImport; - if (importTx.vout.size() == 0 || DecodeTokenCreateOpRet(importTx.vout.back().scriptPubKey, vorigpubkeySrc, nameSrc, descSrc, opretsImport) == 0) - return eval->Invalid("cannot-decode-token-import-tx"); - - // check that name,pubkey,description in import tx correspond ones in token creation tx in the source chain: - if (vorigpubkeySrc != vorigpubkeyImport || - nameSrc != nameImport || - descSrc != descImport) - return eval->Invalid("import-tx-token-params-incorrect"); - } - - - // Check burntx shows correct outputs hash -// if (payoutsHash != SerializeHash(payouts)) // done in ImportCoin -// return eval->Invalid("wrong-payouts"); - - - TxProof merkleBranchProof; - std::vector notaryTxids; - - // Check proof confirms existance of burnTx - if (proof.IsMerkleBranch(merkleBranchProof)) { - uint256 target = merkleBranchProof.second.Exec(burnTx.GetHash()); - LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Eval::ImportCoin() momom target=" << target.GetHex() << " merkleBranchProof.first=" << merkleBranchProof.first.GetHex() << std::endl); - if (!CheckMoMoM(merkleBranchProof.first, target)) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MoMoM check failed for importtx=" << importTx.GetHash().GetHex() << std::endl); - return eval->Invalid("momom-check-fail"); - } - } - else if (proof.IsNotaryTxids(notaryTxids)) { - if (!CheckNotariesApproval(burnTx.GetHash(), notaryTxids)) { - return eval->Invalid("notaries-approval-check-fail"); - } - } - else { - return eval->Invalid("invalid-import-proof"); - } - -/* if (vimportOpret.begin()[0] == EVAL_TOKENS) - return eval->Invalid("test-invalid-tokens-are-good!!"); - else - return eval->Invalid("test-invalid-coins-are-good!!"); */ - return true; -} - -bool Eval::ImportCoin(const std::vector params, const CTransaction &importTx, unsigned int nIn) -{ - ImportProof proof; - CTransaction burnTx; - std::vector payouts; - CAmount txfee = 10000, amount; - int32_t height, burnvout; - std::vector publishers; - uint32_t targetCcid; - std::string targetSymbol, srcaddr, destaddr, receipt, rawburntx; - uint256 payoutsHash, bindtxid, burntxid; - std::vector rawproof; - std::vector txids; - CPubKey destpub; - - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "Validating import tx..., txid=" << importTx.GetHash().GetHex() << std::endl); - - if (importTx.vout.size() < 2) - return Invalid("too-few-vouts"); - // params - if (!UnmarshalImportTx(importTx, proof, burnTx, payouts)) - return Invalid("invalid-params"); - // Control all aspects of this transaction - // It should not be at all malleable - if (ASSETCHAINS_SELFIMPORT!="PEGSCC" && MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) // ExistsImportTombstone prevents from duplication - return Invalid("non-canonical"); - // burn params - if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof)) - return Invalid("invalid-burn-tx"); - - if (burnTx.vout.size() == 0) - return Invalid("invalid-burn-tx-no-vouts"); - - // check burned normal amount >= import amount && burned amount <= import amount + txfee (extra txfee is for miners and relaying, see GetImportCoinValue() func) - CAmount burnAmount = burnTx.vout.back().nValue; - if (burnAmount == 0) - return Invalid("invalid-burn-amount"); - CAmount totalOut = 0; - for (auto v : importTx.vout) - if (!v.scriptPubKey.IsPayToCryptoCondition()) - totalOut += v.nValue; - if (totalOut > burnAmount || totalOut < burnAmount - txfee) - return Invalid("payout-too-high-or-too-low"); - - // Check burntx shows correct outputs hash - if (payoutsHash != SerializeHash(payouts)) - return Invalid("wrong-payouts"); - if (targetCcid < HUSH_FIRSTFUNGIBLEID) - return Invalid("chain-not-fungible"); - - if ( targetCcid != 0xffffffff ) - { - - if (targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol()) - return Invalid("importcoin-wrong-chain"); - - if (!CheckMigration(this, importTx, burnTx, payouts, proof, rawproof)) - return false; // eval->Invalid() is called in the func - } - else - { - TxProof merkleBranchProof; - if (!proof.IsMerkleBranch(merkleBranchProof)) - return Invalid("invalid-import-proof-for-0xFFFFFFFF"); - - if ( targetSymbol == "BEAM" ) - { - if ( ASSETCHAINS_BEAMPORT == 0 ) - return Invalid("BEAM-import-without-port"); - else if ( CheckBEAMimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 ) - return Invalid("BEAM-import-failure"); - } - else if ( targetSymbol == "CODA" ) - { - if ( ASSETCHAINS_CODAPORT == 0 ) - return Invalid("CODA-import-without-port"); - else if ( UnmarshalBurnTx(burnTx,srcaddr,receipt)==0 || CheckCODAimport(importTx,burnTx,payouts,srcaddr,receipt) < 0 ) - return Invalid("CODA-import-failure"); - } - else if ( targetSymbol == "PEGSCC" ) - { - if ( ASSETCHAINS_SELFIMPORT != "PEGSCC" ) - return Invalid("PEGSCC-import-when-not PEGSCC"); - // else if ( CheckPUBKEYimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 ) - // return Invalid("PEGSCC-import-failure"); - } - else if ( targetSymbol == "PUBKEY" ) - { - if ( ASSETCHAINS_SELFIMPORT != "PUBKEY" ) - return Invalid("PUBKEY-import-when-not PUBKEY"); - else if ( CheckPUBKEYimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 ) - return Invalid("PUBKEY-import-failure"); - } - else - { - if ( targetSymbol != ASSETCHAINS_SELFIMPORT ) - return Invalid("invalid-gateway-import-coin"); - else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,burntxid,height,burnvout,rawburntx,destpub,amount)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,burntxid,height,burnvout,rawburntx,destpub,amount) < 0 ) - return Invalid("GATEWAY-import-failure"); - } - } - - // return Invalid("test-invalid"); - LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Valid import tx! txid=" << importTx.GetHash().GetHex() << std::endl); - - return Valid(); -} diff --git a/src/cc/importgateway.cpp b/src/cc/importgateway.cpp deleted file mode 100644 index ea4ea4318..000000000 --- a/src/cc/importgateway.cpp +++ /dev/null @@ -1,1288 +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 "CCImportGateway.h" -#include "key_io.h" -#include "../importcoin.h" -// start of consensus code -#define HUSH_PUBTYPE 60 -#define HUSH_P2SHTYPE 85 -#define HUSH_WIFTYPE 188 -#define HUSH_TADDR 0 -#define CC_MARKER_VALUE 10000 - -extern uint256 HUSH_EARLYTXID; - -CScript EncodeImportGatewayBindOpRet(uint8_t funcid,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector importgatewaypubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2,uint8_t wiftype) -{ - CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << oracletxid << M << N << importgatewaypubkeys << taddr << prefix << prefix2 << wiftype); - return(opret); -} - -uint8_t DecodeImportGatewayBindOpRet(char *burnaddr,const CScript &scriptPubKey,std::string &coin,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &importgatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype) -{ - std::vector vopret; uint8_t *script,e,f; std::vector pubkeys; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - burnaddr[0] = 0; - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> oracletxid; ss >> M; ss >> N; ss >> importgatewaypubkeys; ss >> taddr; ss >> prefix; ss >> prefix2; ss >> wiftype) != 0 ) - { - if ( prefix == HUSH_PUBTYPE && prefix2 == HUSH_P2SHTYPE ) - { - if ( N > 1 ) - { - strcpy(burnaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,importgatewaypubkeys))).ToString().c_str()); - LOGSTREAM("importgateway", CCLOG_DEBUG1, stream << "f." << f << " M." << (int)M << " of N." << (int)N << " size." << (int32_t)importgatewaypubkeys.size() << " -> " << burnaddr << std::endl); - } else Getscriptaddress(burnaddr,CScript() << ParseHex(HexStr(importgatewaypubkeys[0])) << OP_CHECKSIG); - } - else - { - if ( N > 1 ) strcpy(burnaddr,CCustomBitcoinAddress(CScriptID(GetScriptForMultisig(M,importgatewaypubkeys)),taddr,prefix,prefix2).ToString().c_str()); - else GetCustomscriptaddress(burnaddr,CScript() << ParseHex(HexStr(importgatewaypubkeys[0])) << OP_CHECKSIG,taddr,prefix,prefix2); - } - return(f); - } else LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "error decoding bind opret" << std::endl); - return(0); -} - -CScript EncodeImportGatewayDepositOpRet(uint8_t funcid,uint256 bindtxid,std::string refcoin,std::vector publishers,std::vectortxids,int32_t height,uint256 burntxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) -{ - CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; - - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << bindtxid << publishers << txids << height << burntxid << claimvout << deposithex << proof << destpub << amount); - return(opret); -} - -uint8_t DecodeImportGatewayDepositOpRet(const CScript &scriptPubKey,uint256 &bindtxid,std::string &refcoin,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &burntxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) -{ - std::vector vopret; uint8_t *script,e,f; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> burntxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) - { - return(f); - } - return(0); -} - -CScript EncodeImportGatewayWithdrawOpRet(uint8_t funcid,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) -{ - CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; - - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << withdrawpub << amount); - return(opret); -} - -uint8_t DecodeImportGatewayWithdrawOpRet(const CScript &scriptPubKey,uint256 &bindtxid,std::string &refcoin,CPubKey &withdrawpub,int64_t &amount) -{ - std::vector vopret; uint8_t *script,e,f; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> bindtxid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) - { - return(f); - } - return(0); -} - -CScript EncodeImportGatewayPartialOpRet(uint8_t funcid, uint256 withdrawtxid,std::string refcoin,uint8_t K, CPubKey signerpk,std::string hex) -{ - CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; - - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << K << signerpk << hex); - return(opret); -} - -uint8_t DecodeImportGatewayPartialOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,uint8_t &K,CPubKey &signerpk,std::string &hex) -{ - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> K; ss >> signerpk; ss >> hex) != 0 ) - { - return(f); - } - return(0); -} - -CScript EncodeImportGatewayCompleteSigningOpRet(uint8_t funcid,uint256 withdrawtxid,std::string refcoin,uint8_t K,std::string hex) -{ - CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << K << hex); - return(opret); -} - -uint8_t DecodeImportGatewayCompleteSigningOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,uint8_t &K,std::string &hex) -{ - std::vector vopret; uint8_t *script,e,f; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> K; ss >> hex) != 0 ) - { - return(f); - } - return(0); -} - -CScript EncodeImportGatewayMarkDoneOpRet(uint8_t funcid,uint256 withdrawtxid,std::string refcoin,uint256 completetxid) -{ - CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; - - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << completetxid); - return(opret); -} - -uint8_t DecodeImportGatewayMarkDoneOpRet(const CScript &scriptPubKey, uint256 &withdrawtxid, std::string &refcoin, uint256 &completetxid) -{ - std::vector vopret; uint8_t *script,e,f; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> completetxid;) != 0 ) - { - return(f); - } - return(0); -} - -uint8_t DecodeImportGatewayOpRet(const CScript &scriptPubKey) -{ - std::vector vopret; uint8_t *script,e,f; - - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && script[0] == EVAL_IMPORTGATEWAY) - { - f=script[1]; - if (f == 'B' || f == 'D' || f == 'C' || f == 'W' || f == 'P' || f == 'S' || f == 'M') - return(f); - } - return(0); -} - -int64_t IsImportGatewayvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) -{ - char destaddr[64]; - - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - } - return(0); -} - -int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 burntxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2) -{ - std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; - char destaddr[64],destpubaddr[64],claimaddr[64]; int32_t i,numvouts; int64_t nValue = 0; - - if ( myGetTransaction(oracletxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify cant find oracletxid " << oracletxid.GetHex() << std::endl); - return(0); - } - if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin ) - { - LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify mismatched oracle name " << name << " != " << refcoin << std::endl); - return(0); - } - proofroot = BitcoinGetProofMerkleRoot(proof,txids); - if ( proofroot != merkleroot ) - { - LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify mismatched merkleroot " << proofroot.GetHex() << " != " << merkleroot.GetHex() << std::endl); - return(0); - } - if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) - { - LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify invalid proof for this burntxid " << burntxid.GetHex() << std::endl); - return 0; - } - if ( DecodeHexTx(tx,deposithex) != 0 ) - { - GetCustomscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey,taddr,prefix,prefix2); - GetCustomscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG,taddr,prefix,prefix2); - if ( strcmp(claimaddr,destpubaddr) == 0 ) - { - for (i=0; i publishers; std::vectortxids; uint256 bindtxid,burntxid; std::vector proof; CPubKey claimpubkey; - if ( (numvouts= tx.vout.size()) > 0 ) - { - if ( DecodeImportGatewayDepositOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,publishers,txids,height,burntxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) - { - return(amount); - } - } - return(0); -} - -int32_t ImportGatewayBindExists(struct CCcontract_info *cp,CPubKey importgatewaypk,std::string refcoin) -{ - char markeraddr[64],burnaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; - uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; CTransaction tx; - std::vector txids; - - _GetCCaddress(markeraddr,EVAL_IMPORTGATEWAY,importgatewaypk); - SetCCtxids(txids,markeraddr,true,cp->evalcode,zeroid,'B'); - for (std::vector::const_iterator it=txids.begin(); it!=txids.end(); it++) - { - if ( myGetTransaction(*it,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 && DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey)=='B' ) - { - if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) == 'B' ) - { - if ( coin == refcoin ) - { - LOGSTREAM("importgateway",CCLOG_INFO, stream << "trying to bind an existing import for coin" << std::endl); - return(1); - } - } - } - } - std::vector tmp_txs; - myGet_mempool_txs(tmp_txs,EVAL_IMPORTGATEWAY,'B'); - for (std::vector::const_iterator it=tmp_txs.begin(); it!=tmp_txs.end(); it++) - { - const CTransaction &txmempool = *it; - - if ((numvouts=txmempool.vout.size()) > 0 && DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey)=='B') - if (DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) == 'B') - return(1); - } - - return(0); -} - -bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn) -{ - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks,height,claimvout; bool retval; uint8_t funcid,hash[32],K,M,N,taddr,prefix,prefix2,wiftype; - char str[65],destaddr[65],burnaddr[65],importgatewayaddr[65],validationError[512]; - std::vector txids; std::vector pubkeys,publishers,tmppublishers; std::vector proof; int64_t amount,tmpamount; - uint256 hashblock,txid,bindtxid,deposittxid,withdrawtxid,completetxid,tmptokenid,oracletxid,bindtokenid,burntxid,tmptxid,merkleroot,mhash; CTransaction bindtx,tmptx; - std::string refcoin,tmprefcoin,hex,name,description,format; CPubKey pubkey,tmppubkey,importgatewaypk; - - return (true); - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else - { - //LogPrint("importgateway-1","check amounts\n"); - // if ( ImportGatewayExactAmounts(cp,eval,tx,1,10000) == false ) - // { - // return eval->Invalid("invalid inputs vs. outputs!"); - // } - // else - // { - importgatewaypk = GetUnspendable(cp,0); - GetCCaddress(cp, importgatewayaddr, importgatewaypk); - if ( (funcid = DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey)) != 0) - { - switch ( funcid ) - { - case 'B': - //vin.0: normal input - //vout.0: CC vout marker - //vout.n-1: opreturn - 'B' coin oracletxid M N pubkeys taddr prefix prefix2 wiftype - return eval->Invalid("unexpected ImportGatewayValidate for gatewaysbind!"); - break; - case 'W': - //vin.0: normal input - //vin.1: CC input of tokens - //vout.0: CC vout marker to gateways CC address - //vout.1: CC vout of gateways tokens back to gateways tokens CC address - //vout.2: CC vout change of tokens back to owners pubkey (if any) - //vout.n-1: opreturn - 'W' bindtxid refcoin withdrawpub amount - return eval->Invalid("unexpected ImportGatewayValidate for gatewaysWithdraw!"); - break; - case 'P': - //vin.0: normal input - //vin.1: CC input of marker from previous tx (withdraw or partialsing) - //vout.0: CC vout marker to gateways CC address - //vout.n-1: opreturn - 'P' withdrawtxid refcoin number_of_signs mypk hex - if ((numvouts=tx.vout.size()) > 0 && DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,refcoin,K,pubkey,hex)!='P') - return eval->Invalid("invalid gatewaysPartialSign OP_RETURN data!"); - else if (myGetTransaction(withdrawtxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid withdraw txid!"); - else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,tmprefcoin,pubkey,amount)!='W') - return eval->Invalid("invalid gatewayswithdraw OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different than in bind tx"); - else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for gatewaysWithdraw!"); - else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysWithdraw!"); - else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) - return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); - else if ( ConstrainVout(tmptx.vout[1],1,importgatewayaddr,amount)==0) - return eval->Invalid("invalid tokens to gateways vout for gatewaysWithdraw!"); - else if (tmptx.vout[1].nValue!=amount) - return eval->Invalid("amount in opret not matching tx tokens amount!"); - else if (hush_txnotarizedconfirmed(withdrawtxid) == false) - return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarized)!"); - else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid gatewaysbind txid!"); - else if ((numvouts=tmptx.vout.size()) < 1 || DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,tmprefcoin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B') - return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different than in bind tx"); - else if (hush_txnotarizedconfirmed(bindtxid) == false) - return eval->Invalid("gatewaysbind tx is not yet confirmed(notarized)!"); - else if (IsCCInput(tx.vin[0].scriptSig) != 0) - return eval->Invalid("vin.0 is normal for gatewayspartialsign!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.1 is CC marker for gatewayspartialsign or invalid marker amount!"); - else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 ) - return eval->Invalid("vout.0 invalid marker for gatewayspartialsign!"); - else if (K>M) - return eval->Invalid("invalid number of signs!"); - break; - case 'S': - //vin.0: normal input - //vin.1: CC input of marker from previous tx (withdraw or partialsing) - //vout.0: CC vout marker to gateways CC address - //vout.n-1: opreturn - 'S' withdrawtxid refcoin hex - if ((numvouts=tx.vout.size()) > 0 && DecodeImportGatewayCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,refcoin,K,hex)!='S') - return eval->Invalid("invalid gatewayscompletesigning OP_RETURN data!"); - else if (myGetTransaction(withdrawtxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid withdraw txid!"); - else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,tmprefcoin,pubkey,amount)!='W') - return eval->Invalid("invalid gatewayswithdraw OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different than in bind tx"); - else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for gatewaysWithdraw!"); - else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysWithdraw!"); - else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) - return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); - else if ( ConstrainVout(tmptx.vout[1],1,importgatewayaddr,amount)==0) - return eval->Invalid("invalid tokens to gateways vout for gatewaysWithdraw!"); - else if (tmptx.vout[1].nValue!=amount) - return eval->Invalid("amount in opret not matching tx tokens amount!"); - else if (hush_txnotarizedconfirmed(withdrawtxid) == false) - return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarized)!"); - else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid gatewaysbind txid!"); - else if ((numvouts=tmptx.vout.size()) < 1 || DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,tmprefcoin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B') - return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different than in bind tx"); - else if (hush_txnotarizedconfirmed(bindtxid) == false) - return eval->Invalid("gatewaysbind tx is not yet confirmed(notarized)!"); - else if (IsCCInput(tx.vin[0].scriptSig) != 0) - return eval->Invalid("vin.0 is normal for gatewayscompletesigning!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.1 is CC marker for gatewayscompletesigning or invalid marker amount!"); - else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 ) - return eval->Invalid("vout.0 invalid marker for gatewayscompletesigning!"); - else if (KInvalid("invalid number of signs!"); - break; - case 'M': - //vin.0: normal input - //vin.1: CC input of gatewayscompletesigning tx marker to gateways CC address - //vout.0: opreturn - 'M' withdrawtxid refcoin completetxid - if ((numvouts=tx.vout.size()) > 0 && DecodeImportGatewayMarkDoneOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,refcoin,completetxid)!='M') - return eval->Invalid("invalid gatewaysmarkdone OP_RETURN data!"); - else if (myGetTransaction(completetxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid gatewayscompletesigning txid!"); - else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayCompleteSigningOpRet(tmptx.vout[numvouts-1].scriptPubKey,withdrawtxid,tmprefcoin,K,hex)!='S') - return eval->Invalid("invalid gatewayscompletesigning OP_RETURN data!"); - else if (hush_txnotarizedconfirmed(completetxid) == false) - return eval->Invalid("gatewayscompletesigning tx is not yet confirmed(notarized)!"); - else if (myGetTransaction(withdrawtxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid withdraw txid!"); - else if ((numvouts=tmptx.vout.size()) > 0 && DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,tmprefcoin,pubkey,amount)!='W') - return eval->Invalid("invalid gatewayswithdraw OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different than in bind tx"); - else if (hush_txnotarizedconfirmed(withdrawtxid) == false) - return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarized)!"); - else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) - return eval->Invalid("invalid gatewaysbind txid!"); - else if ((numvouts=tmptx.vout.size()) < 1 || DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,tmprefcoin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B') - return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different than in bind tx"); - else if (hush_txnotarizedconfirmed(bindtxid) == false) - return eval->Invalid("gatewaysbind tx is not yet confirmed(notarized)!"); - else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for gatewaysmarkdone!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.1 is CC marker for gatewaysmarkdone or invalid marker amount!"); - else if (KInvalid("invalid number of signs!"); - break; - } - } - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGateway tx validated" << std::endl); - else fprintf(stderr,"ImportGateway tx invalid\n"); - return(retval); - // } - } -} -// end of consensus code - -// helper functions for rpc calls in rpcwallet.cpp - -std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CTransaction oracletx; uint8_t taddr,prefix,prefix2,wiftype; CPubKey mypk,importgatewaypk; CScript opret; uint256 hashBlock; - struct CCcontract_info *cp,*cpTokens,C,CTokens; std::string name,description,format; int32_t i,numvouts; - char destaddr[64],coinaddr[64],myTokenCCaddr[64],str[65],*fstr; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - cpTokens = CCinit(&CTokens,EVAL_TOKENS); - if (coin=="HUSH") - { - prefix = HUSH_PUBTYPE; - prefix2 = HUSH_P2SHTYPE; - wiftype = HUSH_WIFTYPE; - taddr = HUSH_TADDR; - } - else - { - prefix = p1; - prefix2 = p2; - wiftype = p3; - taddr = p4; - LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "set prefix " << prefix << ", prefix2 " << prefix2 << ", wiftype " << wiftype << ", taddr " << taddr << " for " << coin << std::endl); - } - if ( N == 0 || N > 15 || M > N ) - { - CCerror = strprintf("illegal M.%d or N.%d",M,N); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( pubkeys.size() != N ) - { - CCerror = strprintf("M.%d N.%d but pubkeys[%d]",M,N,(int32_t)pubkeys.size()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - for (i=0; i 0 ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CC_MARKER_VALUE,importgatewaypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayBindOpRet('B',coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype))); - } - CCerror = strprintf("cant find enough inputs"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); -} - -std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t claimvout,std::string rawburntx,std::vectorproof,CPubKey destpub,int64_t amount) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()), burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CTransaction bindtx; CPubKey mypk; uint256 oracletxid,merkleroot,mhash,hashBlock,txid; std::vector vouts; - int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::string coin; struct CCcontract_info *cp,C; - std::vector pubkeys,publishers; std::vector txids; char str[128],burnaddr[64]; - - if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx)) - { - return std::string(""); - } - LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "ImportGatewayDeposit ht." << height << " " << refcoin << " " << (double)amount/COIN << " numpks." << (int32_t)pubkeys.size() << std::endl); - if ( myGetTransaction(bindtxid,bindtx,hashBlock) == 0 || (numvouts= bindtx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( DecodeImportGatewayBindOpRet(burnaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) - { - CCerror = strprintf("invalid coin - bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if (hush_txnotarizedconfirmed(bindtxid)==false) - { - CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - n = (int32_t)pubkeys.size(); - merkleroot = zeroid; - for (i=m=0; i leaftxids; - BitcoinGetProofMerkleRoot(proof, leaftxids); - MerkleBranch newBranch(0, leaftxids); - TxProof txProof = std::make_pair(burntxid, newBranch); - return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts))); -} - -std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CTransaction tx; CPubKey mypk,importgatewaypk,signerpk; uint256 txid,hashBlock,oracletxid,tmptokenid,tmpbindtxid,withdrawtxid; int32_t vout,numvouts; - int64_t nValue,inputs,CCchange=0,tmpamount; uint8_t funcid,K,M,N,taddr,prefix,prefix2,wiftype; std::string coin,hex; - std::vector msigpubkeys; char burnaddr[64],str[65],coinaddr[64]; struct CCcontract_info *cp,C; - std::vector > unspentOutputs; - - if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - importgatewaypk = GetUnspendable(cp, 0); - - if( myGetTransaction(bindtxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || coin != refcoin ) - { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if (hush_txnotarizedconfirmed(bindtxid)==false) - { - CCerror = strprintf("gatewaysbind tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,importgatewaypk); - SetCCunspents(unspentOutputs,coinaddr,true); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - nValue = (int64_t)it->second.satoshis; - K=0; - if ( vout == 0 && nValue == CC_MARKER_VALUE && myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size())>0 && - (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P')) - { - if (funcid=='W' && DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,tmpamount)=='W' - && refcoin==coin && tmpbindtxid==bindtxid) - { - CCerror = strprintf("unable to create withdraw, another withdraw pending"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - - else if (funcid=='P' && DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)=='P' && - myGetTransaction(withdrawtxid,tx,hashBlock)!=0 && (numvouts=tx.vout.size())>0 && DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,tmpamount)=='W' - && refcoin==coin && tmpbindtxid==bindtxid) - { - CCerror = strprintf("unable to create withdraw, another withdraw pending"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - } - } - if( AddNormalinputs(mtx, mypk, txfee+CC_MARKER_VALUE+amount, 64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,CC_MARKER_VALUE,importgatewaypk)); - mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,amount,CCtxidaddr(str,bindtxid))); - return(FinalizeCCTx(0, cp, mtx, mypk, txfee,EncodeImportGatewayWithdrawOpRet('W',bindtxid,refcoin,withdrawpub,amount))); - } - CCerror = strprintf("cant find enough normal inputs"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); -} - -std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,withdrawpub,signerpk,importgatewaypk; struct CCcontract_info *cp,C; CTransaction tx,tmptx; - std::vector > unspentOutputs; char funcid,str[65],burnaddr[64]; - int32_t numvouts; uint256 withdrawtxid,hashBlock,bindtxid,tokenid,oracletxid; std::string coin,tmphex; int64_t amount; - uint8_t K=0,M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - importgatewaypk = GetUnspendable(cp,0); - if (myGetTransaction(lasttxid,tx,hashBlock)==0 || (numvouts= tx.vout.size())<=0 - || (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) - { - CCerror = strprintf("can't find last tx %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if (funcid=='W') - { - withdrawtxid=lasttxid; - if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) - { - CCerror = strprintf("invalid withdraw tx %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (hush_txnotarizedconfirmed(withdrawtxid)==false) - { - CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(bindtxid,tmptx,hashBlock)==0 || (numvouts=tmptx.vout.size())<=0) - { - CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' - || refcoin!=coin) - { - CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - } - else if (funcid=='P') - { - if (DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) - { - CCerror = strprintf("cannot decode partialsign tx opret %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(withdrawtxid,tmptx,hashBlock)==0 || (numvouts= tmptx.vout.size())<=0) - { - CCerror = strprintf("can't find withdraw tx %s",uint256_str(str,withdrawtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' - || refcoin!=coin) - { - CCerror = strprintf("invalid withdraw tx %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (hush_txnotarizedconfirmed(withdrawtxid)==false) - { - CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(bindtxid,tmptx,hashBlock)==0 || (numvouts=tmptx.vout.size())<=0) - { - CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' - || refcoin!=coin) - { - CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) - { - mtx.vin.push_back(CTxIn(tx.GetHash(),0,CScript())); - mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,CC_MARKER_VALUE,importgatewaypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayPartialOpRet('P',withdrawtxid,refcoin,K+1,mypk,hex))); - } - CCerror = strprintf("error adding funds for partialsign"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); -} - -std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,importgatewaypk,signerpk,withdrawpub; struct CCcontract_info *cp,C; char funcid,str[65],burnaddr[64]; int64_t amount; - std::string coin,tmphex; CTransaction tx,tmptx; uint256 withdrawtxid,hashBlock,tokenid,bindtxid,oracletxid; int32_t numvouts; - uint8_t K=0,M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - mypk = pubkey2pk(Mypubkey()); - importgatewaypk = GetUnspendable(cp,0); - if ( txfee == 0 ) - txfee = 10000; - if (myGetTransaction(lasttxid,tx,hashBlock)==0 || (numvouts= tx.vout.size())<=0 - || (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) - { - CCerror = strprintf("invalid last txid %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if (funcid=='W') - { - withdrawtxid=lasttxid; - if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) - { - CCerror = strprintf("cannot decode withdraw tx opret %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(bindtxid,tmptx,hashBlock)==0 || (numvouts=tmptx.vout.size())<=0) - { - CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (hush_txnotarizedconfirmed(withdrawtxid)==false) - { - CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (GetTransaction(bindtxid,tmptx,hashBlock,false)==0 || (numvouts=tmptx.vout.size())<=0) - { - CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' - || refcoin!=coin) - { - CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - } - else if (funcid=='P') - { - if (DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) - { - CCerror = strprintf("cannot decode partialsign tx opret %s",uint256_str(str,lasttxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(withdrawtxid,tmptx,hashBlock)==0 || (numvouts=tmptx.vout.size())==0) - { - CCerror = strprintf("invalid withdraw txid %s",uint256_str(str,withdrawtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayWithdrawOpRet(tmptx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) - { - CCerror = strprintf("cannot decode withdraw tx opret %s",uint256_str(str,withdrawtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (hush_txnotarizedconfirmed(withdrawtxid)==false) - { - CCerror = strprintf("gatewayswithdraw tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(bindtxid,tmptx,hashBlock)==0 || (numvouts=tmptx.vout.size())<=0) - { - CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayBindOpRet(burnaddr,tmptx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' - || refcoin!=coin) - { - CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) - { - mtx.vin.push_back(CTxIn(lasttxid,0,CScript())); - mtx.vout.push_back(MakeCC1vout(EVAL_IMPORTGATEWAY,CC_MARKER_VALUE,importgatewaypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayCompleteSigningOpRet('S',withdrawtxid,refcoin,K+1,hex))); - } - CCerror = strprintf("error adding funds for completesigning"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); -} - -std::string ImportGatewayMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk; struct CCcontract_info *cp,C; char str[65],burnaddr[64]; CTransaction tx; int32_t numvouts; - uint256 withdrawtxid,bindtxid,oracletxid,tokenid,hashBlock; std::string coin,hex; - uint8_t K,M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; int64_t amount; CPubKey withdrawpub; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - mypk = pubkey2pk(Mypubkey()); - if ( txfee == 0 ) - txfee = 10000; - if (myGetTransaction(completetxid,tx,hashBlock)==0 || (numvouts= tx.vout.size())<=0) - { - CCerror = strprintf("invalid completesigning txid %s",uint256_str(str,completetxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,hex)!='S' || refcoin!=coin) - { - CCerror = strprintf("cannot decode completesigning tx opret %s",uint256_str(str,completetxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if (hush_txnotarizedconfirmed(completetxid)==false) - { - CCerror = strprintf("gatewayscompletesigning tx not yet confirmed/notarized"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(withdrawtxid,tx,hashBlock)==0 || (numvouts= tx.vout.size())==0) - { - CCerror = strprintf("invalid withdraw txid %s",uint256_str(str,withdrawtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) - { - CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (HUSH_EARLYTXID!=zeroid && bindtxid!=HUSH_EARLYTXID) - { - CCerror = strprintf("invalid import gateway. On this chain only valid import gateway is %s",HUSH_EARLYTXID.GetHex()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (myGetTransaction(bindtxid,tx,hashBlock)==0 || (numvouts=tx.vout.size())<=0) - { - CCerror = strprintf("can't find bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - else if (DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 'B' - || refcoin!=coin) - { - CCerror = strprintf("invalid bind tx %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) - { - mtx.vin.push_back(CTxIn(completetxid,0,CScript())); - mtx.vout.push_back(CTxOut(CC_MARKER_VALUE,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeImportGatewayMarkDoneOpRet('M',withdrawtxid,refcoin,completetxid))); - } - CCerror = strprintf("error adding funds for markdone"); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); -} - -UniValue ImportGatewayPendingWithdraws(uint256 bindtxid,std::string refcoin) -{ - UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex; CPubKey mypk,importgatewaypk,withdrawpub,signerpk; - std::vector msigpubkeys; uint256 hashBlock,txid,tmpbindtxid,tmptokenid,oracletxid,withdrawtxid; uint8_t K,M,N,taddr,prefix,prefix2,wiftype; - char funcid,burnaddr[65],coinaddr[65],destaddr[65],str[65],withaddr[65],numstr[32],signeraddr[65],txidaddr[65]; - int32_t i,n,numvouts,vout,queueflag; int64_t amount,nValue; struct CCcontract_info *cp,C; - std::vector > unspentOutputs; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - mypk = pubkey2pk(Mypubkey()); - importgatewaypk = GetUnspendable(cp,0); - _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,importgatewaypk); - if ( myGetTransaction(bindtxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin ) - { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - n = msigpubkeys.size(); - queueflag = 0; - for (i=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - nValue = (int64_t)it->second.satoshis; - K=0; - if ( vout == 0 && nValue == CC_MARKER_VALUE && myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size())>0 && - (funcid=DecodeImportGatewayOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P') && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0) - { - if (funcid=='W') - { - if (DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,amount)==0 || refcoin!=coin || tmpbindtxid!=bindtxid) continue; - } - else if (funcid=='P') - { - if (DecodeImportGatewayPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)!='P' || myGetTransaction(withdrawtxid,tx,hashBlock)==0 - || (numvouts=tx.vout.size())<=0 || DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,withdrawpub,amount)!='W' - || refcoin!=coin || tmpbindtxid!=bindtxid) - continue; - } - Getscriptaddress(destaddr,tx.vout[1].scriptPubKey); - GetCustomscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG,taddr,prefix,prefix2); - if ( strcmp(destaddr,coinaddr) == 0 ) - { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("withdrawtxid",uint256_str(str,tx.GetHash()))); - CCCustomtxidaddr(txidaddr,tx.GetHash(),taddr,prefix,prefix2); - obj.push_back(Pair("withdrawtxidaddr",txidaddr)); - obj.push_back(Pair("withdrawaddr",withaddr)); - sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); - obj.push_back(Pair("amount",numstr)); - obj.push_back(Pair("confirmed_or_notarized",hush_txnotarizedconfirmed(tx.GetHash()))); - if ( queueflag != 0 ) - { - obj.push_back(Pair("depositaddr",burnaddr)); - GetCustomscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG,taddr,prefix,prefix2); - obj.push_back(Pair("signeraddr",signeraddr)); - } - if (N>1) - { - obj.push_back(Pair("number_of_signs",K)); - obj.push_back(Pair("last_txid",uint256_str(str,txid))); - if (K>0) obj.push_back(Pair("hex",hex)); - } - pending.push_back(obj); - } - } - } - result.push_back(Pair("coin",refcoin)); - result.push_back(Pair("pending",pending)); - result.push_back(Pair("queueflag",queueflag)); - return(result); -} - -UniValue ImportGatewayProcessedWithdraws(uint256 bindtxid,std::string refcoin) -{ - UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string coin,hex; - CPubKey mypk,importgatewaypk,withdrawpub; std::vector msigpubkeys; - uint256 withdrawtxid,hashBlock,txid,tmptokenid,oracletxid; uint8_t K,M,N,taddr,prefix,prefix2,wiftype; - char burnaddr[65],coinaddr[65],str[65],numstr[32],withaddr[65],txidaddr[65]; - int32_t i,n,numvouts,vout,queueflag; int64_t nValue,amount; struct CCcontract_info *cp,C; - std::vector > unspentOutputs; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - mypk = pubkey2pk(Mypubkey()); - importgatewaypk = GetUnspendable(cp,0); - _GetCCaddress(coinaddr,EVAL_IMPORTGATEWAY,importgatewaypk); - if ( myGetTransaction(bindtxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B' || refcoin != coin) - { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - n = msigpubkeys.size(); - queueflag = 0; - for (i=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - nValue = (int64_t)it->second.satoshis; - if ( vout == 0 && nValue == CC_MARKER_VALUE && myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size())>0 && - DecodeImportGatewayCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,hex) == 'S' && refcoin == coin && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0) - { - if (myGetTransaction(withdrawtxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size())>0 - && DecodeImportGatewayWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,withdrawpub,amount) == 'W' || refcoin!=coin) - { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("completesigningtxid",uint256_str(str,txid))); - obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); - CCCustomtxidaddr(txidaddr,withdrawtxid,taddr,prefix,prefix2); - obj.push_back(Pair("withdrawtxidaddr",txidaddr)); - GetCustomscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG,taddr,prefix,prefix2); - obj.push_back(Pair("withdrawaddr",withaddr)); - obj.push_back(Pair("confirmed_or_notarized",hush_txnotarizedconfirmed(txid))); - sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); - obj.push_back(Pair("amount",numstr)); - obj.push_back(Pair("hex",hex)); - processed.push_back(obj); - } - } - } - result.push_back(Pair("coin",refcoin)); - result.push_back(Pair("processed",processed)); - result.push_back(Pair("queueflag",queueflag)); - return(result); -} - -UniValue ImportGatewayList() -{ - UniValue result(UniValue::VARR); std::vector txids; - struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction vintx; std::string coin; - char str[65],burnaddr[64]; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector pubkeys; - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - SetCCtxids(txids,cp->unspendableCCaddr,true,cp->evalcode,zeroid,'B'); - for (std::vector::const_iterator it=txids.begin(); it!=txids.end(); it++) - { - txid = *it; - if ( myGetTransaction(txid,vintx,hashBlock) != 0 ) - { - if ( vintx.vout.size() > 0 && DecodeImportGatewayBindOpRet(burnaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 0 ) - { - result.push_back(uint256_str(str,txid)); - } - } - } - return(result); -} - -UniValue ImportGatewayExternalAddress(uint256 bindtxid,CPubKey pubkey) -{ - UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction tx; - std::string coin; int64_t numvouts; char str[65],addr[65],burnaddr[65]; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector msigpubkeys; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - if ( myGetTransaction(bindtxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') - { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - GetCustomscriptaddress(addr,CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG,taddr,prefix,prefix2); - result.push_back(Pair("result","success")); - result.push_back(Pair("address",addr)); - return(result); -} - -UniValue ImportGatewayDumpPrivKey(uint256 bindtxid,CKey key) -{ - UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction tx; - std::string coin,priv; int64_t numvouts; char str[65],addr[65],burnaddr[65]; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::vector msigpubkeys; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - if ( myGetTransaction(bindtxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') - { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - - priv=EncodeCustomSecret(key,wiftype); - result.push_back(Pair("result","success")); - result.push_back(Pair("privkey",priv.c_str())); - return(result); -} - -UniValue ImportGatewayInfo(uint256 bindtxid) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],burnaddr[64],gatewaystokens[64]; - uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2,wiftype; uint256 oracletxid,hashBlock; CTransaction tx; - CPubKey ImportGatewaypk; struct CCcontract_info *cp,C; int32_t i; int64_t numvouts,remaining; std::vector msigpubkeys; - - cp = CCinit(&C,EVAL_IMPORTGATEWAY); - ImportGatewaypk = GetUnspendable(cp,0); - GetTokensCCaddress(cp,gatewaystokens,ImportGatewaypk); - if ( myGetTransaction(bindtxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - CCerror = strprintf("cant find bindtxid %s",uint256_str(str,bindtxid)); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( DecodeImportGatewayBindOpRet(burnaddr,tx.vout[numvouts-1].scriptPubKey,coin,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2,wiftype) != 'B') - { - CCerror = strprintf("invalid bindtxid %s coin.%s",uint256_str(str,bindtxid),coin.c_str()); - LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); - return(""); - } - if ( myGetTransaction(bindtxid,tx,hashBlock) != 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("name","ImportGateway")); - burnaddr[0] = 0; - if ( tx.vout.size() > 0 && DecodeImportGatewayBindOpRet(burnaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,oracletxid,M,N,pubkeys,taddr,prefix,prefix2,wiftype) != 0 && M <= N && N > 0 ) - { - result.push_back(Pair("M",M)); - result.push_back(Pair("N",N)); - for (i=0; i payouts; std::vector rawproof; - if (!UnmarshalImportTx(importTx, proof, burnTx, payouts)) - throw std::runtime_error("Couldn't unmarshal importTx"); - - std::string targetSymbol; - uint32_t targetCCid; - uint256 payoutsHash; - if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) - throw std::runtime_error("Couldn't unmarshal burnTx"); - - TxProof merkleBranch; - if( !proof.IsMerkleBranch(merkleBranch) ) - throw std::runtime_error("Incorrect import tx proof"); - TxProof newMerkleBranch = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, merkleBranch, offset); - ImportProof newProof(newMerkleBranch); - - importTx = MakeImportCoinTransaction(newProof, burnTx, payouts); -} - bool IsSameAssetChain(const Notarization ¬a) { return strcmp(nota.second.symbol, SMART_CHAIN_SYMBOL) == 0; }; @@ -308,112 +282,6 @@ bool CheckMoMoM(uint256 hushNotarizationHash, uint256 momom) } -/* -* Check notaries approvals for the txoutproofs of burn tx -* (alternate check if MoMoM check has failed) -* Params: -* burntxid - txid of burn tx on the source chain -* rawproof - array of txids of notaries' proofs -*/ -bool CheckNotariesApproval(uint256 burntxid, const std::vector & notaryTxids) -{ - int count = 0; - - // get notaries: - uint8_t notaries_pubkeys[64][33]; - std::vector< std::vector > alreadySigned; - - //unmarshal notaries approval txids - for(auto notarytxid : notaryTxids ) { - EvalRef eval; - CBlockIndex block; - CTransaction notarytx; // tx with notary approval of txproof existence - - // get notary approval tx - if (eval->GetTxConfirmed(notarytxid, notarytx, block)) { - - std::vector vopret; - if (!notarytx.vout.empty() && GetOpReturnData(notarytx.vout.back().scriptPubKey, vopret)) { - std::vector txoutproof; - - if (E_UNMARSHAL(vopret, ss >> txoutproof)) { - CMerkleBlock merkleBlock; - std::vector prooftxids; - // extract block's merkle tree - if (E_UNMARSHAL(txoutproof, ss >> merkleBlock)) { - - // extract proven txids: - merkleBlock.txn.ExtractMatches(prooftxids); - if (merkleBlock.txn.ExtractMatches(prooftxids) != merkleBlock.header.hashMerkleRoot || // check block merkle root is correct - std::find(prooftxids.begin(), prooftxids.end(), burntxid) != prooftxids.end()) { // check burn txid is in proven txids list - - if (hush_notaries(notaries_pubkeys, block.GetHeight(), block.GetBlockTime()) >= 0) { - // check it is a notary who signed approved tx: - int i; - for (i = 0; i < sizeof(notaries_pubkeys) / sizeof(notaries_pubkeys[0]); i++) { - std::vector vnotarypubkey(notaries_pubkeys[i], notaries_pubkeys[i] + 33); -#ifdef TESTMODE - char test_notary_pubkey_hex[] = "029fa302968bbae81f41983d2ec20445557b889d31227caec5d910d19b7510ef86"; - uint8_t test_notary_pubkey33[33]; - decode_hex(test_notary_pubkey33, 33, test_notary_pubkey_hex); -#endif - if (CheckVinPubKey(notarytx, 0, notaries_pubkeys[i]) // is signed by a notary? - && std::find(alreadySigned.begin(), alreadySigned.end(), vnotarypubkey) == alreadySigned.end() // check if notary not re-used -#ifdef TESTMODE - || CheckVinPubKey(notarytx, 0, test_notary_pubkey33) // test -#endif - ) - { - alreadySigned.push_back(vnotarypubkey); - count++; - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "CheckNotariesApproval() notary approval checked, count=" << count << std::endl); - break; - } - } - if (i == sizeof(notaries_pubkeys) / sizeof(notaries_pubkeys[0])) - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "CheckNotariesApproval() txproof not signed by a notary or reused" << std::endl); - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() cannot get current notaries pubkeys" << std::endl); - } - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() burntxid not found in txoutproof or incorrect txoutproof" << std::endl); - } - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not unmarshal merkleBlock" << std::endl); - } - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not unmarshal txoutproof" << std::endl); - } - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() no opret in the notary tx" << std::endl); - } - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not load notary tx" << std::endl); - } - } - - bool retcode; -#ifdef TESTMODE - if (count < 1) { // 1 for test -#else - if (count < 5) { -#endif - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() not enough signed notary transactions=" << count << std::endl); - retcode = false; - } - else - retcode = true; - - return retcode; -} - - /* * On assetchain * in: txid diff --git a/src/crosschain.h b/src/crosschain.h index bbde384bc..af5096b6b 100644 --- a/src/crosschain.h +++ b/src/crosschain.h @@ -38,10 +38,8 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int hushHeig std::vector &moms, uint256 &destNotarizationTxid); TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid, const TxProof assetChainProof,int32_t offset); -void CompleteImportTransaction(CTransaction &importTx,int32_t offset); /* On assetchain */ bool CheckMoMoM(uint256 hushNotarizationHash, uint256 momom); -bool CheckNotariesApproval(uint256 burntxid, const std::vector & notaryTxids); #endif /* HUSH_CROSSCHAIN_H */ diff --git a/src/importcoin.cpp b/src/importcoin.cpp deleted file mode 100644 index 88e711e92..000000000 --- a/src/importcoin.cpp +++ /dev/null @@ -1,425 +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 "crosschain.h" -#include "importcoin.h" -#include "cc/utils.h" -#include "coins.h" -#include "hash.h" -#include "script/cc.h" -#include "primitives/transaction.h" -#include "core_io.h" -#include "script/sign.h" -#include "wallet/wallet.h" - -#include "cc/CCinclude.h" - -int32_t hush_nextheight(); - -// makes import tx for either coins or tokens -CTransaction MakeImportCoinTransaction(const ImportProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride) -{ - //std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN); - CScript scriptSig; - - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - if (mtx.fOverwintered) - mtx.nExpiryHeight = 0; - mtx.vout = payouts; - if (mtx.vout.size() == 0) - return CTransaction(mtx); - - // add special import tx vin: - scriptSig << E_MARSHAL(ss << EVAL_IMPORTCOIN); // simple payload for coins - mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), scriptSig)); - - if (nExpiryHeightOverride != 0) - mtx.nExpiryHeight = nExpiryHeightOverride; //this is for validation code, to make a tx used for validating the import tx - - auto importData = E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << proof; ss << burnTx); // added evalcode to differentiate importdata from token opret - // if it is tokens: - vscript_t vopret; - GetOpReturnData(mtx.vout.back().scriptPubKey, vopret); - - if (!vopret.empty()) { - std::vector vorigpubkey; - uint8_t funcId; - std::vector > oprets; - std::string name, desc; - - if (DecodeTokenCreateOpRet(mtx.vout.back().scriptPubKey, vorigpubkey, name, desc, oprets) == 'c') { // parse token 'c' opret - mtx.vout.pop_back(); //remove old token opret - oprets.push_back(std::make_pair(OPRETID_IMPORTDATA, importData)); - mtx.vout.push_back(CTxOut(0, EncodeTokenCreateOpRet('c', vorigpubkey, name, desc, oprets))); // make new token 'c' opret with importData - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeImportCoinTransaction() incorrect token import opret" << std::endl); - } - } - else { //no opret in coin payouts - mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << importData)); // import tx's opret now is in the vout's tail - } - - return CTransaction(mtx); -} - -CTransaction MakePegsImportCoinTransaction(const ImportProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride) -{ - CMutableTransaction mtx; uint256 accounttxid,pegstxid,tokenid; CScript opret; CScript scriptSig; - - mtx=MakeImportCoinTransaction(proof,burnTx,payouts); - // for spending markers in import tx - to track account state - accounttxid=burnTx.vin[0].prevout.hash; - mtx.vin.push_back(CTxIn(accounttxid,0,CScript())); - mtx.vin.push_back(CTxIn(accounttxid,1,CScript())); - return (mtx); -} - - -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string targetSymbol, const std::vector payouts, const std::vector rawproof) -{ - std::vector opret; - opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; // should mark burn opret to differentiate it from token opret - ss << VARINT(targetCCid); - ss << targetSymbol; - ss << SerializeHash(payouts); - ss << rawproof); - return CTxOut(value, CScript() << OP_RETURN << opret); -} - -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, - uint256 bindtxid,std::vector publishers,std::vector txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount) -{ - std::vector opret; - opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; - ss << VARINT(targetCCid); - ss << targetSymbol; - ss << SerializeHash(payouts); - ss << rawproof; - ss << bindtxid; - ss << publishers; - ss << txids; - ss << burntxid; - ss << height; - ss << burnvout; - ss << rawburntx; - ss << destpub; - ss << amount); - - return CTxOut(value, CScript() << OP_RETURN << opret); -} - -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof,std::string srcaddr, - std::string receipt) -{ - std::vector opret; - opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; - ss << VARINT(targetCCid); - ss << targetSymbol; - ss << SerializeHash(payouts); - ss << rawproof; - ss << srcaddr; - ss << receipt); - return CTxOut(value, CScript() << OP_RETURN << opret); -} - -CTxOut MakeBurnOutput(CAmount value,uint32_t targetCCid,std::string targetSymbol,const std::vector payouts,std::vector rawproof,uint256 pegstxid, - uint256 tokenid,CPubKey srcpub,int64_t amount,std::pair account) -{ - std::vector opret; - opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; - ss << VARINT(targetCCid); - ss << targetSymbol; - ss << SerializeHash(payouts); - ss << rawproof; - ss << pegstxid; - ss << tokenid; - ss << srcpub; - ss << amount; - ss << account); - return CTxOut(value, CScript() << OP_RETURN << opret); -} - - -bool UnmarshalImportTx(const CTransaction importTx, ImportProof &proof, CTransaction &burnTx, std::vector &payouts) -{ - if (importTx.vout.size() < 1) - return false; - - if ((!importTx.IsPegsImport() && importTx.vin.size() != 1) || importTx.vin[0].scriptSig != (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN))) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() incorrect import tx vin" << std::endl); - return false; - } - - std::vector vImportData; - GetOpReturnData(importTx.vout.back().scriptPubKey, vImportData); - if (vImportData.empty()) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() no opret" << std::endl); - return false; - } - - if (vImportData.begin()[0] == EVAL_TOKENS) { // if it is tokens - // get import data after token opret: - std::vector> oprets; - std::vector vorigpubkey; - std::string name, desc; - - if (DecodeTokenCreateOpRet(importTx.vout.back().scriptPubKey, vorigpubkey, name, desc, oprets) == 0) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() could not decode token opret" << std::endl); - return false; - } - - GetOpretBlob(oprets, OPRETID_IMPORTDATA, vImportData); // fetch import data after token opret - for (std::vector>::const_iterator i = oprets.begin(); i != oprets.end(); i++) - if ((*i).first == OPRETID_IMPORTDATA) { - oprets.erase(i); // remove import data from token opret to restore original payouts: - break; - } - - payouts = std::vector(importTx.vout.begin(), importTx.vout.end()-1); //exclude opret with import data - payouts.push_back(CTxOut(0, EncodeTokenCreateOpRet('c', vorigpubkey, name, desc, oprets))); // make original payouts token opret (without import data) - } - else { - //payouts = std::vector(importTx.vout.begin()+1, importTx.vout.end()); // see next - payouts = std::vector(importTx.vout.begin(), importTx.vout.end() - 1); // skip opret; and it is now in the back - } - - uint8_t evalCode; - bool retcode = E_UNMARSHAL(vImportData, ss >> evalCode; ss >> proof; ss >> burnTx); - if (!retcode) - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() could not unmarshal import data" << std::endl); - return retcode; -} - - -bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) -{ - std::vector vburnOpret; uint32_t ccid = 0; - uint8_t evalCode; - - if (burnTx.vout.size() == 0) - return false; - - GetOpReturnData(burnTx.vout.back().scriptPubKey, vburnOpret); - if (vburnOpret.empty()) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() cannot unmarshal burn tx: empty burn opret" << std::endl); - return false; - } - - if (vburnOpret.begin()[0] == EVAL_TOKENS) { //if it is tokens - std::vector> oprets; - uint256 tokenid; - uint8_t evalCodeInOpret; - std::vector voutTokenPubkeys; - - if (DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) != 't') - return false; - - //skip token opret: - GetOpretBlob(oprets, OPRETID_BURNDATA, vburnOpret); // fetch burnOpret after token opret - if (vburnOpret.empty()) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() cannot unmarshal token burn tx: empty burn opret for tokenid=" << tokenid.GetHex() << std::endl); - return false; - } - } - - if (vburnOpret.begin()[0] == EVAL_IMPORTCOIN) { - uint8_t evalCode; - bool isEof = true; - return E_UNMARSHAL(vburnOpret, ss >> evalCode; - ss >> VARINT(*targetCCid); - ss >> targetSymbol; - ss >> payoutsHash; - ss >> rawproof; isEof = ss.eof();) || !isEof; // if isEof == false it means we have successfully read the vars upto 'rawproof' - // and it might be additional data further that we do not need here so we allow !isEof - } - else { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() invalid eval code in opret" << std::endl); - return false; - } -} - -bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt) -{ - std::vector burnOpret,rawproof; bool isEof=true; - std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; - uint8_t evalCode; - - if (burnTx.vout.size() == 0) return false; - GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - return (E_UNMARSHAL(burnOpret, ss >> evalCode; - ss >> VARINT(targetCCid); - ss >> targetSymbol; - ss >> payoutsHash; - ss >> rawproof; - ss >> srcaddr; - ss >> receipt)); -} - -bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount) -{ - std::vector burnOpret,rawproof; bool isEof=true; - uint32_t targetCCid; uint256 payoutsHash; std::string targetSymbol; - uint8_t evalCode; - - if (burnTx.vout.size() == 0) return false; - GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - return (E_UNMARSHAL(burnOpret, ss >> evalCode; - ss >> VARINT(targetCCid); - ss >> targetSymbol; - ss >> payoutsHash; - ss >> rawproof; - ss >> bindtxid; - ss >> publishers; - ss >> txids; - ss >> burntxid; - ss >> height; - ss >> burnvout; - ss >> rawburntx; - ss >> destpub; - ss >> amount)); -} - -bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &pegstxid,uint256 &tokenid,CPubKey &srcpub, int64_t &amount,std::pair &account) -{ - std::vector burnOpret,rawproof; bool isEof=true; - uint32_t targetCCid; uint256 payoutsHash; std::string targetSymbol; - uint8_t evalCode; - - - if (burnTx.vout.size() == 0) return false; - GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - return (E_UNMARSHAL(burnOpret, ss >> evalCode; - ss >> VARINT(targetCCid); - ss >> targetSymbol; - ss >> payoutsHash; - ss >> rawproof; - ss >> pegstxid; - ss >> tokenid; - ss >> srcpub; - ss >> amount; - ss >> account)); -} - -/* - * Required by main - */ -CAmount GetCoinImportValue(const CTransaction &tx) -{ - ImportProof proof; CTransaction burnTx; std::vector payouts; - bool isNewImportTx = false; - - if ((isNewImportTx = UnmarshalImportTx(tx, proof, burnTx, payouts))) { - if (burnTx.vout.size() > 0) { - vscript_t vburnOpret; - - GetOpReturnData(burnTx.vout.back().scriptPubKey, vburnOpret); - if (vburnOpret.empty()) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetCoinImportValue() empty burn opret" << std::endl); - return 0; - } - - if (isNewImportTx && vburnOpret.begin()[0] == EVAL_TOKENS) { //if it is tokens - - uint8_t evalCodeInOpret; - uint256 tokenid; - std::vector voutTokenPubkeys; - std::vector> oprets; - - if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) == 0) - return 0; - - uint8_t nonfungibleEvalCode = EVAL_TOKENS; // init as if no non-fungibles - vscript_t vnonfungibleOpret; - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vnonfungibleOpret); - if (!vnonfungibleOpret.empty()) - nonfungibleEvalCode = vnonfungibleOpret.begin()[0]; - - // calc outputs for burn tx - int64_t ccBurnOutputs = 0; - for (auto v : burnTx.vout) - if (v.scriptPubKey.IsPayToCryptoCondition() && - CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(nonfungibleEvalCode, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey - ccBurnOutputs += v.nValue; - - return ccBurnOutputs + burnTx.vout.back().nValue; // total token burned value - } - else - return burnTx.vout.back().nValue; // coin burned value - } - } - return 0; -} - - - -/* - * CoinImport is different enough from normal script execution that it's not worth - * making all the mods neccesary in the interpreter to do the dispatch correctly. - */ -bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state) -{ - auto pc = scriptSig.begin(); - opcodetype opcode; - std::vector evalScript; - - auto f = [&] () { - if (!scriptSig.GetOp(pc, opcode, evalScript)) - return false; - if (pc != scriptSig.end()) - return false; - if (evalScript.size() == 0) - return false; - if (evalScript.begin()[0] != EVAL_IMPORTCOIN) - return false; - // Ok, all looks good so far... - CC *cond = CCNewEval(evalScript); - bool out = checker.CheckEvalCondition(cond); - cc_free(cond); - return out; - }; - - return f() ? true : state.Invalid(false, 0, "invalid-coin-import"); -} - - -void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, int nHeight) -{ - uint256 burnHash = importTx.vin[0].prevout.hash; - //fprintf(stderr,"add tombstone.(%s)\n",burnHash.GetHex().c_str()); - CCoinsModifier modifier = inputs.ModifyCoins(burnHash); - modifier->nHeight = nHeight; - modifier->nVersion = 4;//1; - modifier->vout.push_back(CTxOut(0, CScript() << OP_0)); -} - - -void RemoveImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs) -{ - uint256 burnHash = importTx.vin[0].prevout.hash; - //fprintf(stderr,"remove tombstone.(%s)\n",burnHash.GetHex().c_str()); - inputs.ModifyCoins(burnHash)->Clear(); -} - - -int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &inputs) -{ - uint256 burnHash = importTx.vin[0].prevout.hash; - //fprintf(stderr,"check tombstone.(%s) in %s\n",burnHash.GetHex().c_str(),importTx.GetHash().GetHex().c_str()); - return inputs.HaveCoins(burnHash); -} diff --git a/src/main.cpp b/src/main.cpp index 8cbb35efc..afb028115 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,6 @@ #include "sodium.h" #include "addrman.h" #include "arith_uint256.h" -#include "importcoin.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" @@ -1850,11 +1849,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return state.Invalid(false, REJECT_DUPLICATE, "already have coins"); } - if (tx.IsCoinImport() || tx.IsPegsImport()) { - // Inverse of normal case; if input exists, it's been spent - if (ExistsImportTombstone(tx, view)) - return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists"); - } else { + //if (tx.IsCoinImport() || tx.IsPegsImport()) { + // // Inverse of normal case; if input exists, it's been spent + // if (ExistsImportTombstone(tx, view)) + // return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists"); + //} else + { // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // and only helps with filling in pfMissingInputs (to determine missing vs spent). @@ -2599,10 +2599,10 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); // add outputs // Unorthodox state - if (tx.IsCoinImport() || tx.IsPegsImport()) { - // add a tombstone for the burnTx - AddImportTombstone(tx, inputs, nHeight); - } + //if (tx.IsCoinImport() || tx.IsPegsImport()) { + // // add a tombstone for the burnTx + // AddImportTombstone(tx, inputs, nHeight); + //} } void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) @@ -2643,11 +2643,13 @@ namespace Consensus { CAmount nFees = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) { + /* if (tx.IsPegsImport() && i==0) { nValueIn=GetCoinImportValue(tx); continue; } + */ const COutPoint &prevout = tx.vin[i].prevout; const CCoins *coins = inputs.AccessCoins(prevout.hash); assert(coins); @@ -2771,12 +2773,14 @@ bool ContextualCheckInputs( } } + /* if (tx.IsCoinImport() || tx.IsPegsImport()) { LOCK(cs_main); ServerTransactionSignatureChecker checker(&tx, 0, 0, false, txdata); return VerifyCoinImport(tx.vin[0].scriptSig, checker, state); } + */ return true; } @@ -3051,10 +3055,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } } } + /* else if (tx.IsCoinImport() || tx.IsPegsImport()) { RemoveImportTombstone(tx, view); } + */ } // set the old best Sprout anchor back diff --git a/src/miner.cpp b/src/miner.cpp index e258d8d38..456c2637a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -25,7 +25,6 @@ #include "amount.h" #include "chainparams.h" -#include "importcoin.h" #include "consensus/consensus.h" #include "consensus/upgrades.h" #include "consensus/validation.h" @@ -308,12 +307,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 bool fMissingInputs = false; bool fNotarization = false; std::vector TMP_NotarizationNotaries; - if (tx.IsCoinImport()) + //if (tx.IsCoinImport()) + //{ + // CAmount nValueIn = GetCoinImportValue(tx); // burn amount + // nTotalIn += nValueIn; + // dPriority += (double)nValueIn * 1000; // flat multiplier... max = 1e16. + //} else { - CAmount nValueIn = GetCoinImportValue(tx); // burn amount - nTotalIn += nValueIn; - dPriority += (double)nValueIn * 1000; // flat multiplier... max = 1e16. - } else { TMP_NotarizationNotaries.clear(); bool fToCryptoAddress = false; if ( numSN != 0 && notarypubkeys[0][0] != 0 && hush_is_notarytx(tx) == 1 ) @@ -321,6 +321,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 BOOST_FOREACH(const CTxIn& txin, tx.vin) { + /* if (tx.IsPegsImport() && txin.prevout.n==10e8) { CAmount nValueIn = GetCoinImportValue(tx); // burn amount @@ -328,6 +329,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 dPriority += (double)nValueIn * 1000; // flat multiplier... max = 1e16. continue; } + */ // Read prev transaction if (!view.HaveCoins(txin.prevout.hash)) { diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 1da0d5301..f66836eb0 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -711,7 +711,8 @@ public: bool IsPegsImport() const { - return (ASSETCHAINS_SELFIMPORT=="PEGSCC" && vin[0].prevout.n == 10e8); + //return (ASSETCHAINS_SELFIMPORT=="PEGSCC" && vin[0].prevout.n == 10e8); + return false; } friend bool operator==(const CTransaction& a, const CTransaction& b) diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index 0a8c0b129..aad84151e 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -178,348 +178,6 @@ UniValue calc_MoM(const UniValue& params, bool fHelp, const CPubKey& mypk) } -UniValue migrate_converttoexport(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - std::vector rawproof; uint8_t *ptr; uint8_t i; uint32_t ccid = ASSETCHAINS_CC; uint64_t txfee = 10000; - if (fHelp || params.size() != 2) - throw runtime_error( - "migrate_converttoexport rawTx dest_symbol\n" - "\nConvert a raw transaction to a cross-chain export.\n" - "If neccesary, the transaction should be funded using fundrawtransaction.\n" - "Finally, the transaction should be signed using signrawtransaction\n" - "The finished export transaction, plus the payouts, should be passed to " - "the \"migrate_createimporttransaction\" method to get the corresponding " - "import transaction.\n" - ); - - if (ASSETCHAINS_CC < HUSH_FIRSTFUNGIBLEID) - throw runtime_error("-ac_cc < HUSH_FIRSTFUNGIBLEID"); - - if (SMART_CHAIN_SYMBOL[0] == 0) - throw runtime_error("Must be called on assetchain"); - - vector txData(ParseHexV(params[0], "argument 1")); - CMutableTransaction tx; - if (!E_UNMARSHAL(txData, ss >> tx)) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - - string targetSymbol = params[1].get_str(); - if (targetSymbol.size() == 0 || targetSymbol.size() > 32) - throw runtime_error("targetSymbol length must be >0 and <=32"); - - if (strcmp(SMART_CHAIN_SYMBOL,targetSymbol.c_str()) == 0) - throw runtime_error("cant send a coin to the same chain"); - - /// Tested 44 vins p2pkh inputs as working. Set this at 25, but its a tx size limit. - // likely with a single RPC you can limit it by the size of tx. - if (tx.vout.size() > 25) - throw JSONRPCError(RPC_TYPE_ERROR, "Cannot have more than 50 vins, transaction too large."); - - CAmount burnAmount = 0; - - for (int i=0; i 1000000LL*COIN) - throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export."); - - /* note: we marshal to rawproof in a different way (to be able to add other objects) - rawproof.resize(strlen(SMART_CHAIN_SYMBOL)); - ptr = rawproof.data(); - for (i=0; i 32) - throw runtime_error("targetSymbol length must be >0 and <=32"); - - if (strcmp(SMART_CHAIN_SYMBOL, targetSymbol.c_str()) == 0) - throw runtime_error("cant send a coin to the same chain"); - - std::string dest_addr_or_pubkey = params[1].get_str(); - - CAmount burnAmount; - if(params.size() == 3) - burnAmount = (CAmount)( atof(params[2].get_str().c_str()) * COIN + 0.00000000499999 ); - else - burnAmount = atoll(params[2].get_str().c_str()); - - if (burnAmount <= 0) - throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export a negative or zero value."); - if (burnAmount > 1000000LL * COIN) - throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export."); - - uint256 tokenid = zeroid; - if( params.size() == 4 ) - tokenid = Parseuint256(params[3].get_str().c_str()); - - CPubKey myPubKey = Mypubkey(); - struct CCcontract_info *cpTokens, C; - cpTokens = CCinit(&C, EVAL_TOKENS); - - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - - const std::string chainSymbol(SMART_CHAIN_SYMBOL); - std::vector rawproof; //(chainSymbol.begin(), chainSymbol.end()); - - if (tokenid.IsNull()) { // coins - int64_t inputs; - if ((inputs = AddNormalinputs(mtx, myPubKey, burnAmount + txfee, 10)) == 0) { - throw runtime_error("not enough funds, or need to merge utxos first\n"); - } - - CTxDestination txdest = DecodeDestination(dest_addr_or_pubkey.c_str()); - CScript scriptPubKey = GetScriptForDestination(txdest); - if (!scriptPubKey.IsPayToPublicKeyHash()) { - throw JSONRPCError(RPC_TYPE_ERROR, "Incorrect destination addr."); - } - mtx.vout.push_back(CTxOut(burnAmount, scriptPubKey)); // 'model' vout - ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << mtx.vout)))); // save 'model' vout - - rawproof = E_MARSHAL(ss << chainSymbol); // add src chain name - - CTxOut burnOut = MakeBurnOutput(burnAmount+txfee, ccid, targetSymbol, mtx.vout, rawproof); //make opret with burned amount - - mtx.vout.clear(); // remove 'model' vout - - int64_t change = inputs - (burnAmount+txfee); - if (change != 0) - mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); // make change here to prevent it from making in FinalizeCCtx - - mtx.vout.push_back(burnOut); // mtx now has only burned vout (that is, amount sent to OP_RETURN making it unspendable) - //std::string exportTxHex = FinalizeCCTx(0, cpTokens, mtx, myPubKey, txfee, CScript()); // no change no opret - - } - else { // tokens - CTransaction tokenbasetx; - uint256 hashBlock; - vscript_t vopretNonfungible; - vscript_t vopretBurnData; - std::vector vorigpubkey, vdestpubkey; - std::string name, description; - std::vector> oprets; - - if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) - throw runtime_error("Could not load token creation tx\n"); - - // check if it is non-fungible tx and get its second evalcode from non-fungible payload - if (tokenbasetx.vout.size() == 0) - throw runtime_error("No vouts in token tx\n"); - - if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, description, oprets) != 'c') - throw runtime_error("Incorrect token creation tx\n"); - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - /* allow fungible tokens: - if (vopretNonfungible.empty()) - throw runtime_error("No non-fungible token data\n"); */ - - uint8_t destEvalCode = EVAL_TOKENS; - if (!vopretNonfungible.empty()) - destEvalCode = vopretNonfungible.begin()[0]; - - // check non-fungible tokens amount - if (!vopretNonfungible.empty() && burnAmount != 1) - throw JSONRPCError(RPC_TYPE_ERROR, "For non-fungible tokens amount should be equal to 1."); - - vdestpubkey = ParseHex(dest_addr_or_pubkey); - CPubKey destPubKey = pubkey2pk(vdestpubkey); - if (!destPubKey.IsValid()) - throw runtime_error("Invalid destination pubkey\n"); - - int64_t inputs; - if ((inputs = AddNormalinputs(mtx, myPubKey, txfee, 1)) == 0) // for miners in dest chain - throw runtime_error("No normal input found for two txfee\n"); - - int64_t ccInputs; - if ((ccInputs = AddTokenCCInputs(cpTokens, mtx, myPubKey, tokenid, burnAmount, 4)) < burnAmount) - throw runtime_error("No token inputs found (please try to consolidate tokens)\n"); - - // make payouts (which will be in the import tx with token): - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens, NULL))); // new marker to token cc addr, burnable and validated, vout position now changed to 0 (from 1) - mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, burnAmount, destPubKey)); - - std::vector> voprets; - if (!vopretNonfungible.empty()) - voprets.push_back(std::make_pair(OPRETID_NONFUNGIBLEDATA, vopretNonfungible)); // add additional opret with non-fungible data - - mtx.vout.push_back(CTxOut((CAmount)0, EncodeTokenCreateOpRet('c', vorigpubkey, name, description, voprets))); // make token import opret - ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << mtx.vout)))); // save payouts for import tx - - rawproof = E_MARSHAL(ss << chainSymbol << tokenbasetx); // add src chain name and token creation tx - - CTxOut burnOut = MakeBurnOutput(0, ccid, targetSymbol, mtx.vout, rawproof); //make opret with amount=0 because tokens are burned, not coins (see next vout) - mtx.vout.clear(); // remove payouts - - // now make burn transaction: - mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, burnAmount, pubkey2pk(ParseHex(CC_BURNPUBKEY)))); // burn tokens - - int64_t change = inputs - txfee; - if (change != 0) - mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); // make change here to prevent it from making in FinalizeCCtx - - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(pubkey2pk(ParseHex(CC_BURNPUBKEY))); // maybe we do not need this because ccTokens has the const for burn pubkey - - int64_t ccChange = ccInputs - burnAmount; - if (ccChange != 0) - mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, ccChange, myPubKey)); - - GetOpReturnData(burnOut.scriptPubKey, vopretBurnData); - mtx.vout.push_back(CTxOut(txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, std::make_pair(OPRETID_BURNDATA, vopretBurnData)))); //burn txfee for miners in dest chain - } - - std::string burnTxHex = FinalizeCCTx(0, cpTokens, mtx, myPubKey, txfee, CScript()); //no change, no opret - ret.push_back(Pair("BurnTxHex", burnTxHex)); - return ret; -} - -// util func to check burn tx and source chain params -void CheckBurnTxSource(uint256 burntxid, UniValue &info) { - - CTransaction burnTx; - uint256 blockHash; - - if (!myGetTransaction(burntxid, burnTx, blockHash)) - throw std::runtime_error("Cannot find burn transaction"); - - if (blockHash.IsNull()) - throw std::runtime_error("Burn tx still in mempool"); - - uint256 payoutsHash; - std::string targetSymbol; - uint32_t targetCCid; - std::vector rawproof; - - if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) - throw std::runtime_error("Cannot unmarshal burn tx data"); - - vscript_t vopret; - std::string sourceSymbol; - CTransaction tokenbasetxStored; - uint256 tokenid = zeroid; - - if (burnTx.vout.size() > 0 && GetOpReturnData(burnTx.vout.back().scriptPubKey, vopret) && !vopret.empty()) { - if (vopret.begin()[0] == EVAL_TOKENS) { - if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol; ss >> tokenbasetxStored)) - throw std::runtime_error("Cannot unmarshal rawproof for tokens"); - - uint8_t evalCode; - std::vector voutPubkeys; - std::vector> oprets; - if( DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCode, tokenid, voutPubkeys, oprets) == 0 ) - throw std::runtime_error("Cannot decode token opret in burn tx"); - - if( tokenid != tokenbasetxStored.GetHash() ) - throw std::runtime_error("Incorrect tokenbase in burn tx"); - - CTransaction tokenbasetx; - uint256 hashBlock; - if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) { - throw std::runtime_error("Could not load tokenbase tx"); - } - - // check if nonfungible data present - if (tokenbasetx.vout.size() > 0) { - std::vector origpubkey; - std::string name, description; - std::vector> oprets; - - vscript_t vopretNonfungible; - if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, oprets) == 'c') { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - if (vopretNonfungible.empty()) - throw std::runtime_error("Could not migrate fungible tokens"); - } - else - throw std::runtime_error("Could not decode opreturn in tokenbase tx"); - } - else - throw std::runtime_error("Incorrect tokenbase tx: not opreturn"); - - - struct CCcontract_info *cpTokens, CCtokens_info; - cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS); - int64_t ccInputs = 0, ccOutputs = 0; - if( !TokensExactAmounts(true, cpTokens, ccInputs, ccOutputs, NULL, burnTx, tokenid) ) - throw std::runtime_error("Incorrect token burn tx: cc inputs <> cc outputs"); - } - else if (vopret.begin()[0] == EVAL_IMPORTCOIN) { - if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol)) - throw std::runtime_error("Cannot unmarshal rawproof for coins"); - } - else - throw std::runtime_error("Incorrect eval code in opreturn"); - } - else - throw std::runtime_error("No opreturn in burn tx"); - - - if (sourceSymbol != SMART_CHAIN_SYMBOL) - throw std::runtime_error("Incorrect source chain in rawproof"); - - if (targetCCid != ASSETCHAINS_CC) - throw std::runtime_error("Incorrect CCid in burn tx"); - - if (targetSymbol == SMART_CHAIN_SYMBOL) - throw std::runtime_error("Must not be called on the destination chain"); - - // fill info to return for the notary operator (if manual notarization) or user - info.push_back(Pair("SourceSymbol", sourceSymbol)); - info.push_back(Pair("TargetSymbol", targetSymbol)); - info.push_back(Pair("TargetCCid", std::to_string(targetCCid))); - if (!tokenid.IsNull()) - info.push_back(Pair("tokenid", tokenid.GetHex())); - -} - /* * The process to migrate funds from a chain to chain * @@ -537,590 +195,8 @@ void CheckBurnTxSource(uint256 burntxid, UniValue &info) { * 3. migrate_completeimporttransaction */ -UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp || params.size() < 2) - throw runtime_error("migrate_createimporttransaction burnTx payouts [notarytxid-1]..[notarytxid-N]\n\n" - "Create an importTx given a burnTx and the corresponding payouts, hex encoded\n" - "optional notarytxids are txids of notary operator proofs of burn tx existense (from destination chain).\n" - "Do not make subsequent call to migrate_completeimporttransaction if notary txids are set"); - - if (ASSETCHAINS_CC < HUSH_FIRSTFUNGIBLEID) - throw runtime_error("-ac_cc < HUSH_FIRSTFUNGIBLEID"); - - if (SMART_CHAIN_SYMBOL[0] == 0) - throw runtime_error("Must be called on assetchain"); - - vector txData(ParseHexV(params[0], "argument 1")); - - CTransaction burnTx; - if (!E_UNMARSHAL(txData, ss >> burnTx)) - throw runtime_error("Couldn't parse burnTx"); - - if( burnTx.vin.size() == 0 ) - throw runtime_error("No vins in the burnTx"); - - if (burnTx.vout.size() == 0) - throw runtime_error("No vouts in the burnTx"); - - - vector payouts; - if (!E_UNMARSHAL(ParseHexV(params[1], "argument 2"), ss >> payouts)) - throw runtime_error("Couldn't parse payouts"); - - ImportProof importProof; - if (params.size() == 2) { // standard MoMoM based notarization - // get MoM import proof - importProof = ImportProof(GetAssetchainProof(burnTx.GetHash(), burnTx)); - } - else { // notarization by manual operators notary tx - UniValue info(UniValue::VOBJ); - CheckBurnTxSource(burnTx.GetHash(), info); - - // get notary import proof - std::vector notaryTxids; - for (int i = 2; i < params.size(); i++) { - uint256 txid = Parseuint256(params[i].get_str().c_str()); - if (txid.IsNull()) - throw runtime_error("Incorrect notary approval txid"); - notaryTxids.push_back(txid); - } - importProof = ImportProof(notaryTxids); - } - - CTransaction importTx = MakeImportCoinTransaction(importProof, burnTx, payouts); - - std::string importTxHex = HexStr(E_MARSHAL(ss << importTx)); - UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("ImportTxHex", importTxHex)); - return ret; -} - -UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error("migrate_completeimporttransaction importTx [offset]\n\n" - "Takes a cross chain import tx with proof generated on assetchain " - "and extends proof to target chain proof root\n" - "offset is optional, use it to increase the used HUSH height, use when import fails."); - - if (SMART_CHAIN_SYMBOL[0] != 0) - throw runtime_error("Must be called on HUSH"); - - CTransaction importTx; - if (!E_UNMARSHAL(ParseHexV(params[0], "argument 1"), ss >> importTx)) - throw runtime_error("Couldn't parse importTx"); - - int32_t offset = 0; - if ( params.size() == 2 ) - offset = params[1].get_int(); - - CompleteImportTransaction(importTx, offset); - - std::string importTxHex = HexStr(E_MARSHAL(ss << importTx)); - UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("ImportTxHex", importTxHex)); - return ret; -} - -/* -* Alternate coin migration solution if MoMoM migration has failed -* -* The workflow: -* On the source chain user calls migrate_createburntransaction, sends the burn tx to the chain and sends its txid and the source chain name to the notary operators (off-chain) -* the notary operators call migrate_checkburntransactionsource on the source chain -* on the destination chain the notary operators call migrate_createnotaryapprovaltransaction and pass the burn txid and txoutproof received from the previous call, -* the notary operators send the approval transactions to the chain and send their txids to the user (off-chain) -* on the source chain the user calls migrate_createimporttransaction and passes to it notary txids as additional parameters -* then the user sends the import transaction to the destination chain (where the notary approvals will be validated) -*/ - -// checks if burn tx exists and params stored in the burn tx match to the source chain -// returns txproof -// run it on the source chain -UniValue migrate_checkburntransactionsource(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp || params.size() != 1) - throw runtime_error("migrate_checkburntransactionsource burntxid\n\n" - "checks if params stored in the burn tx match to its tx chain"); - - if (SMART_CHAIN_SYMBOL[0] == 0) - throw runtime_error("Must be called on asset chain"); - - uint256 burntxid = Parseuint256(params[0].get_str().c_str()); - UniValue result(UniValue::VOBJ); - CheckBurnTxSource(burntxid, result); // check and get burn tx data - - // get tx proof for burn tx - UniValue nextparams(UniValue::VARR); - UniValue txids(UniValue::VARR); - txids.push_back(burntxid.GetHex()); - nextparams.push_back(txids); - result.push_back(Pair("TxOutProof", gettxoutproof(nextparams, false, mypk))); // get txoutproof - result.push_back(Pair("result", "success")); // get txoutproof - - return result; -} - -// creates a tx for the dest chain with txproof -// used as a momom-backup manual import solution -// run it on the dest chain -UniValue migrate_createnotaryapprovaltransaction(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp || params.size() != 2) - throw runtime_error("migrate_createnotaryapprovaltransaction burntxid txoutproof\n\n" - "Creates a tx for destination chain with burn tx proof\n" - "txoutproof should be retrieved by hush-cli migrate_checkburntransactionsource call on the source chain\n" ); - - if (SMART_CHAIN_SYMBOL[0] == 0) - throw runtime_error("Must be called on asset chain"); - - uint256 burntxid = Parseuint256(params[0].get_str().c_str()); - if (burntxid.IsNull()) - throw runtime_error("Couldn't parse burntxid or it is null"); - - std::vector proofData = ParseHex(params[1].get_str()); - CMerkleBlock merkleBlock; - std::vector prooftxids; - if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) - throw runtime_error("Couldn't parse txoutproof"); - - merkleBlock.txn.ExtractMatches(prooftxids); - if (std::find(prooftxids.begin(), prooftxids.end(), burntxid) == prooftxids.end()) - throw runtime_error("No burntxid in txoutproof"); - - const int64_t txfee = 10000; - struct CCcontract_info *cpDummy, C; - cpDummy = CCinit(&C, EVAL_TOKENS); // just for FinalizeCCtx to work - - // creating a tx with proof: - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - if (AddNormalinputs(mtx, Mypubkey(), txfee*2, 4) == 0) - throw runtime_error("Cannot find normal inputs\n"); - - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(Mypubkey())) << OP_CHECKSIG)); - std::string notaryTxHex = FinalizeCCTx(0, cpDummy, mtx, Mypubkey(), txfee, CScript() << OP_RETURN << E_MARSHAL(ss << proofData;)); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("NotaryTxHex", notaryTxHex)); - return result; -} - -// creates a source 'quasi-burn' tx for AC_PUBKEY -// run it on the same asset chain -UniValue selfimport(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - std::string destaddr; - std::string source; - std::string sourceTxHex; - std::string importTxHex; - CTransaction burnTx; - CTxOut burnOut; - uint64_t burnAmount; - uint256 sourcetxid, blockHash; - std::vector vouts; - std::vector rawproof; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("selfimport only works on -ac_import chains"); - - if (fHelp || params.size() != 2) - throw runtime_error("selfimport destaddr amount\n" - //TODO: "or selfimport rawburntx burntxid {nvout|\"find\"} rawproof source bindtxid height} \n" - "\ncreates self import coin transaction"); - - destaddr = params[0].get_str(); - burnAmount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999; - - source = ASSETCHAINS_SELFIMPORT; //defaults to -ac_import=... param - - if (source == "BEAM") - { - if (ASSETCHAINS_BEAMPORT == 0) - return(-1); - // confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn - // return(0); - return -1; - } - else if (source == "CODA") - { - if (ASSETCHAINS_CODAPORT == 0) - return(-1); - // confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn - // return(0); - return -1; - } - else if (source == "PEGSCC") - { - return -1; - } - else if (source == "PUBKEY") - { - ImportProof proofNull; - CTxDestination dest = DecodeDestination(destaddr.c_str()); - CMutableTransaction sourceMtx = MakeSelfImportSourceTx(dest, burnAmount); // make self-import source tx - vscript_t rawProofEmpty; - - CMutableTransaction templateMtx; - // prepare self-import 'quasi-burn' tx and also create vout for import tx (in mtx.vout): - if (GetSelfimportProof(sourceMtx, templateMtx, proofNull) < 0) - throw std::runtime_error("Failed creating selfimport template tx"); - - vouts = templateMtx.vout; - burnOut = MakeBurnOutput(burnAmount, 0xffffffff, ASSETCHAINS_SELFIMPORT, vouts, rawProofEmpty); - templateMtx.vout.clear(); - templateMtx.vout.push_back(burnOut); // burn tx has only opret with vouts and optional proof - - burnTx = templateMtx; // complete the creation of 'quasi-burn' tx - - sourceTxHex = HexStr(E_MARSHAL(ss << sourceMtx)); - importTxHex = HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proofNull, burnTx, vouts))); - - result.push_back(Pair("SourceTxHex", sourceTxHex)); - result.push_back(Pair("ImportTxHex", importTxHex)); - - return result; - } - else if (source == ASSETCHAINS_SELFIMPORT) - { - return -1; - } - return result; -} - bool GetNotarizationNotaries(uint8_t notarypubkeys[64][33], int8_t &numNN, const std::vector &vin, std::vector &NotarizationNotaries); - -UniValue importdual(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx; - std::string hex,source,sourceaddr,destaddr,burntxid; uint64_t burnAmount; - CPubKey destpub; std::vector vouts; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importdual only works on -ac_import chains"); - - if (fHelp || params.size() < 4) - throw runtime_error("burntxid source_addr dest_pubkey amount\n"); - - CCerror = ""; - - burntxid = params[0].get_str(); - sourceaddr = params[1].get_str(); - destaddr = params[2].get_str(); - burnAmount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999; - - source = ASSETCHAINS_SELFIMPORT; //defaults to -ac_import=... param - - CTxDestination dest = DecodeDestination(destaddr.c_str()); - CScript scriptPubKey = GetScriptForDestination(dest); - vouts.push_back(CTxOut(burnAmount,scriptPubKey)); - - if (source == "BEAM") - { - if (ASSETCHAINS_BEAMPORT == 0) - return(-1); - // confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn - // return(0); - return -1; - } - else if (source == "CODA") - { - if (ASSETCHAINS_CODAPORT == 0) - return(-1); - hex=MakeCodaImportTx(0,burntxid,sourceaddr,vouts); - // confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn - // return(0); - } - else if (source == "PEGSCC") - { - return -1; - } - RETURN_IF_ERROR(CCerror); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt importdual"); - return result; -} - -UniValue importgatewayinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 txid; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importgatewaybind only works on -ac_import chains"); - if ( fHelp || params.size() != 1 ) - throw runtime_error("importgatewayinfo bindtxid\n"); - txid = Parseuint256(params[0].get_str().c_str()); - return(ImportGatewayInfo(txid)); -} - - -UniValue importgatewaybind(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx; std::vector pubkey; - std::string hex,coin; int32_t i,M,N; std::vector pubkeys; - uint256 oracletxid; uint8_t p1,p2,p3,p4; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importgatewaybind only works on -ac_import chains"); - if ( fHelp || params.size() != 8) - throw runtime_error("use \'importgatewaybind coin orcletxid M N pubkeys pubtype p2shtype wiftype [taddr]\' to bind an import gateway\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - CCerror = ""; - coin = params[0].get_str(); - oracletxid = Parseuint256(params[1].get_str().c_str()); - M = atoi(params[2].get_str().c_str()); - N = atoi(params[3].get_str().c_str()); - if ( M > N || N == 0 || N > 15 ) - throw runtime_error("illegal M or N > 15\n"); - if ( params.size() < 4+N+3 ) - throw runtime_error("not enough parameters for N pubkeys\n"); - for (i=0; i 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt importgatewaybind"); - return result; -} - -UniValue importgatewaydeposit(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx; std::vector rawproof; - std::string hex,coin,rawburntx; int32_t height,burnvout; int64_t amount; - CPubKey destpub; std::vector vouts; uint256 bindtxid,burntxid; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importgatewaydeposit only works on -ac_import chains"); - if ( fHelp || params.size() != 9) - throw runtime_error("use \'importgatewaydeposit bindtxid height coin burntxid nvout rawburntx rawproof destpub amount\' to import deposited coins\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - CCerror = ""; - bindtxid = Parseuint256(params[0].get_str().c_str()); - height = atoi(params[1].get_str().c_str()); - coin = params[2].get_str(); - burntxid = Parseuint256(params[3].get_str().c_str()); - burnvout = atoi(params[4].get_str().c_str()); - rawburntx = params[5].get_str(); - rawproof = ParseHex(params[6].get_str()); - destpub = ParseHex(params[7].get_str()); - amount = atof(params[8].get_str().c_str()) * COIN + 0.00000000499999; - if (coin == "BEAM" || coin == "CODA") - { - ERR_RESULT("for BEAM and CODA import use importdual RPC"); - return result; - } - else if (coin != ASSETCHAINS_SELFIMPORT) - { - ERR_RESULT("source coin not equal to ac_import name"); - return result; - } - hex = ImportGatewayDeposit(0, bindtxid, height, coin, burntxid, burnvout, rawburntx, rawproof, destpub, amount); - RETURN_IF_ERROR(CCerror); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt importgatewaydeposit"); - return result; -} - -UniValue importgatewaywithdraw(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - CMutableTransaction mtx; std::vector rawproof; - std::string hex,coin,rawburntx; int64_t amount; int32_t height,burnvout; - CPubKey destpub; std::vector vouts; uint256 bindtxid,burntxid; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importgatewaywithdraw only works on -ac_import chains"); - if ( fHelp || params.size() != 4) - throw runtime_error("use \'importgatewaywithdraw bindtxid coin withdrawpub amount\' to burn imported coins and withdraw them on external chain\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - CCerror = ""; - bindtxid = Parseuint256(params[0].get_str().c_str()); - coin = params[1].get_str(); - destpub = ParseHex(params[2].get_str()); - amount = atof((char *)params[3].get_str().c_str()) * COIN + 0.00000000499999; - if (coin == "BEAM" || coin == "CODA") - { - ERR_RESULT("for BEAM and CODA import use importdual RPC"); - return result; - } - else if (coin != ASSETCHAINS_SELFIMPORT) - { - ERR_RESULT("source coin not equal to ac_import name"); - return result; - } - hex = ImportGatewayWithdraw(0, bindtxid, coin, destpub, amount); - RETURN_IF_ERROR(CCerror); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt importgatewaywithdraw"); - return result; -} - -UniValue importgatewaypartialsign(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); std::string coin,parthex,hex; uint256 txid; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importgatewayspartialsign only works on -ac_import chains"); - if ( fHelp || params.size() != 3 ) - throw runtime_error("importgatewayspartialsign txidaddr refcoin hex\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - txid = Parseuint256((char *)params[0].get_str().c_str()); - coin = params[1].get_str(); - parthex = params[2].get_str(); - hex = ImportGatewayPartialSign(0,txid,coin,parthex); - RETURN_IF_ERROR(CCerror); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex",hex)); - } else ERR_RESULT("couldnt importgatewayspartialsign"); - return(result); -} - -UniValue importgatewaycompletesigning(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); uint256 withdrawtxid; std::string txhex,hex,coin; - - if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) - throw runtime_error("importgatewaycompletesigning only works on -ac_import chains"); - if ( fHelp || params.size() != 3 ) - throw runtime_error("importgatewaycompletesigning withdrawtxid coin hex\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - withdrawtxid = Parseuint256((char *)params[0].get_str().c_str()); - coin = params[1].get_str(); - txhex = params[2].get_str(); - hex = ImportGatewayCompleteSigning(0,withdrawtxid,coin,txhex); - RETURN_IF_ERROR(CCerror); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt importgatewaycompletesigning"); - return(result); -} - -UniValue importgatewaymarkdone(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); uint256 completetxid; std::string hex,coin; - if ( fHelp || params.size() != 2 ) - throw runtime_error("importgatewaymarkdone completesigningtx coin\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - completetxid = Parseuint256((char *)params[0].get_str().c_str()); - coin = params[1].get_str(); - hex = ImportGatewayMarkDone(0,completetxid,coin); - RETURN_IF_ERROR(CCerror); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt importgatewaymarkdone"); - return(result); -} - -UniValue importgatewaypendingwithdraws(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 bindtxid; std::string coin; - if ( fHelp || params.size() != 2 ) - throw runtime_error("importgatewaypendingwithdraws bindtxid coin\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - bindtxid = Parseuint256((char *)params[0].get_str().c_str()); - coin = params[1].get_str(); - return(ImportGatewayPendingWithdraws(bindtxid,coin)); -} - -UniValue importgatewayprocessed(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 bindtxid; std::string coin; - if ( fHelp || params.size() != 2 ) - throw runtime_error("importgatewayprocessed bindtxid coin\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - bindtxid = Parseuint256((char *)params[0].get_str().c_str()); - coin = params[1].get_str(); - return(ImportGatewayProcessedWithdraws(bindtxid,coin)); -} - -UniValue importgatewayexternaladdress(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 bindtxid; CPubKey pubkey; - - if ( fHelp || params.size() != 2) - throw runtime_error("importgatewayexternaladdress bindtxid pubkey\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - bindtxid = Parseuint256((char *)params[0].get_str().c_str()); - pubkey = ParseHex(params[1].get_str().c_str()); - return(ImportGatewayExternalAddress(bindtxid,pubkey)); -} - -UniValue importgatewaydumpprivkey(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 bindtxid; - - if ( fHelp || params.size() != 2) - throw runtime_error("importgatewaydumpprivkey bindtxid address\n"); - if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - bindtxid = Parseuint256((char *)params[0].get_str().c_str()); - std::string strAddress = params[1].get_str(); - CTxDestination dest = DecodeDestination(strAddress); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid transparent address"); - } - const CKeyID *keyID = boost::get(&dest); - if (!keyID) { - throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); - } - CKey vchSecret; - // if (!pwalletMain->GetKey(*keyID, vchSecret)) { - // throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); - //} - return(ImportGatewayDumpPrivKey(bindtxid,vchSecret)); -} - UniValue getNotarizationsForBlock(const UniValue& params, bool fHelp, const CPubKey& mypk) { // TODO take timestamp as param, and loop blockindex to get starting/finish height. @@ -1195,264 +271,3 @@ UniValue scanNotarizationsDB(const UniValue& params, bool fHelp, const CPubKey& out.pushKV("opreturn", HexStr(E_MARSHAL(ss << nota.second))); return out; } - -UniValue getimports(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getimports \"hash|height\"\n" - "\n\n" - "\nResult:\n" - "{\n" - " \"imports\" : [ (json array)\n" - " \"transactionid\" : { (json object)\n" - " \"value\" : (numeric)\n" - " \"address\" : (string)\n" - " \"export\" { (json object)\n" - " \"txid\" : (string)\n" - " \"value\" : (numeric)\n" - " \"chain\" : (string)\n" - " }\n" - " }" - " ]\n" - " \"TotalImported\" : (numeric)\n" - " \"time\" : (numeric)\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getimports", "\"00000000febc373a1da2bd9f887b105ad79ddc26ac26c2b28652d64e5207c5b5\"") - + HelpExampleRpc("getimports", "\"00000000febc373a1da2bd9f887b105ad79ddc26ac26c2b28652d64e5207c5b5\"") - + HelpExampleCli("getimports", "12800") - + HelpExampleRpc("getimports", "12800") - ); - - LOCK(cs_main); - - std::string strHash = params[0].get_str(); - - // If height is supplied, find the hash - if (strHash.size() < (2 * sizeof(uint256))) { - // std::stoi allows characters, whereas we want to be strict - regex r("[[:digit:]]+"); - if (!regex_match(strHash, r)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); - } - - int nHeight = -1; - try { - nHeight = std::stoi(strHash); - } - catch (const std::exception &e) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); - } - - if (nHeight < 0 || nHeight > chainActive.Height()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - } - strHash = chainActive[nHeight]->GetBlockHash().GetHex(); - } - - uint256 hash(uint256S(strHash)); - - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; - - if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - - if(!ReadBlockFromDisk(block, pblockindex,1)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - - UniValue result(UniValue::VOBJ); - CAmount TotalImported = 0; - UniValue imports(UniValue::VARR); - BOOST_FOREACH(const CTransaction&tx, block.vtx) - { - if(tx.IsCoinImport()) - { - UniValue objTx(UniValue::VOBJ); - objTx.push_back(Pair("txid",tx.GetHash().ToString())); - ImportProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; - TotalImported += tx.vout[0].nValue; // were vouts swapped? - objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[1].nValue))); - if (ExtractDestination(tx.vout[1].scriptPubKey, importaddress)) - { - objTx.push_back(Pair("address", CBitcoinAddress(importaddress).ToString())); - } - UniValue objBurnTx(UniValue::VOBJ); - CPubKey vinPubkey; - if (UnmarshalImportTx(tx, proof, burnTx, payouts)) - { - if (burnTx.vout.size() == 0) - continue; - objBurnTx.push_back(Pair("txid", burnTx.GetHash().ToString())); - objBurnTx.push_back(Pair("amount", ValueFromAmount(burnTx.vout.back().nValue))); - // extract op_return to get burn source chain. - std::vector burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vectorrawproof; - if (UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) - { - if (rawproof.size() > 0) - { - std::string sourceSymbol; - CTransaction tokenbasetx; - E_UNMARSHAL(rawproof, ss >> sourceSymbol; - if (!ss.eof()) - ss >> tokenbasetx ); - objBurnTx.push_back(Pair("source", sourceSymbol)); - if( !tokenbasetx.IsNull() ) - objBurnTx.push_back(Pair("tokenid", tokenbasetx.GetHash().GetHex())); - } - } - } - objTx.push_back(Pair("export", objBurnTx)); - imports.push_back(objTx); - } - } - result.push_back(Pair("imports", imports)); - result.push_back(Pair("TotalImported", TotalImported > 0 ? ValueFromAmount(TotalImported) : 0 )); - result.push_back(Pair("time", block.GetBlockTime())); - return result; -} - - -// outputs burn transactions in the wallet -UniValue getwalletburntransactions(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getwalletburntransactions \"count\"\n\n" - "Lists most recent wallet burn transactions up to \'count\' parameter\n" - "parameter \'count\' is optional. If omitted, defaults to 10 burn transactions" - "\n\n" - "\nResult:\n" - "[\n" - " {\n" - " \"txid\": (string)\n" - " \"burnedAmount\" : (numeric)\n" - " \"targetSymbol\" : (string)\n" - " \"targetCCid\" : (numeric)\n" - " }\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("getwalletburntransactions", "100") - + HelpExampleRpc("getwalletburntransactions", "100") - + HelpExampleCli("getwalletburntransactions", "") - + HelpExampleRpc("getwalletburntransactions", "") - ); - - if (!EnsureWalletIsAvailable(fHelp)) - return NullUniValue; - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strAccount = "*"; - isminefilter filter = ISMINE_SPENDABLE; - int nCount = 10; - - if (params.size() == 1) - nCount = atoi(params[0].get_str()); - if (nCount < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); - - UniValue ret(UniValue::VARR); - - std::list acentries; - CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); - - // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) - { - CWalletTx *const pwtx = (*it).second.first; - if (pwtx != 0) - { - LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "pwtx iterpos=" << (int32_t)pwtx->nOrderPos << " txid=" << pwtx->GetHash().GetHex() << std::endl); - vscript_t vopret; - std::string targetSymbol; - uint32_t targetCCid; uint256 payoutsHash; - std::vector rawproof; - - if (pwtx->vout.size() > 0 && GetOpReturnData(pwtx->vout.back().scriptPubKey, vopret) && !vopret.empty() && - UnmarshalBurnTx(*pwtx, targetSymbol, &targetCCid, payoutsHash, rawproof)) { - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", pwtx->GetHash().GetHex())); - - if (vopret.begin()[0] == EVAL_TOKENS) { - // get burned token value - std::vector> oprets; - uint256 tokenid; - uint8_t evalCodeInOpret; - std::vector voutTokenPubkeys; - - //skip token opret: - if (DecodeTokenOpRet(pwtx->vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) != 0) { - CTransaction tokenbasetx; - uint256 hashBlock; - - if (myGetTransaction(tokenid, tokenbasetx, hashBlock)) { - std::vector vorigpubkey; - std::string name, description; - std::vector> oprets; - - if (tokenbasetx.vout.size() > 0 && - DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, description, oprets) == 'c') - { - uint8_t destEvalCode = EVAL_TOKENS; // init set to fungible token: - vscript_t vopretNonfungible; - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - if (!vopretNonfungible.empty()) - destEvalCode = vopretNonfungible.begin()[0]; - - int64_t burnAmount = 0; - for (auto v : pwtx->vout) - if (v.scriptPubKey.IsPayToCryptoCondition() && - CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(destEvalCode ? destEvalCode : EVAL_TOKENS, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey - burnAmount += v.nValue; - - entry.push_back(Pair("burnedAmount", ValueFromAmount(burnAmount))); - entry.push_back(Pair("tokenid", tokenid.GetHex())); - } - } - } - } - else - entry.push_back(Pair("burnedAmount", ValueFromAmount(pwtx->vout.back().nValue))); // coins - - // check for corrupted strings (look for non-printable chars) from some older versions - // which caused "couldn't parse reply from server" error on client: - if (std::find_if(targetSymbol.begin(), targetSymbol.end(), [](int c) {return !std::isprint(c);}) != targetSymbol.end()) - targetSymbol = ""; - - entry.push_back(Pair("targetSymbol", targetSymbol)); - entry.push_back(Pair("targetCCid", std::to_string(targetCCid))); - if (mytxid_inmempool(pwtx->GetHash())) - entry.push_back(Pair("inMempool", "yes")); - ret.push_back(entry); - } - } //else fprintf(stderr,"null pwtx\n - if ((int)ret.size() >= (nCount)) - break; - } - // ret is newest to oldest - - if (nCount > (int)ret.size()) - nCount = ret.size(); - - vector arrTmp = ret.getValues(); - - vector::iterator first = arrTmp.begin(); - vector::iterator last = arrTmp.begin(); - std::advance(last, nCount); - - if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); - if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first); - - std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest - - ret.clear(); - ret.setArray(); - ret.push_backV(arrTmp); - - return ret; -} diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index a9a27ad8d..23890479f 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -144,9 +144,10 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& UniValue vin(UniValue::VARR); BOOST_FOREACH(const CTxIn& txin, tx.vin) { UniValue in(UniValue::VOBJ); - if (tx.IsCoinBase()) + if (tx.IsCoinBase()) { in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - else if (tx.IsCoinImport() && txin.prevout.n==10e8) { + } + /* else if (tx.IsCoinImport() && txin.prevout.n==10e8) { in.push_back(Pair("is_import", "1")); ImportProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; if (UnmarshalImportTx(tx, proof, burnTx, payouts)) @@ -168,7 +169,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& } } } - } + } */ else { in.push_back(Pair("txid", txin.prevout.hash.GetHex())); in.push_back(Pair("vout", (int64_t)txin.prevout.n)); @@ -216,6 +217,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& out.push_back(Pair("n", (int64_t)i)); UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(txout.scriptPubKey, o, true); + /* if (txout.scriptPubKey.IsOpReturn() && txout.nValue != 0) { std::vector burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vectorrawproof; @@ -224,6 +226,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& out.push_back(Pair("target", "EXPORT->" + targetSymbol)); } } + */ out.push_back(Pair("scriptPubKey", o)); // Add spent information if spentindex is enabled diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index bde315159..25d64a288 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -346,16 +346,6 @@ static const CRPCCommand vRPCCommands[] = { "crosschain", "crosschainproof", &crosschainproof, true }, { "crosschain", "getNotarizationsForBlock", &getNotarizationsForBlock, true }, { "crosschain", "scanNotarizationsDB", &scanNotarizationsDB, true }, - { "crosschain", "getimports", &getimports, true }, - { "crosschain", "getwalletburntransactions", &getwalletburntransactions, true }, - { "crosschain", "migrate_converttoexport", &migrate_converttoexport, true }, - { "crosschain", "migrate_createburntransaction", &migrate_createburntransaction, true }, - { "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true }, - { "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true }, - { "crosschain", "migrate_checkburntransactionsource", &migrate_checkburntransactionsource, true }, - { "crosschain", "migrate_createnotaryapprovaltransaction", &migrate_createnotaryapprovaltransaction, true }, - { "crosschain", "selfimport", &selfimport, true }, - { "crosschain", "importdual", &importdual, true }, /* Mining */ { "mining", "getblocktemplate", &getblocktemplate, true }, @@ -443,26 +433,6 @@ static const CRPCCommand vRPCCommands[] = { "CClib", "cclibinfo", &cclibinfo, true }, { "CClib", "cclib", &cclib, true }, - // tokens & assets - { "tokens", "assetsaddress", &assetsaddress, true }, - { "tokens", "tokeninfo", &tokeninfo, true }, - { "tokens", "tokenlist", &tokenlist, true }, - { "tokens", "tokenorders", &tokenorders, true }, - { "tokens", "mytokenorders", &mytokenorders, true }, - { "tokens", "tokenaddress", &tokenaddress, true }, - { "tokens", "tokenbalance", &tokenbalance, true }, - { "tokens", "tokencreate", &tokencreate, true }, - { "tokens", "tokentransfer", &tokentransfer, true }, - { "tokens", "tokenbid", &tokenbid, true }, - { "tokens", "tokencancelbid", &tokencancelbid, true }, - { "tokens", "tokenfillbid", &tokenfillbid, true }, - { "tokens", "tokenask", &tokenask, true }, - //{ "tokens", "tokenswapask", &tokenswapask, true }, - { "tokens", "tokencancelask", &tokencancelask, true }, - { "tokens", "tokenfillask", &tokenfillask, true }, - //{ "tokens", "tokenfillswap", &tokenfillswap, true }, - { "tokens", "tokenconvert", &tokenconvert, true }, - /* Address index */ { "addressindex", "getaddressmempool", &getaddressmempool, true }, { "addressindex", "getaddressutxos", &getaddressutxos, false }, diff --git a/src/rpc/server.h b/src/rpc/server.h index fc83515c1..22a33fa8b 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -237,22 +237,7 @@ extern UniValue submitblock(const UniValue& params, bool fHelp, const CPubKey& m extern UniValue estimatefee(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue estimatepriority(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokeninfo(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenlist(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue mytokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue assetsaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokencreate(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokentransfer(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenbid(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokencancelbid(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenfillbid(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenask(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokencancelask(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenfillask(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue tokenconvert(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue heiraddress(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue heirfund(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue heiradd(const UniValue& params, bool fHelp, const CPubKey& mypk); @@ -280,8 +265,6 @@ extern UniValue channelsopen(const UniValue& params, bool fHelp, const CPubKey& 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 tokenswapask(const UniValue& params, bool fHelp, const CPubKey& mypk); -//extern UniValue tokenfillswap(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue faucetfund(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue faucetget(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue faucetaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); diff --git a/src/test-hush/test_coinimport.cpp b/src/test-hush/test_coinimport.cpp deleted file mode 100644 index 346c25c81..000000000 --- a/src/test-hush/test_coinimport.cpp +++ /dev/null @@ -1,260 +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 - -#include -#include - -#include "cc/eval.h" -#include "importcoin.h" -#include "base58.h" -#include "core_io.h" -#include "key.h" -#include "main.h" -#include "primitives/transaction.h" -#include "script/cc.h" -#include "script/interpreter.h" -#include "script/serverchecker.h" -#include "txmempool.h" - -#include "testutils.h" - - -extern Eval* EVAL_TEST; - -namespace TestCoinImport { - - -static uint8_t testNum = 0; - -class TestCoinImport : public ::testing::Test, public Eval { -public: - CMutableTransaction burnTx; std::vector rawproof; - std::vector payouts; - TxProof proof; - uint256 MoMoM; - CMutableTransaction importTx; - uint32_t testCcid = 2; - std::string testSymbol = "PIZZA"; - CAmount amount = 100; - - void SetImportTx() { - burnTx.vout.resize(0); - burnTx.vout.push_back(MakeBurnOutput(amount, testCcid, testSymbol, payouts,rawproof)); - importTx = CMutableTransaction(MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts)); - MoMoM = burnTx.GetHash(); // TODO: an actual branch - } - - uint32_t GetAssetchainsCC() const { return testCcid; } - std::string GetAssetchainsSymbol() const { return testSymbol; } - - bool GetProofRoot(uint256 hash, uint256 &momom) const - { - if (MoMoM.IsNull()) return false; - momom = MoMoM; - return true; - } - - -protected: - static void SetUpTestCase() { setupChain(); } - virtual void SetUp() { - ASSETCHAINS_CC = 1; - EVAL_TEST = this; - - std::vector fakepk; - fakepk.resize(33); - fakepk.begin()[0] = testNum++; - payouts.push_back(CTxOut(amount, CScript() << fakepk << OP_CHECKSIG)); - SetImportTx(); - } - - - void TestRunCCEval(CMutableTransaction mtx) - { - CTransaction importTx(mtx); - PrecomputedTransactionData txdata(importTx); - ServerTransactionSignatureChecker checker(&importTx, 0, 0, false, txdata); - CValidationState verifystate; - if (!VerifyCoinImport(importTx.vin[0].scriptSig, checker, verifystate)) - printf("TestRunCCEval: %s\n", verifystate.GetRejectReason().data()); - } -}; - - -TEST_F(TestCoinImport, testProcessImportThroughPipeline) -{ - CValidationState mainstate; - CTransaction tx(importTx); - - // first should work - acceptTxFail(tx); - - // should fail in mempool - ASSERT_FALSE(acceptTx(tx, mainstate)); - EXPECT_EQ("already in mempool", mainstate.GetRejectReason()); - - // should be in persisted UTXO set - generateBlock(); - ASSERT_FALSE(acceptTx(tx, mainstate)); - EXPECT_EQ("already have coins", mainstate.GetRejectReason()); - ASSERT_TRUE(pcoinsTip->HaveCoins(tx.GetHash())); - - // Now disconnect the block - CValidationState invalstate; - if (!InvalidateBlock(invalstate, chainActive.Tip())) { - FAIL() << invalstate.GetRejectReason(); - } - ASSERT_FALSE(pcoinsTip->HaveCoins(tx.GetHash())); - - // should be back in mempool - ASSERT_FALSE(acceptTx(tx, mainstate)); - EXPECT_EQ("already in mempool", mainstate.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testImportTombstone) -{ - CValidationState mainstate; - // By setting an unspendable output, there will be no addition to UTXO - // Nonetheless, we dont want to be able to import twice - payouts[0].scriptPubKey = CScript() << OP_RETURN; - SetImportTx(); - MoMoM = burnTx.GetHash(); // TODO: an actual branch - CTransaction tx(importTx); - - // first should work - acceptTxFail(tx); - - // should be in persisted UTXO set - generateBlock(); - ASSERT_FALSE(acceptTx(tx, mainstate)); - EXPECT_EQ("import tombstone exists", mainstate.GetRejectReason()); - ASSERT_TRUE(pcoinsTip->HaveCoins(burnTx.GetHash())); - - // Now disconnect the block - CValidationState invalstate; - if (!InvalidateBlock(invalstate, chainActive.Tip())) { - FAIL() << invalstate.GetRejectReason(); - } - // Tombstone should be gone from utxo set - ASSERT_FALSE(pcoinsTip->HaveCoins(burnTx.GetHash())); - - // should be back in mempool - ASSERT_FALSE(acceptTx(tx, mainstate)); - EXPECT_EQ("already in mempool", mainstate.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testNoVouts) -{ - importTx.vout.resize(0); - TestRunCCEval(importTx); - EXPECT_EQ("too-few-vouts", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testInvalidParams) -{ - std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << 'a'); - importTx.vin[0].scriptSig = CScript() << payload; - TestRunCCEval(importTx); - EXPECT_EQ("invalid-params", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testNonCanonical) -{ - importTx.nLockTime = 10; - TestRunCCEval(importTx); - EXPECT_EQ("non-canonical", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testInvalidBurnOutputs) -{ - burnTx.vout.resize(0); - MoMoM = burnTx.GetHash(); // TODO: an actual branch - CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); - TestRunCCEval(tx); - EXPECT_EQ("invalid-burn-tx", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testInvalidBurnParams) -{ - burnTx.vout.back().scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid)); - MoMoM = burnTx.GetHash(); // TODO: an actual branch - CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); - TestRunCCEval(tx); - EXPECT_EQ("invalid-burn-tx", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testWrongChainId) -{ - testCcid = 0; - TestRunCCEval(importTx); - EXPECT_EQ("importcoin-wrong-chain", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testInvalidBurnAmount) -{ - burnTx.vout.back().nValue = 0; - MoMoM = burnTx.GetHash(); // TODO: an actual branch - CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); - TestRunCCEval(tx); - EXPECT_EQ("invalid-burn-amount", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testPayoutTooHigh) -{ - importTx.vout[1].nValue = 101; - TestRunCCEval(importTx); - EXPECT_EQ("payout-too-high", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testAmountInOpret) -{ - importTx.vout[0].nValue = 1; - TestRunCCEval(importTx); - EXPECT_EQ("non-canonical", state.GetRejectReason()); -} - - - -TEST_F(TestCoinImport, testInvalidPayouts) -{ - importTx.vout[1].nValue = 40; - importTx.vout.push_back(importTx.vout[0]); - TestRunCCEval(importTx); - EXPECT_EQ("wrong-payouts", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testCouldntLoadMomom) -{ - MoMoM.SetNull(); - TestRunCCEval(importTx); - EXPECT_EQ("coudnt-load-momom", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testMomomCheckFail) -{ - MoMoM.SetNull(); - MoMoM.begin()[0] = 1; - TestRunCCEval(importTx); - EXPECT_EQ("momom-check-fail", state.GetRejectReason()); -} - - -TEST_F(TestCoinImport, testGetCoinImportValue) -{ - ASSERT_EQ(100, GetCoinImportValue(importTx)); -} - -} /* namespace TestCoinImport */ diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9f0c6beb2..e5dcbb657 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6403,19 +6403,6 @@ UniValue assetsaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) return(CCaddress(cp, (char *)"Assets", pubkey)); } -UniValue tokenaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - struct CCcontract_info *cp,C; std::vector pubkey; - cp = CCinit(&C,EVAL_TOKENS); - if ( fHelp || params.size() > 1 ) - throw runtime_error("tokenaddress [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 *)"Tokens", pubkey)); -} - UniValue oracleslist(const UniValue& params, bool fHelp, const CPubKey& mypk) { if ( fHelp || params.size() > 0 ) @@ -6691,498 +6678,6 @@ UniValue faucetget(const UniValue& params, bool fHelp, const CPubKey& mypk) return(result); } -UniValue tokenlist(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 tokenid; - if ( fHelp || params.size() > 0 ) - throw runtime_error("tokenlist\n"); - if ( ensure_CCrequirements(EVAL_TOKENS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - return(TokenList()); -} - -UniValue tokeninfo(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 tokenid; - if ( fHelp || params.size() != 1 ) - throw runtime_error("tokeninfo tokenid\n"); - if ( ensure_CCrequirements(EVAL_TOKENS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - return(TokenInfo(tokenid)); -} - -UniValue tokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 tokenid; - if ( fHelp || params.size() > 1 ) - throw runtime_error("tokenorders [tokenid]\n" - "returns token orders for the tokenid or all available token orders if tokenid is not set\n" - "(this rpc supports only fungible tokens)\n" "\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - if (params.size() == 1) { - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - if (tokenid == zeroid) - throw runtime_error("incorrect tokenid\n"); - return AssetOrders(tokenid, CPubKey(), 0); - } - else { - // throw runtime_error("no tokenid\n"); - return AssetOrders(zeroid, CPubKey(), 0); - } -} - - -UniValue mytokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - uint256 tokenid; - if (fHelp || params.size() > 1) - throw runtime_error("mytokenorders [evalcode]\n" - "returns all the token orders for mypubkey\n" - "if evalcode is set then returns mypubkey token orders for non-fungible tokens with this evalcode\n" "\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - uint8_t additionalEvalCode = 0; - if (params.size() == 1) - additionalEvalCode = strtol(params[0].get_str().c_str(), NULL, 0); // supports also 0xEE-like values - - return AssetOrders(zeroid, Mypubkey(), additionalEvalCode); -} - -UniValue tokenbalance(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); uint256 tokenid; uint64_t balance; std::vector pubkey; struct CCcontract_info *cp,C; - CCerror.clear(); - - if ( fHelp || params.size() > 2 ) - throw runtime_error("tokenbalance tokenid [pubkey]\n"); - if ( ensure_CCrequirements(EVAL_TOKENS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - - LOCK(cs_main); - - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - if ( params.size() == 2 ) - pubkey = ParseHex(params[1].get_str().c_str()); - else - pubkey = Mypubkey(); - - balance = GetTokenBalance(pubkey2pk(pubkey),tokenid); - - if (CCerror.empty()) { - char destaddr[64]; - - result.push_back(Pair("result", "success")); - cp = CCinit(&C,EVAL_TOKENS); - if (GetCCaddress(cp, destaddr, pubkey2pk(pubkey)) != 0) - result.push_back(Pair("CCaddress", destaddr)); - - result.push_back(Pair("tokenid", params[0].get_str())); - result.push_back(Pair("balance", (int64_t)balance)); - } - else { - ERR_RESULT(CCerror); - } - - return(result); -} - -UniValue tokencreate(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - std::string name, description, hextx; - std::vector nonfungibleData; - int64_t supply; // changed from uin64_t to int64_t for this 'if ( supply <= 0 )' to work as expected - - CCerror.clear(); - - if ( fHelp || params.size() > 4 || params.size() < 2 ) - throw runtime_error("tokencreate name supply [description][data]\n"); - if ( ensure_CCrequirements(EVAL_TOKENS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - - name = params[0].get_str(); - if (name.size() == 0 || name.size() > 32) { - ERR_RESULT("Token name must not be empty and up to 32 characters"); - return(result); - } - - supply = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999; // what for is this '+0.00000000499999'? it will be lost while converting double to int64_t (dimxy) - if (supply <= 0) { - ERR_RESULT("Token supply must be positive"); - return(result); - } - - if (params.size() >= 3) { - description = params[2].get_str(); - if (description.size() > 4096) { - ERR_RESULT("Token description must be <= 4096 characters"); - return(result); - } - } - - if (params.size() == 4) { - nonfungibleData = ParseHex(params[3].get_str()); - if (nonfungibleData.size() > DRAGON_MAXSCRIPTSIZE) // opret limit - { - ERR_RESULT("Non-fungible data size must be <= " + std::to_string(DRAGON_MAXSCRIPTSIZE)); - return(result); - } - if( nonfungibleData.empty() ) { - ERR_RESULT("Non-fungible data incorrect"); - return(result); - } - } - - hextx = CreateToken(0, supply, name, description, nonfungibleData); - if( hextx.size() > 0 ) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hextx)); - } - else - ERR_RESULT(CCerror); - return(result); -} - -UniValue tokentransfer(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); - std::string hex; - int64_t amount; - uint256 tokenid; - - CCerror.clear(); - - if ( fHelp || params.size() != 3) - throw runtime_error("tokentransfer tokenid destpubkey amount\n"); - if ( ensure_CCrequirements(EVAL_TOKENS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - std::vector pubkey(ParseHex(params[1].get_str().c_str())); - //amount = atol(params[2].get_str().c_str()); - amount = atoll(params[2].get_str().c_str()); // dimxy changed to prevent loss of significance - if( tokenid == zeroid ) { - ERR_RESULT("invalid tokenid"); - return(result); - } - if( amount <= 0 ) { - ERR_RESULT("amount must be positive"); - return(result); - } - - hex = TokenTransfer(0, tokenid, pubkey, amount); - - if( !CCerror.empty() ) { - ERR_RESULT(CCerror); - } - else { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } - return(result); -} - -UniValue tokenconvert(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); std::string hex; int32_t evalcode; int64_t amount; uint256 tokenid; - if ( fHelp || params.size() != 4 ) - throw runtime_error("tokenconvert evalcode tokenid pubkey amount\n"); - if ( ensure_CCrequirements(EVAL_ASSETS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - evalcode = atoi(params[0].get_str().c_str()); - tokenid = Parseuint256((char *)params[1].get_str().c_str()); - std::vector pubkey(ParseHex(params[2].get_str().c_str())); - //amount = atol(params[3].get_str().c_str()); - amount = atoll(params[3].get_str().c_str()); // dimxy changed to prevent loss of significance - if ( tokenid == zeroid ) - { - ERR_RESULT("invalid tokenid"); - return(result); - } - if ( amount <= 0 ) - { - ERR_RESULT("amount must be positive"); - return(result); - } - - ERR_RESULT("deprecated"); - return(result); - -/* hex = AssetConvert(0,tokenid,pubkey,amount,evalcode); - if (amount > 0) { - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt convert tokens"); - } else { - ERR_RESULT("amount must be positive"); - } - return(result); */ -} - -UniValue tokenbid(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid; - if ( fHelp || params.size() != 3 ) - throw runtime_error("tokenbid numtokens tokenid price\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - //numtokens = atoi(params[0].get_str().c_str()); - numtokens = atoll(params[0].get_str().c_str()); // dimxy changed to prevent loss of significance - tokenid = Parseuint256((char *)params[1].get_str().c_str()); - price = atof(params[2].get_str().c_str()); - bidamount = (price * numtokens) * COIN + 0.0000000049999; - if ( price <= 0 ) - { - ERR_RESULT("price must be positive"); - return(result); - } - if ( tokenid == zeroid ) - { - ERR_RESULT("invalid tokenid"); - return(result); - } - if ( bidamount <= 0 ) - { - ERR_RESULT("bid amount must be positive"); - return(result); - } - hex = CreateBuyOffer(0,bidamount,tokenid,numtokens); - if (price > 0 && numtokens > 0) { - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create bid"); - } else { - ERR_RESULT("price and numtokens must be positive"); - } - return(result); -} - -UniValue tokencancelbid(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid; - if ( fHelp || params.size() != 2 ) - throw runtime_error("tokencancelbid tokenid bidtxid\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - bidtxid = Parseuint256((char *)params[1].get_str().c_str()); - if ( tokenid == zeroid || bidtxid == zeroid ) - { - result.push_back(Pair("error", "invalid parameter")); - return(result); - } - hex = CancelBuyOffer(0,tokenid,bidtxid); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt cancel bid"); - return(result); -} - -UniValue tokenfillbid(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); int64_t fillamount; std::string hex; uint256 tokenid,bidtxid; - if ( fHelp || params.size() != 3 ) - throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - bidtxid = Parseuint256((char *)params[1].get_str().c_str()); - // fillamount = atol(params[2].get_str().c_str()); - fillamount = atoll(params[2].get_str().c_str()); // dimxy changed to prevent loss of significance - if ( fillamount <= 0 ) - { - ERR_RESULT("fillamount must be positive"); - return(result); - } - if ( tokenid == zeroid || bidtxid == zeroid ) - { - ERR_RESULT("must provide tokenid and bidtxid"); - return(result); - } - hex = FillBuyOffer(0,tokenid,bidtxid,fillamount); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt fill bid"); - return(result); -} - -UniValue tokenask(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid; - if ( fHelp || params.size() != 3 ) - throw runtime_error("tokenask numtokens tokenid price\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - //numtokens = atoi(params[0].get_str().c_str()); - numtokens = atoll(params[0].get_str().c_str()); // dimxy changed to prevent loss of significance - tokenid = Parseuint256((char *)params[1].get_str().c_str()); - price = atof(params[2].get_str().c_str()); - askamount = (price * numtokens) * COIN + 0.0000000049999; - //std::cerr << std::boolalpha << "tokenask(): (tokenid == zeroid) is " << (tokenid == zeroid) << " (numtokens <= 0) is " << (numtokens <= 0) << " (price <= 0) is " << (price <= 0) << " (askamount <= 0) is " << (askamount <= 0) << std::endl; - if ( tokenid == zeroid || numtokens <= 0 || price <= 0 || askamount <= 0 ) - { - ERR_RESULT("invalid parameter"); - return(result); - } - hex = CreateSell(0,numtokens,tokenid,askamount); - if (price > 0 && numtokens > 0) { - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create ask"); - } else { - ERR_RESULT("price and numtokens must be positive"); - } - return(result); -} - -UniValue tokenswapask(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - static uint256 zeroid; - UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid,otherid; - if ( fHelp || params.size() != 4 ) - throw runtime_error("tokenswapask numtokens tokenid otherid price\n"); - if ( ensure_CCrequirements(EVAL_ASSETS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - //numtokens = atoi(params[0].get_str().c_str()); - numtokens = atoll(params[0].get_str().c_str()); // dimxy changed to prevent loss of significance - tokenid = Parseuint256((char *)params[1].get_str().c_str()); - otherid = Parseuint256((char *)params[2].get_str().c_str()); - price = atof(params[3].get_str().c_str()); - askamount = (price * numtokens); - hex = CreateSwap(0,numtokens,tokenid,otherid,askamount); - if (price > 0 && numtokens > 0) { - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create swap"); - } else { - ERR_RESULT("price and numtokens must be positive"); - } - return(result); -} - -UniValue tokencancelask(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,asktxid; - if ( fHelp || params.size() != 2 ) - throw runtime_error("tokencancelask tokenid asktxid\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - asktxid = Parseuint256((char *)params[1].get_str().c_str()); - if ( tokenid == zeroid || asktxid == zeroid ) - { - result.push_back(Pair("error", "invalid parameter")); - return(result); - } - hex = CancelSell(0,tokenid,asktxid); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt cancel ask"); - return(result); -} - -UniValue tokenfillask(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,asktxid; - if ( fHelp || params.size() != 3 ) - throw runtime_error("tokenfillask tokenid asktxid fillunits\n"); - if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - asktxid = Parseuint256((char *)params[1].get_str().c_str()); - //fillunits = atol(params[2].get_str().c_str()); - fillunits = atoll(params[2].get_str().c_str()); // dimxy changed to prevent loss of significance - if ( fillunits <= 0 ) - { - ERR_RESULT("fillunits must be positive"); - return(result); - } - if ( tokenid == zeroid || asktxid == zeroid ) - { - result.push_back(Pair("error", "invalid parameter")); - return(result); - } - hex = FillSell(0,tokenid,zeroid,asktxid,fillunits); - if (fillunits > 0) { - if (CCerror != "") { - ERR_RESULT(CCerror); - } else if ( hex.size() > 0) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else { - ERR_RESULT("couldnt fill ask"); - } - } else { - ERR_RESULT("fillunits must be positive"); - } - return(result); -} - -UniValue tokenfillswap(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - static uint256 zeroid; - UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,otherid,asktxid; - if ( fHelp || params.size() != 4 ) - throw runtime_error("tokenfillswap tokenid otherid asktxid fillunits\n"); - if ( ensure_CCrequirements(EVAL_ASSETS) < 0 ) - throw runtime_error(CC_REQUIREMENTS_MSG); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - otherid = Parseuint256((char *)params[1].get_str().c_str()); - asktxid = Parseuint256((char *)params[2].get_str().c_str()); - //fillunits = atol(params[3].get_str().c_str()); - fillunits = atoll(params[3].get_str().c_str()); // dimxy changed to prevent loss of significance - hex = FillSell(0,tokenid,otherid,asktxid,fillunits); - if (fillunits > 0) { - if ( hex.size() > 0 ) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt fill bid"); - } else { - ERR_RESULT("fillunits must be positive"); - } - return(result); -} - UniValue getbalance64(const UniValue& params, bool fHelp, const CPubKey& mypk) { set setAddress; vector vecOutputs;