Delete many things we do not want or need
This commit is contained in:
@@ -272,13 +272,10 @@ libbitcoin_server_a_SOURCES = \
|
|||||||
asyncrpcqueue.cpp \
|
asyncrpcqueue.cpp \
|
||||||
bloom.cpp \
|
bloom.cpp \
|
||||||
cc/eval.cpp \
|
cc/eval.cpp \
|
||||||
cc/import.cpp \
|
|
||||||
cc/importgateway.cpp \
|
|
||||||
cc/CCassetsCore.cpp \
|
cc/CCassetsCore.cpp \
|
||||||
cc/CCcustom.cpp \
|
cc/CCcustom.cpp \
|
||||||
cc/CCtx.cpp \
|
cc/CCtx.cpp \
|
||||||
cc/CCutils.cpp \
|
cc/CCutils.cpp \
|
||||||
cc/CCtokens.cpp \
|
|
||||||
cc/assets.cpp \
|
cc/assets.cpp \
|
||||||
cc/faucet.cpp \
|
cc/faucet.cpp \
|
||||||
cc/fsm.cpp \
|
cc/fsm.cpp \
|
||||||
@@ -339,7 +336,6 @@ libbitcoin_wallet_a_SOURCES = \
|
|||||||
zcash/Note.cpp \
|
zcash/Note.cpp \
|
||||||
transaction_builder.cpp \
|
transaction_builder.cpp \
|
||||||
wallet/rpcdump.cpp \
|
wallet/rpcdump.cpp \
|
||||||
cc/CCtokens.cpp \
|
|
||||||
cc/CCassetsCore.cpp \
|
cc/CCassetsCore.cpp \
|
||||||
cc/CCassetstx.cpp \
|
cc/CCassetstx.cpp \
|
||||||
cc/CCtx.cpp \
|
cc/CCtx.cpp \
|
||||||
@@ -406,7 +402,6 @@ libbitcoin_common_a_SOURCES = \
|
|||||||
core_read.cpp \
|
core_read.cpp \
|
||||||
core_write.cpp \
|
core_write.cpp \
|
||||||
hash.cpp \
|
hash.cpp \
|
||||||
importcoin.cpp \
|
|
||||||
key.cpp \
|
key.cpp \
|
||||||
key_io.cpp \
|
key_io.cpp \
|
||||||
keystore.cpp \
|
keystore.cpp \
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include "CCPrices.h"
|
#include "CCPrices.h"
|
||||||
#include "CCPegs.h"
|
#include "CCPegs.h"
|
||||||
#include "CCtokens.h"
|
#include "CCtokens.h"
|
||||||
#include "CCImportGateway.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CCcustom has most of the functions that need to be extended to create a new CC contract.
|
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->normaladdr, TokensNormaladdr);
|
||||||
strcpy(cp->CChexstr, TokensCChexstr);
|
strcpy(cp->CChexstr, TokensCChexstr);
|
||||||
memcpy(cp->CCpriv, TokensCCpriv, 32);
|
memcpy(cp->CCpriv, TokensCCpriv, 32);
|
||||||
cp->validate = TokensValidate;
|
//cp->validate = TokensValidate;
|
||||||
cp->ismyvin = IsTokensInput;
|
//cp->ismyvin = IsTokensInput;
|
||||||
break;
|
break;
|
||||||
case EVAL_IMPORTGATEWAY:
|
case EVAL_IMPORTGATEWAY:
|
||||||
strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr);
|
strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr);
|
||||||
strcpy(cp->normaladdr, ImportGatewayNormaladdr);
|
strcpy(cp->normaladdr, ImportGatewayNormaladdr);
|
||||||
strcpy(cp->CChexstr, ImportGatewayCChexstr);
|
strcpy(cp->CChexstr, ImportGatewayCChexstr);
|
||||||
memcpy(cp->CCpriv, ImportGatewayCCpriv, 32);
|
memcpy(cp->CCpriv, ImportGatewayCCpriv, 32);
|
||||||
cp->validate = ImportGatewayValidate;
|
//cp->validate = ImportGatewayValidate;
|
||||||
cp->ismyvin = IsImportGatewayInput;
|
//cp->ismyvin = IsImportGatewayInput;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if ( CClib_initcp(cp,evalcode) < 0 )
|
if ( CClib_initcp(cp,evalcode) < 0 )
|
||||||
|
|||||||
1059
src/cc/CCtokens.cpp
1059
src/cc/CCtokens.cpp
File diff suppressed because it is too large
Load Diff
@@ -19,448 +19,8 @@
|
|||||||
#include "CCassets.h"
|
#include "CCassets.h"
|
||||||
#include "CCtokens.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 <pubkey> <assetid> -> [{address:amount}, ... ] // like withdraw api
|
|
||||||
selloffer <pubkey> <txid/vout> <amount> -> cancel or fillsell -> mempool txid or rejected, might not confirm
|
|
||||||
buyoffer <amount> <assetid> <required> -> cancelbuy or fillbuy -> mempool txid or rejected, might not confirm
|
|
||||||
exchange <pubkey> <txid/vout> <required> <required assetid> -> cancel or fillexchange -> mempool txid or rejected, might not confirm
|
|
||||||
|
|
||||||
assetsaddress <pubkey> // all assets end up in a special address for each pubkey
|
|
||||||
assetbalance <pubkey> <assetid>
|
|
||||||
assetutxos <pubkey> <assetid>
|
|
||||||
assetsbalances <pubkey>
|
|
||||||
asks <assetid>
|
|
||||||
bids <assetid>
|
|
||||||
swaps <assetid>
|
|
||||||
|
|
||||||
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
|
// tx validation
|
||||||
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||||
{
|
{
|
||||||
static uint256 zero;
|
return false;
|
||||||
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<uint8_t> 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'] [{"<assetname>":"<description>"}]
|
|
||||||
//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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "crosschain.h"
|
|
||||||
#define FAUCET2SIZE COIN
|
#define FAUCET2SIZE COIN
|
||||||
#define EVAL_FAUCET2 EVAL_FIRSTUSER
|
#define EVAL_FAUCET2 EVAL_FIRSTUSER
|
||||||
#ifdef BUILD_ROGUE
|
#ifdef BUILD_ROGUE
|
||||||
@@ -642,50 +641,10 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len)
|
|||||||
} else return(-1);
|
} 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"
|
#include "customcc.cpp"
|
||||||
|
|
||||||
#elif BUILD_GAMESCC
|
|
||||||
#include "rogue/cursesd.c"
|
|
||||||
#include "gamescc.cpp"
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include "musig.cpp"
|
#include "musig.cpp"
|
||||||
#include "dilithium.c"
|
#include "dilithium.c"
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
|
|||||||
|
|
||||||
switch ( ecode )
|
switch ( ecode )
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
case EVAL_IMPORTPAYOUT:
|
case EVAL_IMPORTPAYOUT:
|
||||||
return ImportPayout(vparams, txTo, nIn);
|
return ImportPayout(vparams, txTo, nIn);
|
||||||
break;
|
break;
|
||||||
@@ -110,7 +111,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
|
|||||||
case EVAL_IMPORTCOIN:
|
case EVAL_IMPORTCOIN:
|
||||||
return ImportCoin(vparams, txTo, nIn);
|
return ImportCoin(vparams, txTo, nIn);
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
return(ProcessCC(cp,this, vparams, txTo, nIn));
|
return(ProcessCC(cp,this, vparams, txTo, nIn));
|
||||||
break;
|
break;
|
||||||
|
|||||||
1813
src/cc/gamescc.cpp
1813
src/cc/gamescc.cpp
File diff suppressed because it is too large
Load Diff
@@ -545,7 +545,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
|
|||||||
if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
|
if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
|
||||||
funcId != 0 &&
|
funcId != 0 &&
|
||||||
isMyFuncId(funcId) &&
|
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<Helper>(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts
|
//(voutValue = IsHeirFundingVout<Helper>(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))
|
!myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, voutIndex))
|
||||||
{
|
{
|
||||||
@@ -596,7 +596,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
|
|||||||
if (funcId != 0 &&
|
if (funcId != 0 &&
|
||||||
(txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
|
(txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
|
||||||
isMyFuncId(funcId) && !isSpendingTx(funcId) &&
|
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
|
!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)
|
total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change)
|
||||||
|
|||||||
@@ -68,9 +68,12 @@ class TokenHelper {
|
|||||||
public:
|
public:
|
||||||
static uint8_t getMyEval() { return EVAL_TOKENS; }
|
static uint8_t getMyEval() { return EVAL_TOKENS; }
|
||||||
static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
|
static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
|
||||||
|
/*
|
||||||
struct CCcontract_info *cpHeir, heirC;
|
struct CCcontract_info *cpHeir, heirC;
|
||||||
cpHeir = CCinit(&heirC, EVAL_TOKENS);
|
cpHeir = CCinit(&heirC, EVAL_TOKENS);
|
||||||
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
|
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
|
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
|
||||||
|
|||||||
@@ -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 <wolfssl/wolfcrypt/sha.h>
|
|
||||||
#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<uint8_t> &proofData, std::vector<uint256> &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<CPubKey> &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::vector<uint8_t>proof,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<CTxOut> vouts)
|
|
||||||
{
|
|
||||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()),burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight());
|
|
||||||
CPubKey mypk; uint256 codaburntxid; std::vector<unsigned char> 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<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
|
|
||||||
{
|
|
||||||
// check with dual-BEAM daemon via ASSETCHAINS_BEAMPORT for validity of burnTx
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector<CTxOut> 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<uint8_t> proof,
|
|
||||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> 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<CTxOut> vouts; CPubKey regpk;
|
|
||||||
std::vector<CPubKey> pubkeys,tmppubkeys,tmppublishers; char markeraddr[64],deposit[64],destaddr[64],tmpdest[64]; int64_t datafee;
|
|
||||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > 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<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> 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<uint8_t> 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<CTxOut> & payouts, const ImportProof &proof, const std::vector<uint8_t> &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<std::pair<uint8_t, vscript_t>> oprets;
|
|
||||||
uint8_t evalCodeInOpret;
|
|
||||||
std::vector<CPubKey> 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<std::pair<uint8_t, vscript_t>> oprets;
|
|
||||||
uint8_t evalCodeInOpret;
|
|
||||||
std::vector<CPubKey> 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<std::pair<uint8_t, vscript_t>> 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<std::pair<uint8_t, vscript_t>> 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<uint256> 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<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
|
|
||||||
{
|
|
||||||
ImportProof proof;
|
|
||||||
CTransaction burnTx;
|
|
||||||
std::vector<CTxOut> payouts;
|
|
||||||
CAmount txfee = 10000, amount;
|
|
||||||
int32_t height, burnvout;
|
|
||||||
std::vector<CPubKey> publishers;
|
|
||||||
uint32_t targetCcid;
|
|
||||||
std::string targetSymbol, srcaddr, destaddr, receipt, rawburntx;
|
|
||||||
uint256 payoutsHash, bindtxid, burntxid;
|
|
||||||
std::vector<uint8_t> rawproof;
|
|
||||||
std::vector<uint256> 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();
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
|||||||
echo pricescc.so
|
|
||||||
gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp
|
|
||||||
echo prices
|
|
||||||
cd games
|
|
||||||
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES ../gamescc.cpp -lncurses -lcurl -o prices
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
echo gamescc.so with tetris
|
|
||||||
gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp
|
|
||||||
echo tetris dapp
|
|
||||||
cd games
|
|
||||||
gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE ../gamescc.cpp -lncurses -lcurl -o tetris
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
@@ -557,17 +557,17 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
|
|||||||
CAmount value,nResult = 0;
|
CAmount value,nResult = 0;
|
||||||
if ( interestp != 0 )
|
if ( interestp != 0 )
|
||||||
*interestp = 0;
|
*interestp = 0;
|
||||||
if ( tx.IsCoinImport() )
|
//if ( tx.IsCoinImport() )
|
||||||
return GetCoinImportValue(tx);
|
// return GetCoinImportValue(tx);
|
||||||
if ( tx.IsCoinBase() != 0 )
|
if ( tx.IsCoinBase() != 0 )
|
||||||
return 0;
|
return 0;
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
{
|
{
|
||||||
if (tx.IsPegsImport() && i==0)
|
//if (tx.IsPegsImport() && i==0)
|
||||||
{
|
//{
|
||||||
nResult = GetCoinImportValue(tx);
|
// nResult = GetCoinImportValue(tx);
|
||||||
continue;
|
// continue;
|
||||||
}
|
//}
|
||||||
value = GetOutputFor(tx.vin[i]).nValue;
|
value = GetOutputFor(tx.vin[i]).nValue;
|
||||||
nResult += value;
|
nResult += value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,32 +223,6 @@ cont:
|
|||||||
return std::make_pair(targetChainNotarizationTxid,newBranch);
|
return std::make_pair(targetChainNotarizationTxid,newBranch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Takes an importTx that has proof leading to assetchain root
|
|
||||||
* and extends proof to cross chain root
|
|
||||||
*/
|
|
||||||
void CompleteImportTransaction(CTransaction &importTx, int32_t offset)
|
|
||||||
{
|
|
||||||
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; std::vector<uint8_t> 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) {
|
bool IsSameAssetChain(const Notarization ¬a) {
|
||||||
return strcmp(nota.second.symbol, SMART_CHAIN_SYMBOL) == 0;
|
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<uint256> & notaryTxids)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// get notaries:
|
|
||||||
uint8_t notaries_pubkeys[64][33];
|
|
||||||
std::vector< std::vector<uint8_t> > 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<uint8_t> vopret;
|
|
||||||
if (!notarytx.vout.empty() && GetOpReturnData(notarytx.vout.back().scriptPubKey, vopret)) {
|
|
||||||
std::vector<uint8_t> txoutproof;
|
|
||||||
|
|
||||||
if (E_UNMARSHAL(vopret, ss >> txoutproof)) {
|
|
||||||
CMerkleBlock merkleBlock;
|
|
||||||
std::vector<uint256> 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<uint8_t> 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
|
* On assetchain
|
||||||
* in: txid
|
* in: txid
|
||||||
|
|||||||
@@ -38,10 +38,8 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int hushHeig
|
|||||||
std::vector<uint256> &moms, uint256 &destNotarizationTxid);
|
std::vector<uint256> &moms, uint256 &destNotarizationTxid);
|
||||||
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
|
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
|
||||||
const TxProof assetChainProof,int32_t offset);
|
const TxProof assetChainProof,int32_t offset);
|
||||||
void CompleteImportTransaction(CTransaction &importTx,int32_t offset);
|
|
||||||
|
|
||||||
/* On assetchain */
|
/* On assetchain */
|
||||||
bool CheckMoMoM(uint256 hushNotarizationHash, uint256 momom);
|
bool CheckMoMoM(uint256 hushNotarizationHash, uint256 momom);
|
||||||
bool CheckNotariesApproval(uint256 burntxid, const std::vector<uint256> & notaryTxids);
|
|
||||||
|
|
||||||
#endif /* HUSH_CROSSCHAIN_H */
|
#endif /* HUSH_CROSSCHAIN_H */
|
||||||
|
|||||||
@@ -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<CTxOut> payouts, uint32_t nExpiryHeightOverride)
|
|
||||||
{
|
|
||||||
//std::vector<uint8_t> 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<uint8_t> vorigpubkey;
|
|
||||||
uint8_t funcId;
|
|
||||||
std::vector <std::pair<uint8_t, vscript_t>> 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<CTxOut> 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<CTxOut> payouts, const std::vector<uint8_t> rawproof)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<CTxOut> payouts,std::vector<uint8_t> rawproof,
|
|
||||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<CTxOut> payouts,std::vector<uint8_t> rawproof,std::string srcaddr,
|
|
||||||
std::string receipt)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<CTxOut> payouts,std::vector<uint8_t> rawproof,uint256 pegstxid,
|
|
||||||
uint256 tokenid,CPubKey srcpub,int64_t amount,std::pair<int64_t,int64_t> account)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<CTxOut> &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<uint8_t> 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<std::pair<uint8_t, vscript_t>> oprets;
|
|
||||||
std::vector<uint8_t> 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<std::pair<uint8_t, vscript_t>>::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<CTxOut>(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<CTxOut>(importTx.vout.begin()+1, importTx.vout.end()); // see next
|
|
||||||
payouts = std::vector<CTxOut>(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<uint8_t>&rawproof)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<std::pair<uint8_t, vscript_t>> oprets;
|
|
||||||
uint256 tokenid;
|
|
||||||
uint8_t evalCodeInOpret;
|
|
||||||
std::vector<CPubKey> 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<uint8_t> 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<CPubKey> &publishers,std::vector<uint256> &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<int64_t,int64_t> &account)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> 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<CTxOut> 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<CPubKey> voutTokenPubkeys;
|
|
||||||
std::vector<std::pair<uint8_t, vscript_t>> 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<uint8_t> 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);
|
|
||||||
}
|
|
||||||
26
src/main.cpp
26
src/main.cpp
@@ -21,7 +21,6 @@
|
|||||||
#include "sodium.h"
|
#include "sodium.h"
|
||||||
#include "addrman.h"
|
#include "addrman.h"
|
||||||
#include "arith_uint256.h"
|
#include "arith_uint256.h"
|
||||||
#include "importcoin.h"
|
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
#include "checkqueue.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");
|
return state.Invalid(false, REJECT_DUPLICATE, "already have coins");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.IsCoinImport() || tx.IsPegsImport()) {
|
//if (tx.IsCoinImport() || tx.IsPegsImport()) {
|
||||||
// Inverse of normal case; if input exists, it's been spent
|
// // Inverse of normal case; if input exists, it's been spent
|
||||||
if (ExistsImportTombstone(tx, view))
|
// if (ExistsImportTombstone(tx, view))
|
||||||
return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists");
|
// return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists");
|
||||||
} else {
|
//} else
|
||||||
|
{
|
||||||
// do all inputs exist?
|
// do all inputs exist?
|
||||||
// Note that this does not check for the presence of actual outputs (see the next check for that),
|
// 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).
|
// 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
|
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); // add outputs
|
||||||
|
|
||||||
// Unorthodox state
|
// Unorthodox state
|
||||||
if (tx.IsCoinImport() || tx.IsPegsImport()) {
|
//if (tx.IsCoinImport() || tx.IsPegsImport()) {
|
||||||
// add a tombstone for the burnTx
|
// // add a tombstone for the burnTx
|
||||||
AddImportTombstone(tx, inputs, nHeight);
|
// AddImportTombstone(tx, inputs, nHeight);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
|
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
|
||||||
@@ -2643,11 +2643,13 @@ namespace Consensus {
|
|||||||
CAmount nFees = 0;
|
CAmount nFees = 0;
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
if (tx.IsPegsImport() && i==0)
|
if (tx.IsPegsImport() && i==0)
|
||||||
{
|
{
|
||||||
nValueIn=GetCoinImportValue(tx);
|
nValueIn=GetCoinImportValue(tx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
const COutPoint &prevout = tx.vin[i].prevout;
|
const COutPoint &prevout = tx.vin[i].prevout;
|
||||||
const CCoins *coins = inputs.AccessCoins(prevout.hash);
|
const CCoins *coins = inputs.AccessCoins(prevout.hash);
|
||||||
assert(coins);
|
assert(coins);
|
||||||
@@ -2771,12 +2773,14 @@ bool ContextualCheckInputs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (tx.IsCoinImport() || tx.IsPegsImport())
|
if (tx.IsCoinImport() || tx.IsPegsImport())
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
ServerTransactionSignatureChecker checker(&tx, 0, 0, false, txdata);
|
ServerTransactionSignatureChecker checker(&tx, 0, 0, false, txdata);
|
||||||
return VerifyCoinImport(tx.vin[0].scriptSig, checker, state);
|
return VerifyCoinImport(tx.vin[0].scriptSig, checker, state);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3051,10 +3055,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
else if (tx.IsCoinImport() || tx.IsPegsImport())
|
else if (tx.IsCoinImport() || tx.IsPegsImport())
|
||||||
{
|
{
|
||||||
RemoveImportTombstone(tx, view);
|
RemoveImportTombstone(tx, view);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the old best Sprout anchor back
|
// set the old best Sprout anchor back
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "importcoin.h"
|
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
@@ -308,12 +307,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
|||||||
bool fMissingInputs = false;
|
bool fMissingInputs = false;
|
||||||
bool fNotarization = false;
|
bool fNotarization = false;
|
||||||
std::vector<int8_t> TMP_NotarizationNotaries;
|
std::vector<int8_t> 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();
|
TMP_NotarizationNotaries.clear();
|
||||||
bool fToCryptoAddress = false;
|
bool fToCryptoAddress = false;
|
||||||
if ( numSN != 0 && notarypubkeys[0][0] != 0 && hush_is_notarytx(tx) == 1 )
|
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)
|
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
if (tx.IsPegsImport() && txin.prevout.n==10e8)
|
if (tx.IsPegsImport() && txin.prevout.n==10e8)
|
||||||
{
|
{
|
||||||
CAmount nValueIn = GetCoinImportValue(tx); // burn amount
|
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.
|
dPriority += (double)nValueIn * 1000; // flat multiplier... max = 1e16.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Read prev transaction
|
// Read prev transaction
|
||||||
if (!view.HaveCoins(txin.prevout.hash))
|
if (!view.HaveCoins(txin.prevout.hash))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -711,7 +711,8 @@ public:
|
|||||||
|
|
||||||
bool IsPegsImport() const
|
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)
|
friend bool operator==(const CTransaction& a, const CTransaction& b)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -144,9 +144,10 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
|
|||||||
UniValue vin(UniValue::VARR);
|
UniValue vin(UniValue::VARR);
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||||
UniValue in(UniValue::VOBJ);
|
UniValue in(UniValue::VOBJ);
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase()) {
|
||||||
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
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"));
|
in.push_back(Pair("is_import", "1"));
|
||||||
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
|
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
|
||||||
if (UnmarshalImportTx(tx, proof, burnTx, payouts))
|
if (UnmarshalImportTx(tx, proof, burnTx, payouts))
|
||||||
@@ -168,7 +169,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
else {
|
else {
|
||||||
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
|
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
|
||||||
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
|
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));
|
out.push_back(Pair("n", (int64_t)i));
|
||||||
UniValue o(UniValue::VOBJ);
|
UniValue o(UniValue::VOBJ);
|
||||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||||
|
/*
|
||||||
if (txout.scriptPubKey.IsOpReturn() && txout.nValue != 0)
|
if (txout.scriptPubKey.IsOpReturn() && txout.nValue != 0)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vector<uint8_t>rawproof;
|
std::vector<uint8_t> burnOpret; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; std::vector<uint8_t>rawproof;
|
||||||
@@ -224,6 +226,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
|
|||||||
out.push_back(Pair("target", "EXPORT->" + targetSymbol));
|
out.push_back(Pair("target", "EXPORT->" + targetSymbol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
out.push_back(Pair("scriptPubKey", o));
|
out.push_back(Pair("scriptPubKey", o));
|
||||||
|
|
||||||
// Add spent information if spentindex is enabled
|
// Add spent information if spentindex is enabled
|
||||||
|
|||||||
@@ -346,16 +346,6 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "crosschain", "crosschainproof", &crosschainproof, true },
|
{ "crosschain", "crosschainproof", &crosschainproof, true },
|
||||||
{ "crosschain", "getNotarizationsForBlock", &getNotarizationsForBlock, true },
|
{ "crosschain", "getNotarizationsForBlock", &getNotarizationsForBlock, true },
|
||||||
{ "crosschain", "scanNotarizationsDB", &scanNotarizationsDB, 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 */
|
||||||
{ "mining", "getblocktemplate", &getblocktemplate, true },
|
{ "mining", "getblocktemplate", &getblocktemplate, true },
|
||||||
@@ -443,26 +433,6 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "CClib", "cclibinfo", &cclibinfo, true },
|
{ "CClib", "cclibinfo", &cclibinfo, true },
|
||||||
{ "CClib", "cclib", &cclib, 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 */
|
/* Address index */
|
||||||
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
|
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
|
||||||
{ "addressindex", "getaddressutxos", &getaddressutxos, false },
|
{ "addressindex", "getaddressutxos", &getaddressutxos, false },
|
||||||
|
|||||||
@@ -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 estimatefee(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue estimatepriority(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 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 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 heiraddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue heirfund(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);
|
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 channelspayment(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue channelsclose(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 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 faucetfund(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
extern UniValue faucetget(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);
|
extern UniValue faucetaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
|
||||||
|
|||||||
@@ -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 <cryptoconditions.h>
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#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<uint8_t> rawproof;
|
|
||||||
std::vector<CTxOut> 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<uint8_t> 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<uint8_t> 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 */
|
|
||||||
@@ -6403,19 +6403,6 @@ UniValue assetsaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
return(CCaddress(cp, (char *)"Assets", pubkey));
|
return(CCaddress(cp, (char *)"Assets", pubkey));
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue tokenaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|
||||||
{
|
|
||||||
struct CCcontract_info *cp,C; std::vector<unsigned char> 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)
|
UniValue oracleslist(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
{
|
{
|
||||||
if ( fHelp || params.size() > 0 )
|
if ( fHelp || params.size() > 0 )
|
||||||
@@ -6691,498 +6678,6 @@ UniValue faucetget(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
return(result);
|
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<unsigned char> 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<uint8_t> 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<unsigned char> 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<unsigned char> 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)
|
UniValue getbalance64(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
{
|
{
|
||||||
set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
|
set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
|
||||||
|
|||||||
Reference in New Issue
Block a user