]> Git Repo - VerusCoin.git/blob - src/crosschain.cpp
rpc methods for cross chain transactions
[VerusCoin.git] / src / crosschain.cpp
1 #include "cc/eval.h"
2 #include "importcoin.h"
3 #include "main.h"
4 #include "notarisationdb.h"
5 #include "komodo_structs.h"
6
7
8 /*
9  * This file is built in the server
10  */
11
12 /* On KMD */
13 uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
14         std::vector<uint256> &moms, uint256 &destNotarisationTxid)
15 {
16     /*
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.
21      *
22      *    kmdHeight      notarisations-0      notarisations-1
23      *        |                |********************|
24      *        > scan backwards >
25      */
26
27     if (targetCCid <= 1)
28         return uint256();
29
30     if (kmdHeight < 0 || kmdHeight > chainActive.Height())
31         return uint256();
32
33     int seenOwnNotarisations = 0;
34
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))
40             continue;
41         BOOST_FOREACH(Notarisation& nota, notarisations) {
42             NotarisationData& data = nota.second;
43             if (data.ccId != targetCCid)
44                 continue;
45             if (strcmp(data.symbol, symbol) == 0)
46             {
47                 seenOwnNotarisations++;
48                 if (seenOwnNotarisations == 2)
49                     goto end;
50                 if (seenOwnNotarisations == 1)
51                     destNotarisationTxid = nota.first;
52             }
53             if (seenOwnNotarisations == 1)
54                 moms.push_back(data.MoM);
55         }
56     }
57
58 end:
59     return GetMerkleRoot(moms);
60 }
61
62
63 /* On KMD */
64 TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
65         const TxProof assetChainProof)
66 {
67     /*
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).
72      */
73     EvalRef eval;
74     uint256 MoM = assetChainProof.second.Exec(txid);
75     
76     // Get a kmd height for given notarisation Txid
77     int kmdHeight;
78     {
79         CTransaction sourceNotarisation;
80         uint256 hashBlock;
81         CBlockIndex blockIdx;
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;
86         else
87             throw std::runtime_error("Notarisation not found");
88     }
89
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);
94     if (MoMoM.IsNull())
95         throw std::runtime_error("No MoMs found");
96     
97     // Find index of source MoM in MoMoM
98     int nIndex;
99     for (nIndex=0; nIndex<moms.size(); nIndex++) {
100         if (moms[nIndex] == MoM)
101             goto cont;
102     }
103     throw std::runtime_error("Couldn't find MoM within MoMoM set");
104 cont:
105
106     // Create a branch
107     std::vector<uint256> vBranch;
108     {
109         CBlock fakeBlock;
110         for (int i=0; i<moms.size(); i++) {
111             CTransaction fakeTx;
112             // first value in CTransaction memory is it's hash
113             memcpy((void*)&fakeTx, moms[i].begin(), 32);
114             fakeBlock.vtx.push_back(fakeTx);
115         }
116         vBranch = fakeBlock.GetMerkleBranch(nIndex);
117     }
118
119     // Concatenate branches
120     MerkleBranch newBranch = assetChainProof.second;
121     newBranch << MerkleBranch(nIndex, vBranch);
122
123     // Check proof
124     if (newBranch.Exec(txid) != MoMoM)
125         throw std::runtime_error("Proof check failed");
126
127     return std::make_pair(targetChainNotarisationTxid,newBranch);
128 }
129
130
131 /*
132  * Takes an importTx that has proof leading to assetchain root
133  * and extends proof to cross chain root
134  */
135 void CompleteImportTransaction(CTransaction &importTx)
136 {
137     TxProof proof;
138     CTransaction burnTx;
139     std::vector<CTxOut> payouts;
140     if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
141         throw std::runtime_error("Couldn't parse importTx");
142
143     std::string targetSymbol;
144     uint32_t targetCCid;
145     uint256 payoutsHash;
146     if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash))
147         throw std::runtime_error("Couldn't parse burnTx");
148
149     proof = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, proof);
150
151     importTx = MakeImportCoinTransaction(proof, burnTx, importTx.vout);
152 }
153
154
155 struct notarized_checkpoint *komodo_npptr_at(int idx);
156 struct notarized_checkpoint *komodo_npptr_for_height(int32_t height, int *idx);
157
158
159 /* On assetchain */
160 bool GetNextBacknotarisation(uint256 kmdNotarisationTxid, std::pair<uint256,NotarisationData> &out)
161 {
162     /*
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.
166      */
167     Notarisation bn;
168     if (!GetBackNotarisation(kmdNotarisationTxid, bn))
169         return false;
170
171     int npIdx;
172     struct notarized_checkpoint* np = komodo_npptr_for_height(bn.second.height, &npIdx);
173     if (!(np = komodo_npptr_at(npIdx+1)))
174         return false;
175
176     return GetBackNotarisation(np->notarized_desttxid, out);
177         throw std::runtime_error("Can't get backnotarisation");
178 }
179
180
181 struct notarized_checkpoint* komodo_npptr(int32_t height);
182
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);
184
185 /*
186  * On assetchain
187  * in: txid
188  * out: pair<notarisationTxHash,merkleBranch>
189  */
190 TxProof GetAssetchainProof(uint256 hash)
191 {
192     int nIndex;
193     CBlockIndex* blockIndex;
194     struct notarized_checkpoint* np;
195     std::vector<uint256> branch;
196
197     {
198         uint256 blockHash;
199         CTransaction tx;
200         if (!GetTransaction(hash, tx, blockHash, true))
201             throw std::runtime_error("cannot find transaction");
202
203         blockIndex = mapBlockIndex[blockHash];
204         if (!(np = komodo_npptr(blockIndex->nHeight)))
205             throw std::runtime_error("notarisation not found");
206         
207         // index of block in MoM leaves
208         nIndex = np->notarized_height - blockIndex->nHeight;
209     }
210
211     // build merkle chain from blocks to MoM
212     {
213         // since the merkle branch code is tied up in a block class
214         // and we want to make a merkle branch for something that isnt transactions
215         CBlock fakeBlock;
216         for (int i=0; i<np->MoMdepth; i++) {
217             uint256 mRoot = chainActive[np->notarized_height - i]->hashMerkleRoot;
218             CTransaction fakeTx;
219             // first value in CTransaction memory is it's hash
220             memcpy((void*)&fakeTx, mRoot.begin(), 32);
221             fakeBlock.vtx.push_back(fakeTx);
222         }
223         branch = fakeBlock.GetMerkleBranch(nIndex);
224
225         // Check branch
226         if (np->MoM != CBlock::CheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex))
227             throw std::runtime_error("Failed merkle block->MoM");
228     }
229
230     // Now get the tx merkle branch
231     {
232         CBlock block;
233
234         if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0)
235             throw std::runtime_error("Block not available (pruned data)");
236
237         if(!ReadBlockFromDisk(block, blockIndex,1))
238             throw std::runtime_error("Can't read block from disk");
239
240         // Locate the transaction in the block
241         int nTxIndex;
242         for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++)
243             if (block.vtx[nTxIndex].GetHash() == hash)
244                 break;
245
246         if (nTxIndex == (int)block.vtx.size())
247             throw std::runtime_error("Error locating tx in block");
248
249         std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex);
250
251         // Check branch
252         if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex))
253             throw std::runtime_error("Failed merkle tx->block");
254
255         // concatenate branches
256         nIndex = (nIndex << txBranch.size()) + nTxIndex;
257         branch.insert(branch.begin(), txBranch.begin(), txBranch.end());
258     }
259
260     // Check the proof
261     if (np->MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex)) 
262         throw std::runtime_error("Failed validating MoM");
263
264     // All done!
265     CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION);
266     return std::make_pair(np->notarized_desttxid, MerkleBranch(nIndex, branch));
267 }
268
269
This page took 0.038846 seconds and 4 git commands to generate.