Scott Sadler
6 years ago
28 changed files with 879 additions and 223 deletions
@ -0,0 +1,70 @@ |
|||
#include "cc/eval.h" |
|||
#include "cc/utils.h" |
|||
#include "importcoin.h" |
|||
#include "primitives/transaction.h" |
|||
|
|||
|
|||
/*
|
|||
* 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. |
|||
*/ |
|||
bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn) |
|||
{ |
|||
if (importTx.vout.size() == 0) return Invalid("no-vouts"); |
|||
|
|||
// params
|
|||
MomoProof proof; |
|||
CTransaction burnTx; |
|||
if (!E_UNMARSHAL(params, ss >> proof; ss >> burnTx)) |
|||
return Invalid("invalid-params"); |
|||
|
|||
// Control all aspects of this transaction
|
|||
// It must not be at all malleable
|
|||
if (MakeImportCoinTransaction(proof, burnTx, importTx.vout).GetHash() != importTx.GetHash()) |
|||
return Invalid("non-canonical"); |
|||
|
|||
// burn params
|
|||
uint32_t chain; // todo
|
|||
uint256 payoutsHash; |
|||
std::vector<uint8_t> burnOpret; |
|||
if (burnTx.vout.size() == 0) return Invalid("invalid-burn-outputs"); |
|||
GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret); |
|||
if (!E_UNMARSHAL(burnOpret, ss >> VARINT(chain); ss >> payoutsHash)) |
|||
return Invalid("invalid-burn-params"); |
|||
|
|||
// check chain
|
|||
if (chain != GetCurrentLedgerID()) |
|||
return Invalid("importcoin-wrong-chain"); |
|||
|
|||
// check burn amount
|
|||
{ |
|||
uint64_t burnAmount = burnTx.vout[0].nValue; |
|||
if (burnAmount == 0) |
|||
return Invalid("invalid-burn-amount"); |
|||
uint64_t totalOut = 0; |
|||
for (int i=0; i<importTx.vout.size(); i++) |
|||
totalOut += importTx.vout[i].nValue; |
|||
if (totalOut > burnAmount) |
|||
return Invalid("payout-too-high"); |
|||
} |
|||
|
|||
// Check burntx shows correct outputs hash
|
|||
if (payoutsHash != SerializeHash(importTx.vout)) |
|||
return Invalid("wrong-payouts"); |
|||
|
|||
// Check proof confirms existance of burnTx
|
|||
{ |
|||
NotarisationData data; |
|||
if (!GetNotarisationData(proof.notarisationHeight, data, true)) |
|||
return Invalid("coudnt-load-momom"); |
|||
|
|||
if (data.MoMoM != proof.branch.Exec(burnTx.GetHash())) |
|||
return Invalid("momom-check-fail"); |
|||
} |
|||
|
|||
return Valid(); |
|||
} |
|||
|
|||
|
@ -0,0 +1,34 @@ |
|||
#ifndef CC_UTILS_H |
|||
#define CC_UTILS_H |
|||
|
|||
#include "streams.h" |
|||
#include "version.h" |
|||
|
|||
|
|||
/*
|
|||
* Serialisation boilerplate |
|||
*/ |
|||
|
|||
template <class T> |
|||
std::vector<uint8_t> SerializeF(const T f) |
|||
{ |
|||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); |
|||
f(ss); |
|||
return std::vector<unsigned char>(ss.begin(), ss.end()); |
|||
} |
|||
|
|||
template <class T> |
|||
bool DeserializeF(const std::vector<unsigned char> vIn, T f) |
|||
{ |
|||
CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); |
|||
try { |
|||
f(ss); |
|||
if (ss.eof()) return true; |
|||
} catch(...) {} |
|||
return false; |
|||
} |
|||
|
|||
#define E_MARSHAL(body) SerializeF([&] (CDataStream &ss) {body;}) |
|||
#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;}) |
|||
|
|||
#endif /* CC_UTILS_H */ |
@ -0,0 +1,217 @@ |
|||
#include "cc/eval.h" |
|||
#include "main.h" |
|||
#include "notarisationdb.h" |
|||
|
|||
|
|||
/* On KMD */ |
|||
uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vector<uint256> &moms, int* assetChainHeight) |
|||
{ |
|||
/*
|
|||
* Notaries don't wait for confirmation on KMD before performing a backnotarisation, |
|||
* but we need a determinable range that will encompass all merkle roots. Include MoMs |
|||
* including the block height of the last notarisation until the height before the |
|||
* previous notarisation. |
|||
*/ |
|||
if (targetCCid <= 1) |
|||
return uint256(); |
|||
|
|||
int seenOwnNotarisations = 0; |
|||
|
|||
// TODO: test height out of range
|
|||
// TODO: Make sure that boundary for moms is notarisation tx not block
|
|||
|
|||
for (int i=0; i<1440; i++) { |
|||
if (i > kmdHeight) break; |
|||
NotarisationsInBlock notarisations; |
|||
uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock; |
|||
if (!pnotarisations->Read(blockHash, notarisations)) |
|||
continue; |
|||
BOOST_FOREACH(Notarisation& nota, notarisations) { |
|||
NotarisationData& data = nota.second; |
|||
if (data.ccId != targetCCid) |
|||
continue; |
|||
if (strcmp(data.symbol, symbol) == 0) |
|||
{ |
|||
seenOwnNotarisations++; |
|||
if (seenOwnNotarisations == 2) |
|||
goto end; |
|||
if (seenOwnNotarisations == 1) |
|||
*assetChainHeight = data.height; // TODO: Needed?
|
|||
continue; // Don't include own MoMs
|
|||
} |
|||
if (seenOwnNotarisations == 1) |
|||
moms.push_back(data.MoM); |
|||
} |
|||
} |
|||
|
|||
end: |
|||
return GetMerkleRoot(moms); |
|||
} |
|||
|
|||
|
|||
/* On KMD */ |
|||
std::pair<uint256,MerkleBranch> GetCrossChainProof(uint256 txid, char* targetSymbol, |
|||
uint32_t targetCCid, uint256 notarisationTxid, MerkleBranch assetChainProof) |
|||
{ |
|||
/*
|
|||
* Here we are given a proof generated by an assetchain A which goes from given txid to |
|||
* an assetchain MoM. We need to go from the notarisationTxid for A to the MoMoM range of the |
|||
* backnotarisation for B (given by kmdheight of notarisation), find the MoM within the MoMs for |
|||
* that range, and finally extend the proof to lead to the MoMoM (proof root). |
|||
*/ |
|||
EvalRef eval; |
|||
uint256 MoM = assetChainProof.Exec(txid); |
|||
|
|||
// Get a kmd height for given notarisation Txid
|
|||
int kmdHeight; |
|||
{ |
|||
CTransaction sourceNotarisation; |
|||
uint256 hashBlock; |
|||
CBlockIndex blockIdx; |
|||
if (eval->GetTxConfirmed(notarisationTxid, sourceNotarisation, blockIdx)) |
|||
kmdHeight = blockIdx.nHeight; |
|||
else if (eval->GetTxUnconfirmed(notarisationTxid, sourceNotarisation, hashBlock)) |
|||
kmdHeight = chainActive.Tip()->nHeight; |
|||
else |
|||
throw std::runtime_error("Notarisation not found"); |
|||
} |
|||
|
|||
// Get MoMs for kmd height and symbol
|
|||
std::vector<uint256> moms; |
|||
int targetChainStartHeight; |
|||
uint256 MoMoM = GetProofRoot(targetSymbol, targetCCid, kmdHeight, moms, &targetChainStartHeight); |
|||
if (MoMoM.IsNull()) |
|||
throw std::runtime_error("No MoMs found"); |
|||
|
|||
// Find index of source MoM in MoMoM
|
|||
int nIndex; |
|||
for (nIndex=0; nIndex<moms.size(); nIndex++) |
|||
if (moms[nIndex] == MoM) |
|||
goto cont; |
|||
throw std::runtime_error("Couldn't find MoM within MoMoM set"); |
|||
cont: |
|||
|
|||
// Create a branch
|
|||
std::vector<uint256> newBranch; |
|||
{ |
|||
CBlock fakeBlock; |
|||
for (int i=0; i<moms.size(); i++) { |
|||
CTransaction fakeTx; |
|||
// first value in CTransaction memory is it's hash
|
|||
memcpy((void*)&fakeTx, moms[i].begin(), 32); |
|||
fakeBlock.vtx.push_back(fakeTx); |
|||
} |
|||
newBranch = fakeBlock.GetMerkleBranch(nIndex); |
|||
} |
|||
|
|||
// Concatenate branches
|
|||
MerkleBranch newProof = assetChainProof; |
|||
newProof << MerkleBranch(nIndex, newBranch); |
|||
|
|||
// Check proof
|
|||
if (newProof.Exec(txid) != MoMoM) |
|||
throw std::runtime_error("Proof check failed"); |
|||
|
|||
return std::make_pair(uint256(), newProof); |
|||
} |
|||
|
|||
|
|||
/* On assetchain */ |
|||
bool ValidateCrossChainProof(uint256 txid, int notarisationHeight, MerkleBranch proof) |
|||
{ |
|||
/*
|
|||
* Here we are given a notarisation txid, and a proof. |
|||
* We go from the notarisation to get the backnotarisation, and verify the proof |
|||
* against the MoMoM it contains. |
|||
*/ |
|||
} |
|||
|
|||
|
|||
|
|||
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); |
|||
|
|||
/*
|
|||
* On assetchain |
|||
* in: txid |
|||
* out: pair<notarisationTxHash,merkleBranch> |
|||
*/ |
|||
std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash) |
|||
{ |
|||
uint256 notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex; |
|||
std::vector<uint256> branch; |
|||
int nIndex,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; |
|||
|
|||
{ |
|||
uint256 blockHash; |
|||
CTransaction tx; |
|||
if (!GetTransaction(hash, tx, blockHash, true)) |
|||
throw std::runtime_error("cannot find transaction"); |
|||
|
|||
blockIndex = mapBlockIndex[blockHash]; |
|||
|
|||
depth = komodo_MoM(¬arisedHeight, &MoM, ¬arisationHash, blockIndex->nHeight,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi); |
|||
|
|||
if (!depth) |
|||
throw std::runtime_error("notarisation not found"); |
|||
|
|||
// index of block in MoM leaves
|
|||
nIndex = notarisedHeight - blockIndex->nHeight; |
|||
} |
|||
|
|||
// build merkle chain from blocks to MoM
|
|||
{ |
|||
// since the merkle branch code is tied up in a block class
|
|||
// and we want to make a merkle branch for something that isnt transactions
|
|||
CBlock fakeBlock; |
|||
for (int i=0; i<depth; i++) { |
|||
uint256 mRoot = chainActive[notarisedHeight - i]->hashMerkleRoot; |
|||
CTransaction fakeTx; |
|||
// first value in CTransaction memory is it's hash
|
|||
memcpy((void*)&fakeTx, mRoot.begin(), 32); |
|||
fakeBlock.vtx.push_back(fakeTx); |
|||
} |
|||
branch = fakeBlock.GetMerkleBranch(nIndex); |
|||
|
|||
// Check branch
|
|||
if (MoM != CBlock::CheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex)) |
|||
throw std::runtime_error("Failed merkle block->MoM"); |
|||
} |
|||
|
|||
// Now get the tx merkle branch
|
|||
{ |
|||
CBlock block; |
|||
|
|||
if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0) |
|||
throw std::runtime_error("Block not available (pruned data)"); |
|||
|
|||
if(!ReadBlockFromDisk(block, blockIndex,1)) |
|||
throw std::runtime_error("Can't read block from disk"); |
|||
|
|||
// Locate the transaction in the block
|
|||
int nTxIndex; |
|||
for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++) |
|||
if (block.vtx[nTxIndex].GetHash() == hash) |
|||
break; |
|||
|
|||
if (nTxIndex == (int)block.vtx.size()) |
|||
throw std::runtime_error("Error locating tx in block"); |
|||
|
|||
std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex); |
|||
|
|||
// Check branch
|
|||
if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex)) |
|||
throw std::runtime_error("Failed merkle tx->block"); |
|||
|
|||
// concatenate branches
|
|||
nIndex = (nIndex << txBranch.size()) + nTxIndex; |
|||
branch.insert(branch.begin(), txBranch.begin(), txBranch.end()); |
|||
} |
|||
|
|||
// Check the proof
|
|||
if (MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex)) |
|||
throw std::runtime_error("Failed validating MoM"); |
|||
|
|||
// All done!
|
|||
CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); |
|||
return std::make_pair(notarisationHash, MerkleBranch(nIndex, branch)); |
|||
} |
@ -0,0 +1,21 @@ |
|||
#ifndef CROSSCHAIN_H |
|||
#define CROSSCHAIN_H |
|||
|
|||
#include "cc/eval.h" |
|||
|
|||
|
|||
/* On assetchain */ |
|||
std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash); |
|||
|
|||
/* On KMD */ |
|||
uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vector<uint256> &moms, int* assetChainHeight); |
|||
|
|||
/* On KMD */ |
|||
std::pair<uint256,MerkleBranch> GetCrossChainProof(uint256 txid, char* targetSymbol, |
|||
uint32_t targetCCid, uint256 notarisationTxid, MerkleBranch assetChainProof); |
|||
|
|||
/* On assetchain */ |
|||
bool ValidateCrossChainProof(uint256 txid, int notarisationHeight, MerkleBranch proof); |
|||
|
|||
|
|||
#endif /* CROSSCHAIN_H */ |
@ -0,0 +1,46 @@ |
|||
#include "leveldbwrapper.h" |
|||
#include "notarisationdb.h" |
|||
#include "uint256.h" |
|||
#include "cc/eval.h" |
|||
|
|||
#include <boost/foreach.hpp> |
|||
|
|||
|
|||
NotarisationDB *pnotarisations; |
|||
|
|||
|
|||
NotarisationDB::NotarisationDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "notarisations", nCacheSize, fMemory, fWipe, false, 64) { |
|||
} |
|||
|
|||
NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight) |
|||
{ |
|||
EvalRef eval; |
|||
NotarisationsInBlock vNotarisations; |
|||
bool IsBackNotarisation = ASSETCHAINS_SYMBOL[0] != 0; |
|||
|
|||
for (unsigned int i = 0; i < block.vtx.size(); i++) { |
|||
CTransaction tx = block.vtx[i]; |
|||
if (eval->CheckNotaryInputs(tx, nHeight, block.nTime)) { |
|||
NotarisationData data(IsBackNotarisation); |
|||
if (ParseNotarisationOpReturn(tx, data)) |
|||
vNotarisations.push_back(std::make_pair(tx.GetHash(), data)); |
|||
else |
|||
fprintf(stderr, "Warning: Couldn't parse notarisation for tx: %s at height %i\n", |
|||
tx.GetHash().GetHex().data(), nHeight); |
|||
} |
|||
} |
|||
return vNotarisations; |
|||
} |
|||
|
|||
|
|||
/*
|
|||
* Write an index of KMD notarisation id -> backnotarisation |
|||
*/ |
|||
void WriteBackNotarisations(NotarisationsInBlock notarisations) |
|||
{ |
|||
BOOST_FOREACH(Notarisation &n, notarisations) |
|||
{ |
|||
if (n.second.IsBackNotarisation) |
|||
pnotarisations->Write(n.second.txHash, n); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
#ifndef NOTARISATIONDB_H |
|||
#define NOTARISATIONDB_H |
|||
|
|||
#include "uint256.h" |
|||
#include "leveldbwrapper.h" |
|||
#include "cc/eval.h" |
|||
|
|||
|
|||
class NotarisationDB : public CLevelDBWrapper |
|||
{ |
|||
public: |
|||
NotarisationDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); |
|||
}; |
|||
|
|||
|
|||
extern NotarisationDB *pnotarisations; |
|||
|
|||
|
|||
typedef std::pair<uint256,NotarisationData> Notarisation; |
|||
typedef std::vector<Notarisation> NotarisationsInBlock; |
|||
|
|||
NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight); |
|||
|
|||
void WriteBackNotarisations(NotarisationsInBlock notarisations); |
|||
|
|||
#endif /* NOTARISATIONDB_H */ |
@ -0,0 +1,267 @@ |
|||
#include <zmq.h> |
|||
#include <stdio.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
|
|||
#include <cryptoconditions.h> |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "cc/eval.h" |
|||
#include "importcoin.h" |
|||
#include "base58.h" |
|||
#include "core_io.h" |
|||
#include "crosschain.h" |
|||
#include "key.h" |
|||
#include "main.h" |
|||
#include "primitives/block.h" |
|||
#include "primitives/transaction.h" |
|||
#include "script/cc.h" |
|||
#include "script/interpreter.h" |
|||
#include "script/serverchecker.h" |
|||
#include "txmempool.h" |
|||
#include "crosschain.h" |
|||
|
|||
#include "testutils.h" |
|||
|
|||
|
|||
extern uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth); |
|||
|
|||
|
|||
/*
|
|||
* Tests for the whole process of creating and validating notary proofs |
|||
* using proof roots (MoMoMs). This is to support coin imports. |
|||
*/ |
|||
|
|||
namespace TestCrossChainProof { |
|||
|
|||
|
|||
class TestCrossChain : public ::testing::Test, public Eval { |
|||
public: |
|||
bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const |
|||
{ |
|||
NotarisationData data; |
|||
return ParseNotarisationOpReturn(tx, data); |
|||
} |
|||
protected: |
|||
static void SetUpTestCase() { } |
|||
virtual void SetUp() { |
|||
ASSETCHAINS_CC = 1; |
|||
EVAL_TEST = this; |
|||
} |
|||
}; |
|||
|
|||
|
|||
|
|||
TEST_F(TestCrossChain, testCreateAndValidateImportProof) |
|||
{ |
|||
/*
|
|||
* This tests the full process of creation of a cross chain proof. |
|||
* For the purposes of the test we will use one assetchain and a KMD chain. |
|||
* |
|||
* In order to do this test, we need 2 blockchains, so we'll fork and make a socket |
|||
* for IPC. |
|||
*/ |
|||
|
|||
int childPid = fork(); |
|||
void *ctx = zmq_ctx_new(); |
|||
void *socket = zmq_socket(ctx, ZMQ_PAIR); |
|||
setupChain(); |
|||
std::vector<CBlock> blocks; |
|||
blocks.resize(10); |
|||
NotarisationData a2kmd, kmd2a(true); |
|||
|
|||
|
|||
auto SendIPC = [&] (std::vector<uint8_t> v) { |
|||
assert(v.size() == zmq_send(socket, v.data(), v.size(), 0)); |
|||
}; |
|||
|
|||
auto RecvIPC = [&] () { |
|||
std::vector<uint8_t> out; |
|||
out.resize(100000); |
|||
int len = zmq_recv(socket, out.data(), out.size(), 0); |
|||
assert(len != -1); |
|||
out.resize(len); |
|||
return out; |
|||
}; |
|||
|
|||
auto RecordNotarisation = [&] (CTransaction inputTx, NotarisationData data) { |
|||
CMutableTransaction mtx = spendTx(inputTx); |
|||
mtx.vout.resize(2); |
|||
mtx.vout[0].scriptPubKey << VCH(notaryKey.GetPubKey().begin(), 33) << OP_CHECKSIG; |
|||
mtx.vout[1].scriptPubKey << OP_RETURN << E_MARSHAL(ss << data); |
|||
mtx.vout[1].nValue = 0; |
|||
mtx.vin[0].scriptSig << getSig(mtx, inputTx.vout[0].scriptPubKey); |
|||
|
|||
acceptTxFail(CTransaction(mtx)); |
|||
printf("accept %snotarisation: %s\n", data.IsBackNotarisation ? "back" : "", |
|||
mtx.GetHash().GetHex().data()); |
|||
return mtx.GetHash(); |
|||
}; |
|||
|
|||
auto RunTestAssetchain = [&] () |
|||
{ |
|||
NotarisationData back(1); |
|||
strcpy(ASSETCHAINS_SYMBOL, "symbolA"); |
|||
strcpy(a2kmd.symbol, "symbolA"); |
|||
a2kmd.ccId = 2; |
|||
|
|||
/*
|
|||
* Notarisation 1 |
|||
*/ |
|||
generateBlock(&blocks[1]); |
|||
generateBlock(&blocks[2]); |
|||
a2kmd.blockHash = blocks[2].GetHash(); |
|||
a2kmd.MoM = komodo_calcMoM(a2kmd.height = chainActive.Height(), a2kmd.MoMDepth = 2); |
|||
SendIPC(E_MARSHAL(ss << a2kmd)); |
|||
E_UNMARSHAL(RecvIPC(), ss >> back); |
|||
RecordNotarisation(blocks[1].vtx[0], back); |
|||
|
|||
/*
|
|||
* Notarisation 2 |
|||
*/ |
|||
generateBlock(&blocks[3]); |
|||
generateBlock(&blocks[4]); |
|||
a2kmd.blockHash = blocks[4].GetHash(); |
|||
a2kmd.MoM = komodo_calcMoM(a2kmd.height = chainActive.Height(), a2kmd.MoMDepth = 2); |
|||
SendIPC(E_MARSHAL(ss << a2kmd)); |
|||
E_UNMARSHAL(RecvIPC(), ss >> back); |
|||
RecordNotarisation(blocks[3].vtx[0], back); |
|||
|
|||
/*
|
|||
* Generate proof |
|||
*/ |
|||
generateBlock(&blocks[5]); |
|||
uint256 txid = blocks[3].vtx[0].GetHash(); |
|||
std::pair<uint256,MerkleBranch> assetChainProof = GetAssetchainProof(txid); |
|||
SendIPC(E_MARSHAL(ss << txid; ss << assetChainProof)); |
|||
}; |
|||
|
|||
auto RunTestKmd = [&] () |
|||
{ |
|||
NotarisationData n; |
|||
|
|||
/*
|
|||
* Notarisation 1 |
|||
*/ |
|||
E_UNMARSHAL(RecvIPC(), ss >> n); |
|||
// Grab a coinbase input to fund notarisation
|
|||
generateBlock(&blocks[1]); |
|||
n.txHash = RecordNotarisation(blocks[1].vtx[0], a2kmd); |
|||
n.height = chainActive.Height(); |
|||
SendIPC(E_MARSHAL(ss << n)); |
|||
|
|||
/*
|
|||
* Notarisation 2 |
|||
*/ |
|||
E_UNMARSHAL(RecvIPC(), ss >> n); |
|||
// Grab a coinbase input to fund notarisation
|
|||
generateBlock(&blocks[2]); |
|||
n.txHash = RecordNotarisation(blocks[2].vtx[0], a2kmd); |
|||
n.height = chainActive.Height(); |
|||
SendIPC(E_MARSHAL(ss << n)); |
|||
|
|||
/*
|
|||
* Extend proof |
|||
*/ |
|||
std::pair<uint256,MerkleBranch> assetChainProof; |
|||
uint256 txid; |
|||
// Extend proof to MoMoM
|
|||
assert(E_UNMARSHAL(RecvIPC(), ss >> txid; ss >> kmd2a)); |
|||
std::pair<uint256,MerkleBranch> ccProof = GetCrossChainProof(txid, (char*)"symbolA", |
|||
2, assetChainProof.first, assetChainProof.second); |
|||
}; |
|||
|
|||
const char endpoint[] = "ipc://tmpKomodoTestCrossChainSock"; |
|||
|
|||
if (!childPid) { |
|||
assert(0 == zmq_connect(socket, endpoint)); |
|||
usleep(20000); |
|||
RunTestAssetchain(); |
|||
exit(0); |
|||
} |
|||
else { |
|||
assert(0 == zmq_bind(socket, endpoint)); |
|||
RunTestKmd(); |
|||
int returnStatus; |
|||
waitpid(childPid, &returnStatus, 0); |
|||
unlink("tmpKomodoTestCrossChainSock"); |
|||
ASSERT_EQ(0, returnStatus); |
|||
} |
|||
|
|||
|
|||
|
|||
/*
|
|||
|
|||
* |
|||
* Assetchain notarisation 2 |
|||
* |
|||
|
|||
ON_ASSETCHAIN { |
|||
a2kmd.blockHash = blocks[4].GetHash(); |
|||
a2kmd.MoM = komodo_calcMoM(a2kmd.height = chainActive.Height(), a2kmd.MoMDepth = 2); |
|||
SendIPC(E_MARSHAL(ss << a2kmd)); |
|||
} |
|||
|
|||
ON_KMD { |
|||
assert(E_UNMARSHAL(RecvIPC(), ss >> a2kmd)); |
|||
// Grab a coinbase input to fund notarisation
|
|||
RecordNotarisation(blocks[2].vtx[0], a2kmd); |
|||
} |
|||
|
|||
generateBlock(&blocks[5]); |
|||
generateBlock(&blocks[6]); |
|||
|
|||
* |
|||
* Backnotarisation |
|||
* |
|||
* This is what will contain the MoMoM which allows us to prove across chains |
|||
* |
|||
std::vector<uint256> moms; |
|||
int assetChainHeight; |
|||
|
|||
ON_KMD { |
|||
memset(kmd2a.txHash.begin(), 1, 32); // Garbage but non-null
|
|||
kmd2a.symbol[0] = 0; // KMD
|
|||
kmd2a.MoMoM = GetProofRoot((char*)"symbolA", 2, chainActive.Height(), moms, &assetChainHeight); |
|||
kmd2a.MoMoMDepth = 0; // Needed?
|
|||
SendIPC(E_MARSHAL(ss << kmd2a)); |
|||
} |
|||
|
|||
ON_ASSETCHAIN { |
|||
assert(E_UNMARSHAL(RecvIPC(), ss >> kmd2a)); |
|||
RecordNotarisation(blocks[1].vtx[0], kmd2a); |
|||
} |
|||
|
|||
|
|||
* |
|||
* We can now prove a tx from A on A, via a merkle root backpropagated from KMD. |
|||
* |
|||
* The transaction that we'll try to prove is the coinbase from the 3rd block. |
|||
* We should be able to start with only that transaction ID, and generate a merkle |
|||
* proof. |
|||
* |
|||
|
|||
std::pair<uint256,MerkleBranch> assetChainProof; |
|||
uint256 txid; |
|||
|
|||
ON_ASSETCHAIN { |
|||
txid = blocks[2].vtx[0].GetHash(); |
|||
|
|||
// First thing to do is get the proof from the assetchain
|
|||
assetChainProof = GetAssetchainProof(txid); |
|||
SendIPC(E_MARSHAL(ss << txid; ss << assetChainProof)); |
|||
} |
|||
|
|||
ON_KMD { |
|||
// Extend proof to MoMoM
|
|||
assert(E_UNMARSHAL(RecvIPC(), ss >> txid; ss >> kmd2a)); |
|||
std::pair<uint256,MerkleBranch> ccProof = GetCrossChainProof(txid, (char*)"symbolA", |
|||
2, assetChainProof.first, assetChainProof.second); |
|||
} |
|||
|
|||
*/ |
|||
} |
|||
|
|||
|
|||
} /* namespace TestCrossChainProof */ |
Loading…
Reference in new issue