Browse Source

Delete many things we do not want or need

duke
Duke 4 months ago
parent
commit
3a3c67e0fc
  1. 5
      src/Makefile.am
  2. 9
      src/cc/CCcustom.cpp
  3. 1059
      src/cc/CCtokens.cpp
  4. 442
      src/cc/assets.cpp
  5. 43
      src/cc/cclib.cpp
  6. 3
      src/cc/eval.cpp
  7. 1813
      src/cc/gamescc.cpp
  8. 4
      src/cc/heir.cpp
  9. 3
      src/cc/heir_validate.h
  10. 764
      src/cc/import.cpp
  11. 1288
      src/cc/importgateway.cpp
  12. 8
      src/cc/makeprices
  13. 7
      src/cc/maketetris
  14. 14
      src/coins.cpp
  15. 132
      src/crosschain.cpp
  16. 2
      src/crosschain.h
  17. 425
      src/importcoin.cpp
  18. 26
      src/main.cpp
  19. 14
      src/miner.cpp
  20. 3
      src/primitives/transaction.h
  21. 1185
      src/rpc/crosschain.cpp
  22. 9
      src/rpc/rawtransaction.cpp
  23. 30
      src/rpc/server.cpp
  24. 17
      src/rpc/server.h
  25. 260
      src/test-hush/test_coinimport.cpp
  26. 505
      src/wallet/rpcwallet.cpp

5
src/Makefile.am

@ -272,13 +272,10 @@ libbitcoin_server_a_SOURCES = \
asyncrpcqueue.cpp \
bloom.cpp \
cc/eval.cpp \
cc/import.cpp \
cc/importgateway.cpp \
cc/CCassetsCore.cpp \
cc/CCcustom.cpp \
cc/CCtx.cpp \
cc/CCutils.cpp \
cc/CCtokens.cpp \
cc/assets.cpp \
cc/faucet.cpp \
cc/fsm.cpp \
@ -339,7 +336,6 @@ libbitcoin_wallet_a_SOURCES = \
zcash/Note.cpp \
transaction_builder.cpp \
wallet/rpcdump.cpp \
cc/CCtokens.cpp \
cc/CCassetsCore.cpp \
cc/CCassetstx.cpp \
cc/CCtx.cpp \
@ -406,7 +402,6 @@ libbitcoin_common_a_SOURCES = \
core_read.cpp \
core_write.cpp \
hash.cpp \
importcoin.cpp \
key.cpp \
key_io.cpp \
keystore.cpp \

9
src/cc/CCcustom.cpp

@ -27,7 +27,6 @@
#include "CCPrices.h"
#include "CCPegs.h"
#include "CCtokens.h"
#include "CCImportGateway.h"
/*
CCcustom has most of the functions that need to be extended to create a new CC contract.
@ -409,16 +408,16 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
strcpy(cp->normaladdr, TokensNormaladdr);
strcpy(cp->CChexstr, TokensCChexstr);
memcpy(cp->CCpriv, TokensCCpriv, 32);
cp->validate = TokensValidate;
cp->ismyvin = IsTokensInput;
//cp->validate = TokensValidate;
//cp->ismyvin = IsTokensInput;
break;
case EVAL_IMPORTGATEWAY:
strcpy(cp->unspendableCCaddr, ImportGatewayCCaddr);
strcpy(cp->normaladdr, ImportGatewayNormaladdr);
strcpy(cp->CChexstr, ImportGatewayCChexstr);
memcpy(cp->CCpriv, ImportGatewayCCpriv, 32);
cp->validate = ImportGatewayValidate;
cp->ismyvin = IsImportGatewayInput;
//cp->validate = ImportGatewayValidate;
//cp->ismyvin = IsImportGatewayInput;
break;
default:
if ( CClib_initcp(cp,evalcode) < 0 )

1059
src/cc/CCtokens.cpp

File diff suppressed because it is too large

442
src/cc/assets.cpp

@ -19,448 +19,8 @@
#include "CCassets.h"
#include "CCtokens.h"
/*
Assets can be created or transferred.
native coins are also locked in the EVAL_ASSETS address, so we need a strict rule on when utxo in the special address are native coins and when they are assets. The specific rule that must not be violated is that vout0 for 'b'/'B' funcid are native coins. All other utxo locked in the special address are assets.
To create an asset use CC EVAL_ASSETS to create a transaction where vout[0] funds the assets. Externally each satoshi can be interpreted to represent 1 asset, or 100 million satoshis for one asset with 8 decimals, and the other decimals in between. The interpretation of the number of decimals is left to the higher level usages.
Once created, the assetid is the txid of the create transaction and using the assetid/0 it can spend the assets to however many outputs it creates. The restriction is that the last output must be an opreturn with the assetid. The sum of all but the first output needs to add up to the total assetoshis input. The first output is ignored and used for change from txfee.
What this means is that vout 0 of the creation txid and vouts 1 ... n-2 for transfer vouts are assetoshi outputs.
There is a special type of transfer to an unspendable address, that locks the asset and creates an offer for all. The details specified in the opreturn. In order to be compatible with the signing restrictions, the "unspendable" address is actually an address whose privkey is known to all. Funds sent to this address can only be spent if the swap parameters are fulfilled, or if the original pubkey cancels the offer by spending it.
Types of transactions:
create name:description -> txid for assetid
transfer <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
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
static uint256 zero;
CTxDestination address;
CTransaction vinTx, createTx;
uint256 hashBlock, assetid, assetid2;
int32_t i,starti, numvins, numvouts, preventCCvins, preventCCvouts;
int64_t remaining_price, nValue, assetoshis, outputsDummy,inputs,tmpprice,totalunits,ignore;
std::vector<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);
return false;
}

43
src/cc/cclib.cpp

@ -26,7 +26,6 @@
#include "main.h"
#include "chain.h"
#include "core_io.h"
#include "crosschain.h"
#define FAUCET2SIZE COIN
#define EVAL_FAUCET2 EVAL_FIRSTUSER
#ifdef BUILD_ROGUE
@ -642,50 +641,10 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len)
} else return(-1);
}
#ifdef BUILD_ROGUE
#include "rogue_rpc.cpp"
#include "rogue/cursesd.c"
#include "rogue/vers.c"
#include "rogue/extern.c"
#include "rogue/armor.c"
#include "rogue/chase.c"
#include "rogue/command.c"
#include "rogue/daemon.c"
#include "rogue/daemons.c"
#include "rogue/fight.c"
#include "rogue/init.c"
#include "rogue/io.c"
#include "rogue/list.c"
#include "rogue/mach_dep.c"
#include "rogue/rogue.c"
#include "rogue/xcrypt.c"
#include "rogue/mdport.c"
#include "rogue/misc.c"
#include "rogue/monsters.c"
#include "rogue/move.c"
#include "rogue/new_level.c"
#include "rogue/options.c"
#include "rogue/pack.c"
#include "rogue/passages.c"
#include "rogue/potions.c"
#include "rogue/rings.c"
#include "rogue/rip.c"
#include "rogue/rooms.c"
#include "rogue/save.c"
#include "rogue/scrolls.c"
#include "rogue/state.c"
#include "rogue/sticks.c"
#include "rogue/things.c"
#include "rogue/weapons.c"
#include "rogue/wizard.c"
#elif BUILD_CUSTOMCC
#if BUILD_CUSTOMCC
#include "customcc.cpp"
#elif BUILD_GAMESCC
#include "rogue/cursesd.c"
#include "gamescc.cpp"
#else
#include "musig.cpp"
#include "dilithium.c"

3
src/cc/eval.cpp

@ -103,6 +103,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
switch ( ecode )
{
/*
case EVAL_IMPORTPAYOUT:
return ImportPayout(vparams, txTo, nIn);
break;
@ -110,7 +111,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
case EVAL_IMPORTCOIN:
return ImportCoin(vparams, txTo, nIn);
break;
*/
default:
return(ProcessCC(cp,this, vparams, txTo, nIn));
break;

1813
src/cc/gamescc.cpp

File diff suppressed because it is too large

4
src/cc/heir.cpp

@ -545,7 +545,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
funcId != 0 &&
isMyFuncId(funcId) &&
(typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid) > 0) && // token validation logic
(typeid(Helper) != typeid(TokenHelper) ) && // token validation logic
//(voutValue = IsHeirFundingVout<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))
{
@ -596,7 +596,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
if (funcId != 0 &&
(txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
isMyFuncId(funcId) && !isSpendingTx(funcId) &&
(typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid) > 0) &&
(typeid(Helper) != typeid(TokenHelper) ) &&
!myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, ivout)) // exclude tx in mempool
{
total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change)

3
src/cc/heir_validate.h

@ -68,9 +68,12 @@ class TokenHelper {
public:
static uint8_t getMyEval() { return EVAL_TOKENS; }
static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
/*
struct CCcontract_info *cpHeir, heirC;
cpHeir = CCinit(&heirC, EVAL_TOKENS);
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
*/
return 0;
}
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {

764
src/cc/import.cpp

@ -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();
}

1288
src/cc/importgateway.cpp

File diff suppressed because it is too large

8
src/cc/makeprices

@ -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 ..

7
src/cc/maketetris

@ -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 ..

14
src/coins.cpp

@ -557,17 +557,17 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
CAmount value,nResult = 0;
if ( interestp != 0 )
*interestp = 0;
if ( tx.IsCoinImport() )
return GetCoinImportValue(tx);
//if ( tx.IsCoinImport() )
// return GetCoinImportValue(tx);
if ( tx.IsCoinBase() != 0 )
return 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (tx.IsPegsImport() && i==0)
{
nResult = GetCoinImportValue(tx);
continue;
}
//if (tx.IsPegsImport() && i==0)
//{
// nResult = GetCoinImportValue(tx);
// continue;
//}
value = GetOutputFor(tx.vin[i]).nValue;
nResult += value;
}

132
src/crosschain.cpp

@ -223,32 +223,6 @@ cont:
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 &nota) {
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
* in: txid

2
src/crosschain.h

@ -38,10 +38,8 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int hushHeig
std::vector<uint256> &moms, uint256 &destNotarizationTxid);
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
const TxProof assetChainProof,int32_t offset);
void CompleteImportTransaction(CTransaction &importTx,int32_t offset);
/* On assetchain */
bool CheckMoMoM(uint256 hushNotarizationHash, uint256 momom);
bool CheckNotariesApproval(uint256 burntxid, const std::vector<uint256> & notaryTxids);
#endif /* HUSH_CROSSCHAIN_H */

425
src/importcoin.cpp

@ -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

@ -21,7 +21,6 @@
#include "sodium.h"
#include "addrman.h"
#include "arith_uint256.h"
#include "importcoin.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
@ -1850,11 +1849,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return state.Invalid(false, REJECT_DUPLICATE, "already have coins");
}
if (tx.IsCoinImport() || tx.IsPegsImport()) {
// Inverse of normal case; if input exists, it's been spent
if (ExistsImportTombstone(tx, view))
return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists");
} else {
//if (tx.IsCoinImport() || tx.IsPegsImport()) {
// // Inverse of normal case; if input exists, it's been spent
// if (ExistsImportTombstone(tx, view))
// return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists");
//} else
{
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
// and only helps with filling in pfMissingInputs (to determine missing vs spent).
@ -2599,10 +2599,10 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); // add outputs
// Unorthodox state
if (tx.IsCoinImport() || tx.IsPegsImport()) {
// add a tombstone for the burnTx
AddImportTombstone(tx, inputs, nHeight);
}
//if (tx.IsCoinImport() || tx.IsPegsImport()) {
// // add a tombstone for the burnTx
// AddImportTombstone(tx, inputs, nHeight);
//}
}
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
@ -2643,11 +2643,13 @@ namespace Consensus {
CAmount nFees = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
/*
if (tx.IsPegsImport() && i==0)
{
nValueIn=GetCoinImportValue(tx);
continue;
}
*/
const COutPoint &prevout = tx.vin[i].prevout;
const CCoins *coins = inputs.AccessCoins(prevout.hash);
assert(coins);
@ -2771,12 +2773,14 @@ bool ContextualCheckInputs(
}
}
/*
if (tx.IsCoinImport() || tx.IsPegsImport())
{
LOCK(cs_main);
ServerTransactionSignatureChecker checker(&tx, 0, 0, false, txdata);
return VerifyCoinImport(tx.vin[0].scriptSig, checker, state);
}
*/
return true;
}
@ -3051,10 +3055,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
}
}
}
/*
else if (tx.IsCoinImport() || tx.IsPegsImport())
{
RemoveImportTombstone(tx, view);
}
*/
}
// set the old best Sprout anchor back

14
src/miner.cpp

@ -25,7 +25,6 @@
#include "amount.h"
#include "chainparams.h"
#include "importcoin.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
@ -308,12 +307,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
bool fMissingInputs = false;
bool fNotarization = false;
std::vector<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();
bool fToCryptoAddress = false;
if ( numSN != 0 && notarypubkeys[0][0] != 0 && hush_is_notarytx(tx) == 1 )
@ -321,6 +321,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
/*
if (tx.IsPegsImport() && txin.prevout.n==10e8)
{
CAmount nValueIn = GetCoinImportValue(tx); // burn amount
@ -328,6 +329,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
dPriority += (double)nValueIn * 1000; // flat multiplier... max = 1e16.
continue;
}
*/
// Read prev transaction
if (!view.HaveCoins(txin.prevout.hash))
{

3
src/primitives/transaction.h

@ -711,7 +711,8 @@ public:
bool IsPegsImport() const
{
return (ASSETCHAINS_SELFIMPORT=="PEGSCC" && vin[0].prevout.n == 10e8);
//return (ASSETCHAINS_SELFIMPORT=="PEGSCC" && vin[0].prevout.n == 10e8);
return false;
}
friend bool operator==(const CTransaction& a, const CTransaction& b)

1185
src/rpc/crosschain.cpp

File diff suppressed because it is too large

9
src/rpc/rawtransaction.cpp

@ -144,9 +144,10 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
UniValue vin(UniValue::VARR);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
UniValue in(UniValue::VOBJ);
if (tx.IsCoinBase())
if (tx.IsCoinBase()) {
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
else if (tx.IsCoinImport() && txin.prevout.n==10e8) {
}
/* else if (tx.IsCoinImport() && txin.prevout.n==10e8) {
in.push_back(Pair("is_import", "1"));
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
if (UnmarshalImportTx(tx, proof, burnTx, payouts))
@ -168,7 +169,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
}
}
}
}
} */
else {
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
@ -216,6 +217,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
/*
if (txout.scriptPubKey.IsOpReturn() && txout.nValue != 0)
{
std::vector<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("scriptPubKey", o));
// Add spent information if spentindex is enabled

30
src/rpc/server.cpp

@ -346,16 +346,6 @@ static const CRPCCommand vRPCCommands[] =
{ "crosschain", "crosschainproof", &crosschainproof, true },
{ "crosschain", "getNotarizationsForBlock", &getNotarizationsForBlock, true },
{ "crosschain", "scanNotarizationsDB", &scanNotarizationsDB, true },
{ "crosschain", "getimports", &getimports, true },
{ "crosschain", "getwalletburntransactions", &getwalletburntransactions, true },
{ "crosschain", "migrate_converttoexport", &migrate_converttoexport, true },
{ "crosschain", "migrate_createburntransaction", &migrate_createburntransaction, true },
{ "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true },
{ "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true },
{ "crosschain", "migrate_checkburntransactionsource", &migrate_checkburntransactionsource, true },
{ "crosschain", "migrate_createnotaryapprovaltransaction", &migrate_createnotaryapprovaltransaction, true },
{ "crosschain", "selfimport", &selfimport, true },
{ "crosschain", "importdual", &importdual, true },
/* Mining */
{ "mining", "getblocktemplate", &getblocktemplate, true },
@ -443,26 +433,6 @@ static const CRPCCommand vRPCCommands[] =
{ "CClib", "cclibinfo", &cclibinfo, true },
{ "CClib", "cclib", &cclib, true },
// tokens & assets
{ "tokens", "assetsaddress", &assetsaddress, true },
{ "tokens", "tokeninfo", &tokeninfo, true },
{ "tokens", "tokenlist", &tokenlist, true },
{ "tokens", "tokenorders", &tokenorders, true },
{ "tokens", "mytokenorders", &mytokenorders, true },
{ "tokens", "tokenaddress", &tokenaddress, true },
{ "tokens", "tokenbalance", &tokenbalance, true },
{ "tokens", "tokencreate", &tokencreate, true },
{ "tokens", "tokentransfer", &tokentransfer, true },
{ "tokens", "tokenbid", &tokenbid, true },
{ "tokens", "tokencancelbid", &tokencancelbid, true },
{ "tokens", "tokenfillbid", &tokenfillbid, true },
{ "tokens", "tokenask", &tokenask, true },
//{ "tokens", "tokenswapask", &tokenswapask, true },
{ "tokens", "tokencancelask", &tokencancelask, true },
{ "tokens", "tokenfillask", &tokenfillask, true },
//{ "tokens", "tokenfillswap", &tokenfillswap, true },
{ "tokens", "tokenconvert", &tokenconvert, true },
/* Address index */
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
{ "addressindex", "getaddressutxos", &getaddressutxos, false },

17
src/rpc/server.h

@ -237,22 +237,7 @@ extern UniValue submitblock(const UniValue& params, bool fHelp, const CPubKey& m
extern UniValue estimatefee(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue estimatepriority(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokeninfo(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenlist(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue mytokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenbalance(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue assetsaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokencreate(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokentransfer(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenbid(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokencancelbid(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenfillbid(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenask(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokencancelask(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenfillask(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue tokenconvert(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue heiraddress(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue heirfund(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue heiradd(const UniValue& params, bool fHelp, const CPubKey& mypk);
@ -280,8 +265,6 @@ extern UniValue channelsopen(const UniValue& params, bool fHelp, const CPubKey&
extern UniValue channelspayment(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue channelsclose(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue channelsrefund(const UniValue& params, bool fHelp, const CPubKey& mypk);
//extern UniValue tokenswapask(const UniValue& params, bool fHelp, const CPubKey& mypk);
//extern UniValue tokenfillswap(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue faucetfund(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue faucetget(const UniValue& params, bool fHelp, const CPubKey& mypk);
extern UniValue faucetaddress(const UniValue& params, bool fHelp, const CPubKey& mypk);

260
src/test-hush/test_coinimport.cpp

@ -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 */

505
src/wallet/rpcwallet.cpp

@ -6403,19 +6403,6 @@ UniValue assetsaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
return(CCaddress(cp, (char *)"Assets", pubkey));
}
UniValue tokenaddress(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
struct CCcontract_info *cp,C; std::vector<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)
{
if ( fHelp || params.size() > 0 )
@ -6691,498 +6678,6 @@ UniValue faucetget(const UniValue& params, bool fHelp, const CPubKey& mypk)
return(result);
}
UniValue tokenlist(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
uint256 tokenid;
if ( fHelp || params.size() > 0 )
throw runtime_error("tokenlist\n");
if ( ensure_CCrequirements(EVAL_TOKENS) < 0 )
throw runtime_error(CC_REQUIREMENTS_MSG);
return(TokenList());
}
UniValue tokeninfo(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
uint256 tokenid;
if ( fHelp || params.size() != 1 )
throw runtime_error("tokeninfo tokenid\n");
if ( ensure_CCrequirements(EVAL_TOKENS) < 0 )
throw runtime_error(CC_REQUIREMENTS_MSG);
tokenid = Parseuint256((char *)params[0].get_str().c_str());
return(TokenInfo(tokenid));
}
UniValue tokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
uint256 tokenid;
if ( fHelp || params.size() > 1 )
throw runtime_error("tokenorders [tokenid]\n"
"returns token orders for the tokenid or all available token orders if tokenid is not set\n"
"(this rpc supports only fungible tokens)\n" "\n");
if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0)
throw runtime_error(CC_REQUIREMENTS_MSG);
if (params.size() == 1) {
tokenid = Parseuint256((char *)params[0].get_str().c_str());
if (tokenid == zeroid)
throw runtime_error("incorrect tokenid\n");
return AssetOrders(tokenid, CPubKey(), 0);
}
else {
// throw runtime_error("no tokenid\n");
return AssetOrders(zeroid, CPubKey(), 0);
}
}
UniValue mytokenorders(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
uint256 tokenid;
if (fHelp || params.size() > 1)
throw runtime_error("mytokenorders [evalcode]\n"
"returns all the token orders for mypubkey\n"
"if evalcode is set then returns mypubkey token orders for non-fungible tokens with this evalcode\n" "\n");
if (ensure_CCrequirements(EVAL_ASSETS) < 0 || ensure_CCrequirements(EVAL_TOKENS) < 0)
throw runtime_error(CC_REQUIREMENTS_MSG);
uint8_t additionalEvalCode = 0;
if (params.size() == 1)
additionalEvalCode = strtol(params[0].get_str().c_str(), NULL, 0); // supports also 0xEE-like values
return AssetOrders(zeroid, Mypubkey(), additionalEvalCode);
}
UniValue tokenbalance(const UniValue& params, bool fHelp, const CPubKey& mypk)
{
UniValue result(UniValue::VOBJ); uint256 tokenid; uint64_t balance; std::vector<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)
{
set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;

Loading…
Cancel
Save