]>
Commit | Line | Data |
---|---|---|
b2a98c42 MT |
1 | /******************************************************************** |
2 | * (C) 2019 Michael Toutonghi | |
3 | * | |
4 | * Distributed under the MIT software license, see the accompanying | |
5 | * file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
6 | * | |
7 | * This defines the public blockchains as a service (PBaaS) notarization protocol, VerusLink. | |
8 | * VerusLink is a new distributed consensus protocol that enables multiple public blockchains | |
9 | * to operate as a decentralized ecosystem of chains, which can interact and easily engage in cross | |
10 | * chain transactions. | |
11 | * | |
12 | * In all notarization services, there is notarizing chain and a chain paying notarization rewards. They are not the same. | |
13 | * The notarizing chain earns the right to submit notarizations onto the paying chain, which uses provable Verus chain power | |
14 | * of each chain combined with a confirmation process to validate the correct version of one chain to another and vice versa. | |
15 | * Generally, the paying chain will be Verus, and the notarizing chain will be the PBaaS chain started with a root of Verus | |
16 | * notarization. | |
17 | * | |
18 | * On each chain, notarizations spend the output of the prior transaction that spent the notarization output, which has some spending | |
19 | * rules that create a thread of one attempted notarization per block, each of them properly representing the current chain, whether | |
20 | * the prior transaction represents a valid representation of the other chain or not. In order to move the notarization forward, | |
21 | * it must also be accepted onto the paying chain, then referenced to move confirmed notarization forward again on the current chain. | |
22 | * All notarization threads are started with a chain definition on the paying chain, or at block 1 on the PBaaS chain. | |
23 | * | |
24 | * Every notarization besides the chain definition is initiated on the PBaaS chain as an effort to create a notarization that is accepted | |
25 | * and confirmed on the paying chain by first being accepted by a Verus miner before a more valuable | |
26 | * notarization is completed and available for acceptance, then being confirmed by multiple cross notarizations. | |
27 | * | |
28 | * A notarization submission is earned when a block is won by staking or mining on the PBaaS chain. The miner puts a notarization | |
29 | * of the paying chain into the block mined, spending the notarization thread. In order for the miner to have a transaction output to spend from, | |
30 | * all PBaaS chains have a block 1 output of a small, transferable amount of Verus, which is only used as a notarization thread. | |
31 | * | |
32 | * After "n" blocks, currently 8, from the block won, the earned notarization may be submitted, proving the last notarization and | |
33 | * including an MMR root that is 8 blocks after the asserted winning block, which must also be proven along with at least one staked block. | |
34 | * Once accepted and confirmed, the notarization transaction itself may be used to spend from the pool of notarization rewards, | |
35 | * with an output that pays 50% to the notary and 50% to the block miner/staker recipient on the paying chain. | |
36 | * | |
37 | * A notarizaton must be either the first in the chain or refer to a prior notarization with which it agrees. If it skips existing | |
38 | * notarizations, referring to a prior notarization as valid, that is the same as asserting that the skipped notarizations are invalid. | |
39 | * In that case, the notarization and 2 after it must prove one additional block since the notarization skipped. | |
40 | * | |
41 | * The intent is to make it extremely improbable cryptographically to achieve full confirmation of any notarization unless an alternate | |
42 | * fork actually represents a valid chain with a majority of combined work and stake, even if more than the majority of notarizers are | |
43 | * attempting to notarize an invalid chain. | |
44 | * | |
45 | * to accept an earned notarization as valid on the Verus blockchain, it must prove a transaction on the alternate chain, which is | |
46 | * either the original chain definition transaction, which CAN and MUST be proven ONLY in block 1, or the latest notarization transaction | |
47 | * on the alternate chain that represents an accurate MMR for the accepting chain. | |
48 | * In addition, any accepted notarization must fullfill the following requirements: | |
49 | * 1) Must prove either a PoS block from the alternate chain or a merge mined | |
50 | * block that is owned by the submitter and exactly 8 blocks behind the submitted MMR, which is used for proof. | |
51 | * 2) must prove a chain definition tx and be block 1 or contain a notarization tx, which asserts a previous, valid MMR for this | |
52 | * chain and properly proves objects using that MMR, as well as has the proper notarization thread inputs and outputs. | |
53 | * 3) must spend the notarization thread to the specified chainID in a fee free transaction with notarization thread input and output | |
54 | * | |
55 | * to agree with a previous notarization, we must: | |
56 | * 1) agree that at the indicated block height, the MMR root is the root claimed, and is a correct representation of the best chain. | |
57 | * | |
58 | */ | |
59 | ||
60 | #ifndef NOTARIZATION_H | |
61 | #define NOTARIZATION_H | |
62 | ||
63 | #include "pbaas/pbaas.h" | |
64 | #include "key_io.h" | |
65 | ||
66 | // This is the data for a PBaaS notarization transaction, either of a PBaaS chain into the Verus chain, or the Verus | |
67 | // chain into a PBaaS chain. | |
68 | ||
69 | // Part of a transaction with an opret that contains only the hashes and proofs, without the source | |
70 | // headers, transactions, and objects. This type of notarizatoin is mined into a block by the miner, and is created on the PBaaS | |
71 | // chain. | |
72 | class CPBaaSNotarization | |
73 | { | |
74 | public: | |
75 | static const int FINAL_CONFIRMATIONS = 10; | |
76 | static const int CURRENT_VERSION = PBAAS_VERSION; | |
77 | uint32_t nVersion; // PBAAS version | |
78 | uint160 chainID; // chain being notarized | |
79 | CAmount rewardPerBlock; // amount to pay per reward, cannot be changed under normal circumstances | |
80 | ||
81 | uint32_t notarizationHeight; // height of the notarization we certify | |
82 | uint256 mmrRoot; // latest MMR root of the notarization height | |
83 | uint256 compactPower; // compact power of the block height notarization to compare | |
84 | ||
85 | uint256 prevNotarization; // txid of the prior notarization on this chain that we agree with, even those not accepted yet | |
86 | int32_t prevHeight; | |
87 | uint256 crossNotarization; // hash of last notarization transaction on the other chain, which is the first tx object in the opret input | |
88 | int32_t crossHeight; | |
89 | ||
90 | COpRetProof opRetProof; // hashes and types of all objects in our opret, enabling reconstruction without the opret on notarized chain | |
91 | ||
9f0c14b2 | 92 | std::vector<CNodeData> nodes; // network nodes |
b2a98c42 MT |
93 | |
94 | CPBaaSNotarization() : nVersion(PBAAS_VERSION_INVALID) { } | |
95 | ||
96 | CPBaaSNotarization(uint32_t version, | |
97 | uint160 chainid, | |
98 | CAmount rewardperblock, | |
99 | int32_t notarizationheight, | |
100 | uint256 MMRRoot, | |
101 | uint256 compactpower, | |
102 | uint256 prevnotarization, | |
103 | int32_t prevheight, | |
104 | uint256 crossnotarization, | |
105 | int32_t crossheight, | |
106 | COpRetProof orp, | |
9f0c14b2 | 107 | std::vector<CNodeData> &Nodes) : |
b2a98c42 MT |
108 | nVersion(version), |
109 | chainID(chainid), | |
110 | rewardPerBlock(rewardperblock), | |
111 | ||
112 | notarizationHeight(notarizationheight), | |
113 | mmrRoot(MMRRoot), | |
114 | compactPower(compactpower), | |
115 | ||
116 | prevNotarization(prevnotarization), | |
117 | prevHeight(prevheight), | |
118 | crossNotarization(crossnotarization), | |
119 | crossHeight(crossheight), | |
120 | ||
121 | opRetProof(orp), | |
122 | ||
9f0c14b2 | 123 | nodes(Nodes) |
b2a98c42 MT |
124 | { } |
125 | ||
126 | CPBaaSNotarization(const std::vector<unsigned char> &asVector) | |
127 | { | |
128 | ::FromVector(asVector, *this); | |
129 | } | |
130 | ||
131 | CPBaaSNotarization(const CTransaction &tx, bool validate = false); | |
132 | ||
133 | ADD_SERIALIZE_METHODS; | |
134 | ||
135 | template <typename Stream, typename Operation> | |
136 | inline void SerializationOp(Stream& s, Operation ser_action) { | |
137 | READWRITE(VARINT(nVersion)); | |
138 | READWRITE(chainID); | |
139 | READWRITE(rewardPerBlock); | |
140 | READWRITE(notarizationHeight); | |
141 | READWRITE(mmrRoot); | |
142 | READWRITE(compactPower); | |
143 | READWRITE(prevNotarization); | |
144 | READWRITE(prevHeight); | |
145 | READWRITE(crossNotarization); | |
146 | READWRITE(crossHeight); | |
147 | READWRITE(opRetProof); | |
9f0c14b2 | 148 | READWRITE(nodes); |
b2a98c42 MT |
149 | } |
150 | ||
151 | std::vector<unsigned char> AsVector() | |
152 | { | |
153 | return ::AsVector(*this); | |
154 | } | |
155 | ||
156 | bool IsValid() | |
157 | { | |
158 | return !mmrRoot.IsNull(); | |
159 | } | |
160 | ||
161 | UniValue ToUniValue() const | |
162 | { | |
163 | UniValue obj(UniValue::VOBJ); | |
164 | obj.push_back(Pair("version", (int64_t)nVersion)); | |
165 | obj.push_back(Pair("chainid", chainID.GetHex())); | |
166 | obj.push_back(Pair("rewardperblock", rewardPerBlock)); | |
167 | obj.push_back(Pair("notarizationheight", (int64_t)notarizationHeight)); | |
168 | obj.push_back(Pair("mmrroot", mmrRoot.GetHex())); | |
169 | obj.push_back(Pair("work", ((UintToArith256(compactPower) << 128) >> 128).ToString())); | |
170 | obj.push_back(Pair("stake", (UintToArith256(compactPower) >> 128).ToString())); | |
171 | obj.push_back(Pair("prevnotarization", prevNotarization.GetHex())); | |
172 | obj.push_back(Pair("prevheight", prevHeight)); | |
173 | obj.push_back(Pair("crossnotarization", crossNotarization.GetHex())); | |
174 | obj.push_back(Pair("crossheight", rewardPerBlock)); | |
9f0c14b2 MT |
175 | UniValue nodesUni(UniValue::VARR); |
176 | for (auto node : nodes) | |
b2a98c42 | 177 | { |
9f0c14b2 | 178 | nodesUni.push_back(node.ToUniValue()); |
b2a98c42 | 179 | } |
9f0c14b2 | 180 | obj.push_back(Pair("nodes", nodesUni)); |
b2a98c42 MT |
181 | return obj; |
182 | } | |
183 | }; | |
184 | ||
185 | class CNotarizationFinalization | |
186 | { | |
187 | public: | |
188 | int32_t confirmedInput; | |
189 | ||
190 | CNotarizationFinalization() : confirmedInput(-1) {} | |
191 | CNotarizationFinalization(int32_t nIn) : confirmedInput(nIn) {} | |
192 | CNotarizationFinalization(std::vector<unsigned char> vch) | |
193 | { | |
194 | ::FromVector(vch, *this); | |
195 | } | |
196 | CNotarizationFinalization(const CTransaction &tx, bool validate=false); | |
197 | ||
198 | ADD_SERIALIZE_METHODS; | |
199 | ||
200 | template <typename Stream, typename Operation> | |
201 | inline void SerializationOp(Stream& s, Operation ser_action) { | |
202 | READWRITE(confirmedInput); | |
203 | } | |
204 | ||
205 | bool IsValid() | |
206 | { | |
207 | return confirmedInput != -1; | |
208 | } | |
209 | ||
210 | std::vector<unsigned char> AsVector() | |
211 | { | |
212 | return ::AsVector(*this); | |
213 | } | |
214 | }; | |
215 | ||
216 | class CChainNotarizationData | |
217 | { | |
218 | public: | |
219 | static const int CURRENT_VERSION = PBAAS_VERSION; | |
220 | uint32_t version; | |
221 | int32_t startBlock; | |
222 | int32_t endBlock; | |
223 | ||
224 | std::vector<std::pair<uint256, CPBaaSNotarization>> vtx; | |
225 | int32_t lastConfirmed; // last confirmed notarization | |
226 | std::vector<std::vector<int32_t>> forks; // chains that represent alternate branches from the last confirmed notarization | |
227 | int32_t bestChain; // index in forks of the chain, beginning with the last confirmed notarization, that has the most power | |
228 | ||
229 | CChainNotarizationData() : version(0), startBlock(0), endBlock(0), lastConfirmed(-1) {} | |
230 | ||
231 | CChainNotarizationData(uint32_t ver, int32_t start, int32_t end, | |
232 | std::vector<std::pair<uint256, CPBaaSNotarization>> txes, | |
233 | int32_t lastConf, | |
234 | std::vector<std::vector<int32_t>> &Forks, | |
235 | int32_t Best) : | |
236 | version(ver), startBlock(start), endBlock(end), | |
237 | vtx(txes), lastConfirmed(lastConf), bestChain(Best), forks(Forks) {} | |
238 | ||
239 | CChainNotarizationData(std::vector<unsigned char> vch) | |
240 | { | |
241 | ::FromVector(vch, *this); | |
242 | } | |
243 | ||
244 | ADD_SERIALIZE_METHODS; | |
245 | ||
246 | template <typename Stream, typename Operation> | |
247 | inline void SerializationOp(Stream& s, Operation ser_action) { | |
248 | READWRITE(version); | |
249 | READWRITE(startBlock); | |
250 | READWRITE(endBlock); | |
251 | READWRITE(vtx); | |
252 | READWRITE(bestChain); | |
253 | READWRITE(forks); | |
254 | } | |
255 | ||
256 | std::vector<unsigned char> AsVector() | |
257 | { | |
258 | return ::AsVector(*this); | |
259 | } | |
260 | ||
261 | bool IsValid() | |
262 | { | |
263 | // this needs an actual check | |
264 | return version != 0; | |
265 | } | |
266 | ||
267 | bool IsConfirmed() | |
268 | { | |
269 | return lastConfirmed != -1; | |
270 | } | |
271 | ||
272 | UniValue ToUniValue() const | |
273 | { | |
274 | UniValue obj(UniValue::VOBJ); | |
275 | obj.push_back(Pair("version", (int64_t)version)); | |
276 | obj.push_back(Pair("startblock", (int64_t)startBlock)); | |
277 | obj.push_back(Pair("endblock", (int64_t)endBlock)); | |
278 | UniValue notarizations(UniValue::VARR); | |
279 | for (int64_t i = 0; i < vtx.size(); i++) | |
280 | { | |
281 | UniValue notarization(UniValue::VOBJ); | |
282 | obj.push_back(Pair("index", i)); | |
283 | notarization.push_back(Pair("txid", vtx[i].first.GetHex())); | |
284 | notarization.push_back(Pair("notarization", vtx[i].second.ToUniValue())); | |
285 | notarizations.push_back(notarization); | |
286 | } | |
287 | obj.push_back(notarizations); | |
288 | obj.push_back(Pair("lastconfirmed", (int64_t)version)); | |
289 | UniValue Forks(UniValue::VARR); | |
290 | for (int64_t i = 0; i < forks.size(); i++) | |
291 | { | |
292 | UniValue Fork(UniValue::VARR); | |
293 | for (int64_t j = 0; j < forks[i].size(); j++) | |
294 | { | |
295 | Fork.push_back((int64_t)forks[i][j]); | |
296 | } | |
297 | Forks.push_back(Pair("fork", Fork)); | |
298 | } | |
299 | obj.push_back(Pair("forks", Forks)); | |
300 | return obj; | |
301 | } | |
302 | }; | |
303 | ||
2299bd95 MT |
304 | bool CreateEarnedNotarization(CMutableTransaction &mnewTx, CTransaction &lastTx, CTransaction &crossTx, int32_t height, uint256 &prevMMR); |
305 | ||
b2a98c42 | 306 | #endif |