Merge branch 'FSM' into jl777
This commit is contained in:
@@ -20,6 +20,10 @@
|
||||
#include "primitives/transaction.h"
|
||||
#include "cc/CCinclude.h"
|
||||
|
||||
//#define LEV_INFO 0
|
||||
//#define LEV_DEBUG1 1
|
||||
//#define LOGSTREAM(category, level, logoperator) { std::ostringstream stream; logoperator; for(int i = 0; i < level; i ++) if( LogAcceptCategory( (std::string(category) + (level > 0 ? std::string("-")+std::to_string(level) : std::string("") )).c_str() ) ) LogPrintStr(stream.str()); }
|
||||
|
||||
/*
|
||||
* CC Eval method for import coin.
|
||||
*
|
||||
@@ -33,63 +37,299 @@ extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT;
|
||||
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
|
||||
int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector<uint8_t> rawtx,uint256 txid,std::vector<uint8_t> rawproof) // find burnTx with hash from "other" daemon
|
||||
// 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 DecodeGatewaysBindOpRet(char *depositaddr, const CScript &scriptPubKey, std::string &coin, uint256 &tokenid, int64_t &totalsupply, uint256 &oracletxid, uint8_t &M, uint8_t &N, std::vector<CPubKey> &pubkeys, uint8_t &taddr, uint8_t &prefix, uint8_t &prefix2);
|
||||
|
||||
// ac_import=chain support:
|
||||
// encode opret for gateways import
|
||||
CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
MerkleBranch newBranch; CMutableTransaction tmpmtx; CTransaction tx,vintx; uint256 blockHash; char destaddr[64],pkaddr[64];
|
||||
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight());
|
||||
if ( source == "BEAM" )
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
bool ImportCoinGatewaysVerify(char *refdepositaddr, uint256 oracletxid, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vector<uint8_t>proof, uint256 merkleroot)
|
||||
{
|
||||
std::vector<uint256> txids;
|
||||
uint256 proofroot, hashBlock, foundtxid = zeroid;
|
||||
CTransaction oracletx, burntx;
|
||||
std::string name, description, format;
|
||||
char destaddr[64], destpubaddr[64], claimaddr[64];
|
||||
int32_t i, numvouts;
|
||||
int64_t nValue = 0;
|
||||
|
||||
if (myGetTransaction(oracletxid, oracletx, hashBlock) == 0 || (numvouts = oracletx.vout.size()) <= 0)
|
||||
{
|
||||
if ( ASSETCHAINS_BEAMPORT == 0 )
|
||||
return(-1);
|
||||
// confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn
|
||||
// return(0);
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify can't find oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
return false;
|
||||
}
|
||||
else if ( source == "CODA" )
|
||||
if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin)
|
||||
{
|
||||
if ( ASSETCHAINS_CODAPORT == 0 )
|
||||
return(-1);
|
||||
// confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn
|
||||
// return(0);
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
proofroot = BitcoinGetProofMerkleRoot(proof, txids);
|
||||
if (proofroot != merkleroot)
|
||||
{
|
||||
if ( !E_UNMARSHAL(rawtx, ss >> tx) )
|
||||
return(-1);
|
||||
scriptPubKey = tx.vout[0].scriptPubKey;
|
||||
mtx = tx;
|
||||
mtx.fOverwintered = tmpmtx.fOverwintered;
|
||||
mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
|
||||
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
|
||||
mtx.nVersion = tmpmtx.nVersion;
|
||||
mtx.vout.clear();
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].nValue = burnAmount;
|
||||
mtx.vout[0].scriptPubKey = scriptPubKey;
|
||||
if ( tx.GetHash() != txid )
|
||||
return(-1);
|
||||
if ( source == "PUBKEY" )
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check the burntxid is in the proof:
|
||||
if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify invalid proof for this burntxid=" << burntxid.GetHex() << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (DecodeHexTx(burntx, rawburntx) != 0)
|
||||
{
|
||||
Getscriptaddress(claimaddr, burntx.vout[claimvout].scriptPubKey);
|
||||
Getscriptaddress(destpubaddr, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
|
||||
if (strcmp(claimaddr, destpubaddr) == 0)
|
||||
{
|
||||
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
|
||||
if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,blockHash) == 0 )
|
||||
return(-1);
|
||||
if ( tx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr,vintx.vout[tx.vin[0].prevout.n].scriptPubKey) != 0 )
|
||||
for (i = 0; i<numvouts; i++)
|
||||
{
|
||||
pubkey2addr(pkaddr,ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
if ( strcmp(pkaddr,destaddr) == 0 )
|
||||
Getscriptaddress(destaddr, burntx.vout[i].scriptPubKey);
|
||||
if (strcmp(refdepositaddr, destaddr) == 0)
|
||||
{
|
||||
proof = std::make_pair(txid,newBranch);
|
||||
return(0);
|
||||
foundtxid = burntx.GetHash();
|
||||
nValue = burntx.vout[i].nValue;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr,"mismatched vin0[%d] -> %s vs %s\n",tx.vin[0].prevout.n,destaddr,pkaddr);
|
||||
}
|
||||
}
|
||||
else if ( source == ASSETCHAINS_SELFIMPORT )
|
||||
else fprintf(stderr, "claimaddr.(%s) != destpubaddr.(%s)\n", claimaddr, destpubaddr);
|
||||
}*/
|
||||
|
||||
/*
|
||||
if (foundtxid == burntxid) {
|
||||
LOGSTREAM("importcoin", LEV_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in merkleroot merkleroot" << std::endl);
|
||||
return(nValue);
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", LEV_INFO, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in merkleroot merkleroot" << std::endl);
|
||||
|
||||
fprintf(stderr, "(%s) != (%s) or txid %s mismatch.%d or script mismatch\n", refdepositaddr, destaddr, uint256_str(str, foundtxid), foundtxid != burntxid);
|
||||
*/
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in trusted merkleroot" << std::endl);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// make import tx with burntx and its proof of existence
|
||||
std::string MakeGatewaysImportTx(uint64_t txfee, uint256 bindtxid, int32_t height, std::string refcoin, std::vector<uint8_t>proof, std::string rawburntx, int32_t ivout, uint256 burntxid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction burntx, bindtx;
|
||||
CPubKey mypk, gatewayspk;
|
||||
uint256 oracletxid, merkleroot, mhash, hashBlock, tokenid, txid;
|
||||
int64_t totalsupply;
|
||||
int32_t i, m, n, numvouts;
|
||||
uint8_t M, N, taddr, prefix, prefix2;
|
||||
std::string coin;
|
||||
struct CCcontract_info *cp, C;
|
||||
std::vector<CPubKey> pubkeys, publishers;
|
||||
std::vector<uint256>txids;
|
||||
char depositaddr[64], txidaddr[64];
|
||||
|
||||
cp = CCinit(&C, EVAL_GATEWAYS);
|
||||
/*if (txfee == 0)
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
gatewayspk = GetUnspendable(cp, 0); */
|
||||
|
||||
if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx))
|
||||
return std::string("");
|
||||
|
||||
CAmount amount = GetCoinImportValue(burntx); // equal to int64_t
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl);
|
||||
|
||||
if (GetTransaction(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find bindtxid=" << bindtxid.GetHex() << std::endl);
|
||||
return("");
|
||||
}
|
||||
/* if (DecodeGatewaysBindOpRet(depositaddr, bindtx.vout[numvouts - 1].scriptPubKey, coin, tokenid, totalsupply, oracletxid, M, N, pubkeys, taddr, prefix, prefix2) != 'B' || refcoin != coin)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid coin - bindtxid=" << bindtxid.GetHex() << " coin=" << coin.c_str() << std::endl);
|
||||
return("");
|
||||
} eliminate link err */
|
||||
n = (int32_t)pubkeys.size();
|
||||
merkleroot = zeroid;
|
||||
for (i = m = 0; i < n; i++)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl);
|
||||
if ((mhash = GatewaysReverseScan(txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
|
||||
{
|
||||
// source is external coin is the assetchains symbol in the burnTx OP_RETURN
|
||||
// burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent
|
||||
if (merkleroot == zeroid)
|
||||
merkleroot = mhash, m = 1;
|
||||
else if (mhash == merkleroot)
|
||||
m ++;
|
||||
publishers.push_back(pubkeys[i]);
|
||||
txids.push_back(txid);
|
||||
}
|
||||
}
|
||||
return(-1);
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl);
|
||||
if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << coin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
|
||||
return("");
|
||||
}
|
||||
if (GatewaysCointxidExists(cp, burntxid) != 0)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " already exists" << std::endl);
|
||||
return("");
|
||||
}
|
||||
if (!ImportCoinGatewaysVerify(depositaddr, oracletxid, ivout, coin, burntxid, rawburntx, proof, merkleroot))
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx could not validate burntx, txid=" << burntxid.GetHex() << std::endl);
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint256> leaftxids;
|
||||
BitcoinGetProofMerkleRoot(proof, leaftxids);
|
||||
MerkleBranch newBranch(0, leaftxids);
|
||||
TxProof txProof = std::make_pair(burntxid, newBranch);
|
||||
|
||||
std::vector<CTxOut> vouts;
|
||||
|
||||
|
||||
|
||||
return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts)));
|
||||
|
||||
/*if (AddNormalinputs(mtx, mypk, 3 * txfee, 4) > 0)
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, destpub));
|
||||
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr, burntxid))) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeGatewaysImportTxOpRet(0xFFFFFFFF, coin, bindtxid, publishers, txids, height, burntxid, ivout, rawburntx, proof, destpub, amount)));
|
||||
}
|
||||
LOGSTREAM("importcoin", LEV_INFO, stream << "MakeGatewaysImportTx coud not find normal imputs" << std::endl);*/
|
||||
return("");
|
||||
}
|
||||
|
||||
// makes source tx for self import tx
|
||||
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx)
|
||||
{
|
||||
const int64_t txfee = 10000;
|
||||
int64_t inputs, change;
|
||||
CPubKey myPubKey = Mypubkey();
|
||||
struct CCcontract_info *cpDummy, C;
|
||||
|
||||
cpDummy = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
if( (inputs = AddNormalinputs(mtx, myPubKey, txfee, 4)) == 0 ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx: cannot find normal imputs for txfee" << std::endl);
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
mtx.vout.push_back(CTxOut(txfee, scriptPubKey));
|
||||
change = inputs - txfee;
|
||||
if( change != 0 )
|
||||
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG));
|
||||
|
||||
//make opret with amount:
|
||||
return FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount));
|
||||
}
|
||||
|
||||
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
|
||||
int32_t CheckVin0PubKey(const CTransaction &sourcetx)
|
||||
{
|
||||
CTransaction vintx;
|
||||
uint256 blockHash;
|
||||
char destaddr[64], pkaddr[64];
|
||||
|
||||
if( !myGetTransaction(sourcetx.vin[0].prevout.hash, vintx, blockHash) ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() could not load vintx" << sourcetx.vin[0].prevout.hash.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
if( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 )
|
||||
{
|
||||
pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
if (strcmp(pkaddr, destaddr) == 0) {
|
||||
return(0);
|
||||
}
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ac_import=PUBKEY support:
|
||||
// prepare a tx for creating import tx and quasi-burn tx
|
||||
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount) // find burnTx with hash from "other" daemon
|
||||
{
|
||||
MerkleBranch newBranch;
|
||||
CMutableTransaction tmpmtx;
|
||||
CTransaction sourcetx;
|
||||
|
||||
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_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;
|
||||
}
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl);
|
||||
|
||||
scriptPubKey = sourcetx.vout[ivout].scriptPubKey;
|
||||
|
||||
//mtx is template for import tx
|
||||
mtx = sourcetx;
|
||||
mtx.fOverwintered = tmpmtx.fOverwintered;
|
||||
|
||||
//malleability fix for burn tx:
|
||||
//mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
|
||||
mtx.nExpiryHeight = sourcetx.nExpiryHeight;
|
||||
|
||||
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
|
||||
mtx.nVersion = tmpmtx.nVersion;
|
||||
mtx.vout.clear();
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].nValue = burnAmount;
|
||||
mtx.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 (CheckVin0PubKey(sourcetx) < 0) {
|
||||
return -1;
|
||||
}
|
||||
proof = std::make_pair(sourcetxid, newBranch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// use proof from the above functions to validate the import
|
||||
@@ -116,9 +356,52 @@ int32_t CheckGATEWAYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransact
|
||||
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);
|
||||
fprintf(stderr,"proof txid.%s\n",proof.first.GetHex().c_str());
|
||||
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 (CheckVin0PubKey(sourcetx) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get source tx opret:
|
||||
std::vector<uint8_t> vopret;
|
||||
uint8_t evalCode, funcId;
|
||||
int64_t amount;
|
||||
|
||||
GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret);
|
||||
if (vopret.size() == 0 || !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || evalCode != EVAL_IMPORTCOIN || funcId != 'A') {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no 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);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &importTx,unsigned int nIn)
|
||||
@@ -132,10 +415,10 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
|
||||
return Invalid("invalid-params");
|
||||
// Control all aspects of this transaction
|
||||
// It should not be at all malleable
|
||||
if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash())
|
||||
if (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))
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof))
|
||||
return Invalid("invalid-burn-tx");
|
||||
// check burn amount
|
||||
{
|
||||
|
||||
@@ -26,14 +26,17 @@
|
||||
|
||||
int32_t komodo_nextheight();
|
||||
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts)
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts, uint32_t nExpiryHeightOverride)
|
||||
{
|
||||
std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN);
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload));
|
||||
mtx.vout = payouts;
|
||||
auto importData = E_MARSHAL(ss << proof; ss << burnTx);
|
||||
mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << importData));
|
||||
|
||||
if (nExpiryHeightOverride != 0)
|
||||
mtx.nExpiryHeight = nExpiryHeightOverride; //this is for construction of the tx used for validating importtx
|
||||
return CTransaction(mtx);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
CAmount GetCoinImportValue(const CTransaction &tx);
|
||||
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof,
|
||||
const CTransaction burnTx, const std::vector<CTxOut> payouts);
|
||||
const CTransaction burnTx, const std::vector<CTxOut> payouts, uint32_t nExpiryHeightOverride = 0);
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts,std::vector<uint8_t> rawproof);
|
||||
|
||||
|
||||
@@ -34,21 +34,27 @@
|
||||
#include "script/sign.h"
|
||||
#include "script/standard.h"
|
||||
|
||||
#include "key_io.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <univalue.h>
|
||||
#include <regex>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
extern uint16_t ASSETCHAINS_CODAPORT, ASSETCHAINS_BEAMPORT;
|
||||
|
||||
int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip);
|
||||
int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height);
|
||||
struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi);
|
||||
uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
|
||||
extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
uint256 Parseuint256(char *hexstr);
|
||||
int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector<uint8_t> rawtx,uint256 txid,std::vector<uint8_t> rawproof);
|
||||
|
||||
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx);
|
||||
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount);
|
||||
std::string MakeGatewaysImportTx(uint64_t txfee, uint256 bindtxid, int32_t height, std::string refcoin, std::vector<uint8_t>proof, std::string rawburntx, int32_t ivout, uint256 burntxid);
|
||||
|
||||
UniValue assetchainproof(const UniValue& params, bool fHelp)
|
||||
{
|
||||
@@ -256,6 +262,7 @@ UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp)
|
||||
TxProof proof = GetAssetchainProof(burnTx.GetHash(),burnTx);
|
||||
|
||||
CTransaction importTx = MakeImportCoinTransaction(proof, burnTx, payouts);
|
||||
|
||||
return HexStr(E_MARSHAL(ss << importTx));
|
||||
}
|
||||
|
||||
@@ -281,31 +288,122 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue selfimport(const UniValue& params, bool fHelp)
|
||||
{
|
||||
CMutableTransaction mtx;
|
||||
std::string source; TxProof proof; CTransaction burnTx,tx; CTxOut burnOut; uint64_t burnAmount; uint256 txid,blockHash; std::vector<CTxOut> vouts; std::vector<uint8_t> rawtx,rawproof; CScript scriptPubKey;
|
||||
UniValue result(UniValue::VOBJ);
|
||||
CMutableTransaction sourceMtx, templateMtx;
|
||||
std::string destaddr;
|
||||
std::string source;
|
||||
std::string rawsourcetx;
|
||||
CTransaction burnTx;
|
||||
CTxOut burnOut;
|
||||
uint64_t burnAmount;
|
||||
uint256 sourcetxid, blockHash;
|
||||
std::vector<CTxOut> vouts;
|
||||
std::vector<uint8_t> rawproof, rawproofEmpty;
|
||||
int32_t ivout = 0;
|
||||
CScript scriptPubKey;
|
||||
TxProof proof;
|
||||
|
||||
if ( ASSETCHAINS_SELFIMPORT.size() == 0 )
|
||||
throw runtime_error("selfimport only works on -ac_import chains");
|
||||
if (fHelp || params.size() < 3 || params.size() > 5 )
|
||||
throw runtime_error("selfimport rawtx txid burnamount [rawproof source]\n\n"
|
||||
"creates signed selfimport transaction");
|
||||
rawtx = ParseHex(params[0].get_str().c_str());
|
||||
txid = Parseuint256((char *)params[1].get_str().c_str()); // allow for txid != hash(rawtx)
|
||||
burnAmount = atof(params[2].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
source = ASSETCHAINS_SELFIMPORT;
|
||||
if ( params.size() >= 4 )
|
||||
|
||||
if (fHelp || params.size() != 2)
|
||||
throw runtime_error("selfimport destaddr amount\n"
|
||||
//old: "selfimport rawsourcetx sourcetxid {nvout|\"find\"} amount \n"
|
||||
//TODO: "or selfimport rawburntx burntxid {nvout|\"find\"} rawproof source bindtxid height} \n"
|
||||
"\ncreates self import coin transaction");
|
||||
|
||||
/* OLD selfimport schema:
|
||||
rawsourcetx = params[0].get_str();
|
||||
sourcetxid = Parseuint256((char *)params[1].get_str().c_str()); // allow for txid != hash(rawtx)
|
||||
|
||||
int32_t ivout = -1;
|
||||
if( params[2].get_str() != "find" ) {
|
||||
if( !std::all_of(params[2].get_str().begin(), params[2].get_str().end(), ::isdigit) ) // check if not all chars are digit
|
||||
throw std::runtime_error("incorrect nvout param");
|
||||
|
||||
ivout = atoi(params[2].get_str().c_str());
|
||||
}
|
||||
|
||||
burnAmount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999; */
|
||||
|
||||
destaddr = params[0].get_str();
|
||||
burnAmount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
|
||||
source = ASSETCHAINS_SELFIMPORT; //defaults to -ac_import=... param
|
||||
/* TODO for gateways:
|
||||
if ( params.size() >= 5 )
|
||||
{
|
||||
rawproof = ParseHex(params[3].get_str().c_str());
|
||||
if ( params.size() == 5 )
|
||||
source = params[4].get_str();
|
||||
rawproof = ParseHex(params[4].get_str().c_str());
|
||||
if ( params.size() == 6 )
|
||||
source = params[5].get_str();
|
||||
} */
|
||||
|
||||
|
||||
if (source == "BEAM")
|
||||
{
|
||||
if (ASSETCHAINS_BEAMPORT == 0)
|
||||
return(-1);
|
||||
// confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn
|
||||
// return(0);
|
||||
return -1;
|
||||
}
|
||||
if ( GetSelfimportProof(source,mtx,scriptPubKey,proof,burnAmount,rawtx,txid,rawproof) < 0 )
|
||||
throw std::runtime_error("Failed validating selfimport");
|
||||
vouts = mtx.vout;
|
||||
burnOut = MakeBurnOutput(burnAmount,0xffffffff,ASSETCHAINS_SELFIMPORT,vouts,rawproof);
|
||||
mtx.vout.clear();
|
||||
mtx.vout.push_back(burnOut);
|
||||
burnTx = mtx;
|
||||
return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proof,burnTx,vouts)));
|
||||
else if (source == "CODA")
|
||||
{
|
||||
if (ASSETCHAINS_CODAPORT == 0)
|
||||
return(-1);
|
||||
// confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn
|
||||
// return(0);
|
||||
return -1;
|
||||
}
|
||||
else if (source == "PUBKEY")
|
||||
{
|
||||
|
||||
CTxDestination dest = DecodeDestination(destaddr.c_str());
|
||||
rawsourcetx = MakeSelfImportSourceTx(dest, burnAmount, sourceMtx);
|
||||
sourcetxid = sourceMtx.GetHash();
|
||||
|
||||
// prepare self-import 'quasi-burn' tx and also create vout for import tx (in mtx.vout):
|
||||
if (GetSelfimportProof(source, templateMtx, scriptPubKey, proof, rawsourcetx, ivout, sourcetxid, burnAmount) < 0)
|
||||
throw std::runtime_error("Failed validating selfimport");
|
||||
|
||||
vouts = templateMtx.vout;
|
||||
burnOut = MakeBurnOutput(burnAmount, 0xffffffff, ASSETCHAINS_SELFIMPORT, vouts, rawproofEmpty);
|
||||
templateMtx.vout.clear();
|
||||
templateMtx.vout.push_back(burnOut); // burn tx has only opret with vouts and optional proof
|
||||
|
||||
burnTx = templateMtx; // complete the creation of 'quasi-burn' tx
|
||||
|
||||
std::string hextx = HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proof, burnTx, vouts)));
|
||||
|
||||
CTxDestination address;
|
||||
bool fValidAddress = ExtractDestination(scriptPubKey, address);
|
||||
|
||||
result.push_back(Pair("sourceTxHex", rawsourcetx));
|
||||
result.push_back(Pair("importTxHex", hextx));
|
||||
result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx
|
||||
result.push_back(Pair("DestinationAddress", EncodeDestination(address))); // notify user about the address where the funds will be sent
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (source == ASSETCHAINS_SELFIMPORT)
|
||||
{
|
||||
throw std::runtime_error("not implemented yet\n");
|
||||
|
||||
if (params.size() != 8)
|
||||
throw runtime_error("use \'selfimport rawburntx burntxid nvout rawproof source bindtxid height\' to import from a coin chain\n");
|
||||
|
||||
uint256 bindtxid = Parseuint256((char *)params[6].get_str().c_str());
|
||||
int32_t height = atoi((char *)params[7].get_str().c_str());
|
||||
|
||||
|
||||
// source is external coin is the assetchains symbol in the burnTx OP_RETURN
|
||||
// burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent
|
||||
std::string hextx = MakeGatewaysImportTx(0, bindtxid, height, source, rawproof, rawsourcetx, ivout, sourcetxid);
|
||||
|
||||
result.push_back(Pair("hex", hextx));
|
||||
result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp)
|
||||
|
||||
@@ -541,7 +541,8 @@ static const CRPCCommand vRPCCommands[] =
|
||||
/* Not shown in help */
|
||||
{ "hidden", "setmocktime", &setmocktime, true },
|
||||
{ "hidden", "test_ac", &test_ac, true },
|
||||
{ "hidden", "test_heirmarker", &test_heirmarker, true },
|
||||
{ "hidden", "test_heirmarker", &test_heirmarker, true },
|
||||
{ "hidden", "test_proof", &test_proof, true },
|
||||
{ "hidden", "test_burntx", &test_burntx, true },
|
||||
|
||||
|
||||
|
||||
@@ -478,6 +478,6 @@ extern UniValue paxwithdraw(const UniValue& params, bool fHelp);
|
||||
extern UniValue test_ac(const UniValue& params, bool fHelp);
|
||||
extern UniValue test_heirmarker(const UniValue& params, bool fHelp);
|
||||
extern UniValue test_burntx(const UniValue& params, bool fHelp);
|
||||
|
||||
extern UniValue test_proof(const UniValue& params, bool fHelp);
|
||||
|
||||
#endif // BITCOIN_RPCSERVER_H
|
||||
|
||||
@@ -7883,8 +7883,11 @@ UniValue test_heirmarker(const UniValue& params, bool fHelp)
|
||||
|
||||
cp = CCinit(&C, EVAL_HEIR);
|
||||
return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
UniValue test_burntx(const UniValue& params, bool fHelp)
|
||||
{
|
||||
// make fake token tx:
|
||||
@@ -7927,3 +7930,52 @@ UniValue test_burntx(const UniValue& params, bool fHelp)
|
||||
CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr);
|
||||
return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, EncodeTokenOpRet(tokenid, voutPubkeys, CScript())));
|
||||
}
|
||||
|
||||
UniValue test_proof(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
std::vector<uint8_t>proof;
|
||||
|
||||
if (fHelp || (params.size() != 2))
|
||||
throw runtime_error("incorrect params\n");
|
||||
|
||||
|
||||
proof = ParseHex(params[0].get_str());
|
||||
uint256 cointxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
|
||||
std::vector<uint256> txids;
|
||||
|
||||
CMerkleBlock merkleBlock;
|
||||
if (!E_UNMARSHAL(proof, ss >> merkleBlock)) {
|
||||
result.push_back(Pair("error", "could not unmarshal proof"));
|
||||
return result;
|
||||
}
|
||||
uint256 merkleRoot = merkleBlock.txn.ExtractMatches(txids);
|
||||
|
||||
result.push_back(Pair("source_root", merkleRoot.GetHex()));
|
||||
|
||||
for (int i = 0; i < txids.size(); i++)
|
||||
std::cerr << "merkle block txid=" << txids[0].GetHex() << std::endl;
|
||||
|
||||
|
||||
std::vector<bool> vMatches(txids.size());
|
||||
for (auto v : vMatches) v = true;
|
||||
CPartialMerkleTree verifTree(txids, vMatches);
|
||||
|
||||
result.push_back(Pair("verif_root", verifTree.ExtractMatches(txids).GetHex()));
|
||||
|
||||
if (std::find(txids.begin(), txids.end(), cointxid) == txids.end()) {
|
||||
fprintf(stderr, "invalid proof for this cointxid\n");
|
||||
}
|
||||
|
||||
std::vector<uint256> vMerkleTree;
|
||||
bool f;
|
||||
::BuildMerkleTree(&f, txids, vMerkleTree);
|
||||
|
||||
std::vector<uint256> vMerkleBranch = ::GetMerkleBranch(0, txids.size(), vMerkleTree);
|
||||
|
||||
uint256 ourResult = SafeCheckMerkleBranch(zeroid, vMerkleBranch, 0);
|
||||
result.push_back(Pair("SafeCheckMerkleBranch", ourResult.GetHex()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user