2 #include "importcoin.h"
4 #include "notarisationdb.h"
5 #include "komodo_structs.h"
9 * This file is built in the server
13 uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
14 std::vector<uint256> &moms, uint256 &destNotarisationTxid)
17 * Notaries don't wait for confirmation on KMD before performing a backnotarisation,
18 * but we need a determinable range that will encompass all merkle roots. Include MoMs
19 * including the block height of the last notarisation until the height before the
20 * previous notarisation.
22 * kmdHeight notarisations-0 notarisations-1
23 * | |********************|
30 if (kmdHeight < 0 || kmdHeight > chainActive.Height())
33 int seenOwnNotarisations = 0;
35 for (int i=0; i<1440; i++) {
36 if (i > kmdHeight) break;
37 NotarisationsInBlock notarisations;
38 uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock;
39 if (!GetBlockNotarisations(blockHash, notarisations))
41 BOOST_FOREACH(Notarisation& nota, notarisations) {
42 NotarisationData& data = nota.second;
43 if (data.ccId != targetCCid)
45 if (strcmp(data.symbol, symbol) == 0)
47 seenOwnNotarisations++;
48 if (seenOwnNotarisations == 2)
50 if (seenOwnNotarisations == 1)
51 destNotarisationTxid = nota.first;
53 if (seenOwnNotarisations == 1)
54 moms.push_back(data.MoM);
59 return GetMerkleRoot(moms);
64 TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
65 const TxProof assetChainProof)
68 * Here we are given a proof generated by an assetchain A which goes from given txid to
69 * an assetchain MoM. We need to go from the notarisationTxid for A to the MoMoM range of the
70 * backnotarisation for B (given by kmdheight of notarisation), find the MoM within the MoMs for
71 * that range, and finally extend the proof to lead to the MoMoM (proof root).
74 uint256 MoM = assetChainProof.second.Exec(txid);
76 // Get a kmd height for given notarisation Txid
79 CTransaction sourceNotarisation;
82 if (eval->GetTxConfirmed(assetChainProof.first, sourceNotarisation, blockIdx))
83 kmdHeight = blockIdx.nHeight;
84 else if (eval->GetTxUnconfirmed(assetChainProof.first, sourceNotarisation, hashBlock))
85 kmdHeight = chainActive.Tip()->nHeight;
87 throw std::runtime_error("Notarisation not found");
90 // Get MoMs for kmd height and symbol
91 std::vector<uint256> moms;
92 uint256 targetChainNotarisationTxid;
93 uint256 MoMoM = CalculateProofRoot(targetSymbol, targetCCid, kmdHeight, moms, targetChainNotarisationTxid);
95 throw std::runtime_error("No MoMs found");
97 // Find index of source MoM in MoMoM
99 for (nIndex=0; nIndex<moms.size(); nIndex++) {
100 if (moms[nIndex] == MoM)
103 throw std::runtime_error("Couldn't find MoM within MoMoM set");
107 std::vector<uint256> vBranch;
110 for (int i=0; i<moms.size(); i++) {
112 // first value in CTransaction memory is it's hash
113 memcpy((void*)&fakeTx, moms[i].begin(), 32);
114 fakeBlock.vtx.push_back(fakeTx);
116 vBranch = fakeBlock.GetMerkleBranch(nIndex);
119 // Concatenate branches
120 MerkleBranch newBranch = assetChainProof.second;
121 newBranch << MerkleBranch(nIndex, vBranch);
124 if (newBranch.Exec(txid) != MoMoM)
125 throw std::runtime_error("Proof check failed");
127 return std::make_pair(targetChainNotarisationTxid,newBranch);
132 * Takes an importTx that has proof leading to assetchain root
133 * and extends proof to cross chain root
135 void CompleteImportTransaction(CTransaction &importTx)
139 std::vector<CTxOut> payouts;
140 if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
141 throw std::runtime_error("Couldn't parse importTx");
143 std::string targetSymbol;
146 if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash))
147 throw std::runtime_error("Couldn't parse burnTx");
149 proof = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, proof);
151 importTx = MakeImportCoinTransaction(proof, burnTx, importTx.vout);
155 struct notarized_checkpoint *komodo_npptr_at(int idx);
156 struct notarized_checkpoint *komodo_npptr_for_height(int32_t height, int *idx);
160 bool GetNextBacknotarisation(uint256 kmdNotarisationTxid, std::pair<uint256,NotarisationData> &out)
163 * Here we are given a txid, and a proof.
164 * We go from the KMD notarisation txid to the backnotarisation,
165 * then jump to the next backnotarisation, which contains the corresponding MoMoM.
168 if (!GetBackNotarisation(kmdNotarisationTxid, bn))
172 struct notarized_checkpoint* np = komodo_npptr_for_height(bn.second.height, &npIdx);
173 if (!(np = komodo_npptr_at(npIdx+1)))
176 return GetBackNotarisation(np->notarized_desttxid, out);
177 throw std::runtime_error("Can't get backnotarisation");
181 struct notarized_checkpoint* komodo_npptr(int32_t height);
183 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);
185 uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
190 * out: pair<notarisationTxHash,merkleBranch>
192 TxProof GetAssetchainProof(uint256 hash)
195 CBlockIndex* blockIndex;
196 struct notarized_checkpoint* np;
197 std::vector<uint256> branch;
202 if (!GetTransaction(hash, tx, blockHash, true))
203 throw std::runtime_error("cannot find transaction");
205 blockIndex = mapBlockIndex[blockHash];
206 if (!(np = komodo_npptr(blockIndex->nHeight)))
207 throw std::runtime_error("notarisation not found");
209 // index of block in MoM leaves
210 nIndex = np->notarized_height - blockIndex->nHeight;
213 // build merkle chain from blocks to MoM
215 std::vector<uint256> leaves, tree;
216 for (int i=0; i<np->MoMdepth; i++) {
217 uint256 mRoot = chainActive[np->notarized_height - i]->hashMerkleRoot;
218 leaves.push_back(mRoot);
221 BuildMerkleTree(&fMutated, leaves, tree);
222 branch = GetMerkleBranch(nIndex, leaves.size(), tree);
225 uint256 komodoGets = komodo_calcMoM(np->notarized_height, np->MoMdepth);
226 uint256 ourResult = SafeCheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex);
227 printf("Komodo gets:%s, we get:%s\n", komodoGets.GetHex().data(), ourResult.GetHex().data());
228 if (np->MoM != ourResult)
229 throw std::runtime_error("Failed merkle block->MoM");
232 // Now get the tx merkle branch
236 if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0)
237 throw std::runtime_error("Block not available (pruned data)");
239 if(!ReadBlockFromDisk(block, blockIndex,1))
240 throw std::runtime_error("Can't read block from disk");
242 // Locate the transaction in the block
244 for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++)
245 if (block.vtx[nTxIndex].GetHash() == hash)
248 if (nTxIndex == (int)block.vtx.size())
249 throw std::runtime_error("Error locating tx in block");
251 std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex);
254 if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex))
255 throw std::runtime_error("Failed merkle tx->block");
257 // concatenate branches
258 nIndex = (nIndex << txBranch.size()) + nTxIndex;
259 branch.insert(branch.begin(), txBranch.begin(), txBranch.end());
263 if (np->MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex))
264 throw std::runtime_error("Failed validating MoM");
267 CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION);
268 return std::make_pair(np->notarized_desttxid, MerkleBranch(nIndex, branch));