diff --git a/migratecoin.md b/migratecoin.md deleted file mode 100644 index 7859bdff2..000000000 --- a/migratecoin.md +++ /dev/null @@ -1,61 +0,0 @@ -# MigrateCoin protocol - - - -## ExportCoins tx: - - - -``` - -vin: - - [ any ] - -vout: - - - amount: {burnAmount} - - script: OP_RETURN "send to ledger {id} {voutsHash}" - -``` - - - -* ExportCoin is a standard tx which burns coins in an OP_RETURN - - - -## ImportCoins tx: - - - -``` - -vin: - - - txid: 0000000000000000000000000000000000000000000000000000000000000000 - - idx: 0 - - script: CC_EVAL(EVAL_IMPORTCOINS, {momoProof},{exportCoin}) OP_CHECKCRYPTOCONDITION_UNILATERAL - -vout: - - - [ vouts matching voutsHash in exportCoin ] - -``` - - - -* ImportCoin transaction has no signature - -* ImportCoin is non malleable - -* ImportCoin satisfies tx.IsCoinBase() - -* ImportCoin uses a new opcode which allows a one sided check (no scriptPubKey) - -* ImportCoin must contain CC opcode EVAL_IMPORTCOINS - -* ImportCoin fees are equal to the difference between burnAmount in exportCoins and the sum of outputs. diff --git a/migratecoin.sh b/migratecoin.sh new file mode 100644 index 000000000..6cd09ba04 --- /dev/null +++ b/migratecoin.sh @@ -0,0 +1,43 @@ +#!/usr/bin/bash + +# This script makes the neccesary transactions to migrate +# coin between 2 assetchains on the same -ac_cc id + +set -e + +source=TXSCL +target=TXSCL000 +address="RFw7byY4xZpZCrtkMk3nFuuG1NTs9rSGgQ" +amount=1 + +# Alias for running cli on source chain +cli_source="komodo-cli -ac_name=$source" + +# Raw tx that we will work with +txraw=`$cli_source createrawtransaction "[]" "{\"$address\":$amount}"` + +# Convert to an export tx +exportData=`$cli_source migrate_converttoexport $txraw $target $amount` +exportRaw=`echo $exportData | jq -r .exportTx` +exportPayouts=`echo $exportData | jq -r .payouts` + +# Fund +exportFundedData=`$cli_source fundrawtransaction $exportRaw` +exportFundedTx=`echo $exportFundedData | jq -r .hex` + +# Sign +exportSignedData=`$cli_source signrawtransaction $exportFundedTx` +exportSignedTx=`echo $exportSignedData | jq -r .hex` + +# Send +echo "Sending export tx" +$cli_source sendrawtransaction $exportSignedTx + +read -p "Wait for a notarisation to KMD, and then two more notarisations from the target chain, and then press enter to continue" + +# Create import +importTx=`$cli_source migrate_createimporttransaction $exportSignedTx $payouts` +importTx=`komodo-cli migrate_completeimporttransaction $importTx` + +# Send import +komodo-cli -ac_name=$target sendrawtransaction $importTx diff --git a/src/Makefile.am b/src/Makefile.am index 5252b1fa0..7113a1e42 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -280,6 +280,7 @@ libbitcoin_server_a_SOURCES = \ chain.cpp \ checkpoints.cpp \ crosschain.cpp \ + crosschain_authority.cpp \ deprecation.cpp \ httprpc.cpp \ httpserver.cpp \ diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index b6fcf57dd..cb9774a7a 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -140,45 +140,17 @@ int32_t Eval::GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t time return komodo_notaries(pubkeys, height, timestamp); } - bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const { if (tx.vin.size() < 11) return false; - uint8_t seenNotaries[64] = {0}; - uint8_t notaries[64][33]; - int nNotaries = GetNotaries(notaries, height, timestamp); + CrosschainAuthority auth; + auth.requiredSigs = 11; + auth.size = GetNotaries(auth.notaries, height, timestamp); - BOOST_FOREACH(const CTxIn &txIn, tx.vin) - { - // Get notary pubkey - CTransaction tx; - uint256 hashBlock; - if (!GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; - if (tx.vout.size() < txIn.prevout.n) return false; - CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; - if (spk.size() != 35) return false; - const unsigned char *pk = spk.data(); - if (pk++[0] != 33) return false; - if (pk[33] != OP_CHECKSIG) return false; - - // Check it's a notary - for (int i=0; i params, const CTransaction &imp // check burn amount { - uint64_t burnAmount = burnTx.vout[0].nValue; + uint64_t burnAmount = burnTx.vout.back().nValue; if (burnAmount == 0) return Invalid("invalid-burn-amount"); uint64_t totalOut = 0; diff --git a/src/crosschain.cpp b/src/crosschain.cpp index 197390e59..76771b186 100644 --- a/src/crosschain.cpp +++ b/src/crosschain.cpp @@ -50,6 +50,8 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh int seenOwnNotarisations = 0; + int authority = GetSymbolAuthority(symbol); + for (int i=0; i kmdHeight) break; NotarisationsInBlock notarisations; @@ -72,8 +74,9 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh if (seenOwnNotarisations == 1) { BOOST_FOREACH(Notarisation& nota, notarisations) { - if (nota.second.ccId == targetCCid) - moms.push_back(nota.second.MoM); + if (GetSymbolAuthority(nota.second.symbol) == authority) + if (nota.second.ccId == targetCCid) + moms.push_back(nota.second.MoM); } } } diff --git a/src/crosschain.h b/src/crosschain.h index 15452ac63..65be53f92 100644 --- a/src/crosschain.h +++ b/src/crosschain.h @@ -3,6 +3,20 @@ #include "cc/eval.h" +const int CROSSCHAIN_KOMODO = 1; +const int CROSSCHAIN_TXSCL = 2; +const int CROSSCHAIN_STAKED = 3; + +typedef struct CrosschainAuthority { + uint8_t notaries[64][33]; + size_t size; + size_t requiredSigs; +} CrosschainAuthority; + +extern const CrosschainAuthority auth_STAKED; + +int GetSymbolAuthority(const char* symbol); +bool CheckTxAuthority(const CTransaction &tx, CrosschainAuthority auth); /* On assetchain */ TxProof GetAssetchainProof(uint256 hash); diff --git a/src/crosschain_authority.cpp b/src/crosschain_authority.cpp new file mode 100644 index 000000000..4913a4ea0 --- /dev/null +++ b/src/crosschain_authority.cpp @@ -0,0 +1,76 @@ +#include "cc/eval.h" +#include "crosschain.h" +#include "notarisationdb.h" +//#include "notaries_STAKED.h" + +const char *notaries_STAKEDcc[][2] = +{ + {"blackjok3r", "021914947402d936a89fbdd1b12be49eb894a1568e5e17bb18c8a6cffbd3dc106e" }, + {"alright", "0285657c689b903218c97f5f10fe1d10ace2ed6595112d9017f54fb42ea1c1dda8"}, + {"webworker01", "03d01b559004b88fe71f9034ca25c7da0c142e4428afc969473dfbd101c984e7b4"}, + {"CrisF", "03f87f1bccb744d90fdbf7fad1515a98e9fc7feb1800e460d2e7565b88c3971bf3"}, + {"daemonfox", "0383484bdc745b2b953c85b5a0c496a1f27bc42ae971f15779ed1532421b3dd943" }, + {"xrobesx", "020a403b030211c87c77fc3d397db91313d96b3b43b86ca15cb08481508a7f754f" }, + {"jorian", "02150c410a606b898bcab4f083e48e0f98a510e0d48d4db367d37f318d26ae72e3" }, + {"TonyL", "021a559101e355c907d9c553671044d619769a6e71d624f68bfec7d0afa6bd6a96" }, + {"Emman", "038f642dcdacbdf510b7869d74544dbc6792548d9d1f8d73a999dd9f45f513c935" }, +}; + + +int GetSymbolAuthority(const char* symbol) +{ + if (strlen(symbol) >= 5 && strncmp(symbol, "TXSCL", 5) == 0) + return CROSSCHAIN_TXSCL; + if (strlen(symbol) >= 6 && strncmp(symbol, "STAKED", 6) == 0) + return CROSSCHAIN_STAKED; + return CROSSCHAIN_KOMODO; +} + + +bool CheckTxAuthority(const CTransaction &tx, CrosschainAuthority auth) +{ + EvalRef eval; + + if (tx.vin.size() < auth.requiredSigs) return false; + + uint8_t seen[64] = {0}; + + BOOST_FOREACH(const CTxIn &txIn, tx.vin) + { + // Get notary pubkey + CTransaction tx; + uint256 hashBlock; + if (!eval->GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; + if (tx.vout.size() < txIn.prevout.n) return false; + CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; + if (spk.size() != 35) return false; + const unsigned char *pk = spk.data(); + if (pk++[0] != 33) return false; + if (pk[33] != OP_CHECKSIG) return false; + + // Check it's a notary + for (int i=0; i burnOpret; if (burnTx.vout.size() == 0) return false; - GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret); + GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); ss >> targetSymbol; ss >> payoutsHash); @@ -61,7 +61,7 @@ CAmount GetCoinImportValue(const CTransaction &tx) CTransaction burnTx; std::vector payouts; if (UnmarshalImportTx(tx, proof, burnTx, payouts)) { - return burnTx.vout.size() ? burnTx.vout[0].nValue : 0; + return burnTx.vout.size() ? burnTx.vout.back().nValue : 0; } return 0; } diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 4711a9afc..3fbcb25ff 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -18,6 +18,21 @@ #include "komodo_cJSON.h" +//include "notaries_STAKED.h" + +const char *notaries_STAKED[][2] = +{ + {"blackjok3r", "021914947402d936a89fbdd1b12be49eb894a1568e5e17bb18c8a6cffbd3dc106e" }, + {"alright", "0285657c689b903218c97f5f10fe1d10ace2ed6595112d9017f54fb42ea1c1dda8"}, + {"webworker01", "03d01b559004b88fe71f9034ca25c7da0c142e4428afc969473dfbd101c984e7b4"}, + {"CrisF", "03f87f1bccb744d90fdbf7fad1515a98e9fc7feb1800e460d2e7565b88c3971bf3"}, + {"daemonfox", "0383484bdc745b2b953c85b5a0c496a1f27bc42ae971f15779ed1532421b3dd943" }, + {"xrobesx", "020a403b030211c87c77fc3d397db91313d96b3b43b86ca15cb08481508a7f754f" }, + {"jorian", "02150c410a606b898bcab4f083e48e0f98a510e0d48d4db367d37f318d26ae72e3" }, + {"TonyL", "021a559101e355c907d9c553671044d619769a6e71d624f68bfec7d0afa6bd6a96" }, + {"Emman", "038f642dcdacbdf510b7869d74544dbc6792548d9d1f8d73a999dd9f45f513c935" }, +}; + #define KOMODO_MAINNET_START 178999 const char *Notaries_genesis[][2] = @@ -226,13 +241,24 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam { if ( did1 == 0 ) { - n1 = (int32_t)(sizeof(Notaries_elected1)/sizeof(*Notaries_elected1)); - for (i=0; i @@ -21,27 +22,27 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight) for (unsigned int i = 0; i < block.vtx.size(); i++) { CTransaction tx = block.vtx[i]; - // Special case for TXSCL. Should prob be removed at some point. - bool isTxscl = 0; - { - NotarisationData data; - if (ParseNotarisationOpReturn(tx, data)) - if (strlen(data.symbol) >= 5 && strncmp(data.symbol, "TXSCL", 5) == 0) - isTxscl = 1; + NotarisationData data; + bool parsed = ParseNotarisationOpReturn(tx, data); + if (!parsed) data = NotarisationData(); + int authority = GetSymbolAuthority(data.symbol); + + if (authority == CROSSCHAIN_KOMODO) { + if (!eval->CheckNotaryInputs(tx, nHeight, block.nTime)) + continue; + } else if (authority == CROSSCHAIN_STAKED) { + if (!CheckTxAuthority(tx, auth_STAKED)) + continue; } - if (isTxscl || eval->CheckNotaryInputs(tx, nHeight, block.nTime)) { - NotarisationData data; - if (ParseNotarisationOpReturn(tx, data)) { - vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); - //printf("Parsed a notarisation for: %s, txid:%s, ccid:%i, momdepth:%i\n", - // data.symbol, tx.GetHash().GetHex().data(), data.ccId, data.MoMDepth); - //if (!data.MoMoM.IsNull()) printf("MoMoM:%s\n", data.MoMoM.GetHex().data()); - } - else - LogPrintf("WARNING: Couldn't parse notarisation for tx: %s at height %i\n", - tx.GetHash().GetHex().data(), nHeight); - } + if (parsed) { + vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); + //printf("Parsed a notarisation for: %s, txid:%s, ccid:%i, momdepth:%i\n", + // data.symbol, tx.GetHash().GetHex().data(), data.ccId, data.MoMDepth); + //if (!data.MoMoM.IsNull()) printf("MoMoM:%s\n", data.MoMoM.GetHex().data()); + } else + LogPrintf("WARNING: Couldn't parse notarisation for tx: %s at height %i\n", + tx.GetHash().GetHex().data(), nHeight); } return vNotarisations; } diff --git a/src/notarisationdb.h b/src/notarisationdb.h index b8cd93691..f01a5a587 100644 --- a/src/notarisationdb.h +++ b/src/notarisationdb.h @@ -24,5 +24,6 @@ bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n); void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch); void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch); int ScanNotarisationsDB(int height, std::string symbol, int scanLimitBlocks, Notarisation& out); +bool IsTXSCL(const char* symbol); #endif /* NOTARISATIONDB_H */ diff --git a/src/test-komodo/test_coinimport.cpp b/src/test-komodo/test_coinimport.cpp index eac21428a..8c1d8b0f8 100644 --- a/src/test-komodo/test_coinimport.cpp +++ b/src/test-komodo/test_coinimport.cpp @@ -180,7 +180,7 @@ TEST_F(TestCoinImport, testInvalidBurnOutputs) TEST_F(TestCoinImport, testInvalidBurnParams) { - burnTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid)); + 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); @@ -198,7 +198,7 @@ TEST_F(TestCoinImport, testWrongChainId) TEST_F(TestCoinImport, testInvalidBurnAmount) { - burnTx.vout[0].nValue = 0; + burnTx.vout.back().nValue = 0; MoMoM = burnTx.GetHash(); // TODO: an actual branch CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); TestRunCCEval(tx);