]>
Commit | Line | Data |
---|---|---|
12217420 | 1 | // Copyright (c) 2018 Michael Toutonghi |
2 | // Distributed under the MIT software license, see the accompanying | |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
4 | ||
5 | #ifndef BITCOIN_PRIMITIVES_SOLUTIONDATA_H | |
6 | #define BITCOIN_PRIMITIVES_SOLUTIONDATA_H | |
7 | ||
8 | #include "serialize.h" | |
9 | #include "uint256.h" | |
10 | #include "arith_uint256.h" | |
85c51d62 | 11 | #include "hash.h" |
12 | #include "nonce.h" | |
13 | #include "streams.h" | |
12217420 | 14 | |
b2a98c42 | 15 | class CPBaaSBlockHeader; |
bd6639fd | 16 | |
12217420 | 17 | class CActivationHeight |
18 | { | |
19 | public: | |
20 | static const int32_t MAX_HEIGHT = 0x7fffffff; | |
21 | static const int32_t DEFAULT_UPGRADE_HEIGHT = MAX_HEIGHT; | |
bd6639fd | 22 | static const int32_t NUM_VERSIONS = 3; |
90198f71 | 23 | static const int32_t SOLUTION_VERUSV2 = 1; |
bd6639fd | 24 | static const int32_t SOLUTION_VERUSV3 = 2; |
12217420 | 25 | bool active; |
26 | int32_t heights[NUM_VERSIONS]; | |
bd6639fd | 27 | CActivationHeight() : heights{0, DEFAULT_UPGRADE_HEIGHT, DEFAULT_UPGRADE_HEIGHT}, active(true) {} |
12217420 | 28 | |
29 | void SetActivationHeight(int32_t version, int32_t height) | |
30 | { | |
31 | assert(version < NUM_VERSIONS && version > 0); | |
32 | if (height < MAX_HEIGHT) | |
33 | { | |
34 | active = true; | |
35 | } | |
36 | heights[version] = height; | |
37 | } | |
38 | ||
90198f71 | 39 | bool IsActivationHeight(int32_t version, int32_t height) |
40 | { | |
41 | assert(version < NUM_VERSIONS && version > 0); | |
42 | return active && heights[version] == height; | |
43 | } | |
44 | ||
12217420 | 45 | int32_t ActiveVersion(int32_t height) |
46 | { | |
47 | if (!active) | |
48 | return 0; | |
49 | ||
50 | int32_t ver = 0; | |
51 | for (int32_t i = 0; i < NUM_VERSIONS; i++) | |
52 | { | |
53 | if (heights[i] > height) | |
54 | { | |
55 | break; | |
56 | } | |
57 | ver = i; | |
58 | } | |
59 | return ver; | |
60 | } | |
61 | }; | |
62 | ||
85c51d62 | 63 | class CBlockHeader; |
64 | ||
65 | class CPBaaSPreHeader | |
b2a98c42 | 66 | { |
85c51d62 | 67 | public: |
68 | uint256 hashPrevBlock; | |
69 | uint256 hashMerkleRoot; | |
70 | uint256 hashFinalSaplingRoot; | |
71 | uint256 nNonce; | |
72 | uint32_t nBits; | |
73 | ||
74 | CPBaaSPreHeader() : nBits(0) {} | |
75 | CPBaaSPreHeader(const uint256 &prevBlock, const uint256 &merkleRoot, const uint256 &finalSaplingRoot,const uint256 &nonce, uint32_t compactTarget) : | |
76 | hashPrevBlock(prevBlock), hashMerkleRoot(merkleRoot), hashFinalSaplingRoot(finalSaplingRoot), nNonce(nonce), nBits(compactTarget) {} | |
77 | ||
1fa4454d | 78 | CPBaaSPreHeader(const CBlockHeader &bh); |
85c51d62 | 79 | |
80 | ADD_SERIALIZE_METHODS; | |
81 | ||
82 | template <typename Stream, typename Operation> | |
83 | inline void SerializationOp(Stream& s, Operation ser_action) { | |
84 | READWRITE(hashPrevBlock); | |
85 | READWRITE(hashMerkleRoot); | |
86 | READWRITE(hashFinalSaplingRoot); | |
87 | READWRITE(nNonce); | |
88 | READWRITE(nBits); | |
89 | } | |
f8f61a6d | 90 | |
91 | void SetBlockData(CBlockHeader &bh); | |
85c51d62 | 92 | }; |
93 | ||
94 | // this class provides a minimal and compact hash pair and identity for a merge mined PBaaS header | |
95 | class CPBaaSBlockHeader | |
96 | { | |
97 | public: | |
98 | uint160 chainID; // hash of unique PBaaS symbol on Verus chain | |
99 | uint256 hashPreHeader; // hash of block before solution + chain power + block number | |
100 | uint256 hashPrevMMRRoot; // prior block's Merkle Mountain Range | |
101 | ||
102 | // header | |
103 | static const size_t ID_OFFSET = 0; // offset of 32 byte ID in serialized stream | |
104 | static const int32_t CURRENT_VERSION = CPOSNonce::VERUS_V2; | |
105 | static const int32_t CURRENT_VERSION_MASK = 0x0000ffff; // for compatibility | |
106 | ||
107 | CPBaaSBlockHeader() | |
108 | { | |
109 | SetNull(); | |
110 | } | |
111 | ||
112 | CPBaaSBlockHeader(const uint160 &cID, const uint256 &hashPre, const uint256 &hashPrevMMR) : chainID(cID), hashPreHeader(hashPre), hashPrevMMRRoot(hashPrevMMR) { } | |
113 | ||
114 | CPBaaSBlockHeader(const char *pbegin, const char *pend) | |
115 | { | |
116 | CDataStream s = CDataStream(pbegin, pend, SER_NETWORK, PROTOCOL_VERSION); | |
117 | s >> *this; | |
118 | } | |
119 | ||
f8f61a6d | 120 | CPBaaSBlockHeader(const uint160 &cID, const CPBaaSPreHeader &pbph, const uint256 &hashPrevMMR); |
85c51d62 | 121 | |
122 | CPBaaSBlockHeader(const uint160 &cID, | |
123 | const uint256 &hashPrevBlock, | |
124 | const uint256 &hashMerkleRoot, | |
125 | const uint256 &hashFinalSaplingRoot, | |
126 | const uint256 &nNonce, | |
127 | uint32_t nBits, | |
128 | const uint256 &hashPrevMMRRoot) | |
129 | { | |
130 | CPBaaSPreHeader pbph(hashPrevBlock, hashMerkleRoot, hashFinalSaplingRoot, nNonce, nBits); | |
131 | ||
132 | CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION); | |
133 | hw << pbph; | |
134 | ||
135 | hashPreHeader = hw.GetHash(); | |
136 | } | |
137 | ||
138 | ADD_SERIALIZE_METHODS; | |
139 | ||
140 | template <typename Stream, typename Operation> | |
141 | inline void SerializationOp(Stream& s, Operation ser_action) { | |
142 | READWRITE(chainID); | |
143 | READWRITE(hashPreHeader); | |
144 | READWRITE(hashPrevMMRRoot); | |
145 | } | |
146 | ||
147 | bool operator==(const CPBaaSBlockHeader &right) | |
148 | { | |
149 | return (chainID == right.chainID && hashPreHeader == right.hashPreHeader && hashPrevMMRRoot == right.hashPrevMMRRoot); | |
150 | } | |
151 | ||
152 | bool operator!=(const CPBaaSBlockHeader &right) | |
153 | { | |
154 | return (chainID != right.chainID || hashPreHeader != right.hashPreHeader || hashPrevMMRRoot != right.hashPrevMMRRoot); | |
155 | } | |
156 | ||
157 | void SetNull() | |
158 | { | |
159 | chainID.SetNull(); | |
160 | hashPreHeader.SetNull(); | |
161 | hashPrevMMRRoot.SetNull(); | |
162 | } | |
163 | ||
164 | bool IsNull() const | |
165 | { | |
166 | return chainID.IsNull(); | |
167 | } | |
b2a98c42 MT |
168 | }; |
169 | ||
170 | enum SolutionConstants | |
171 | { | |
172 | SOLUTION_POW = 0x1, // if set, this is a PoW solution, otherwise, not | |
85c51d62 | 173 | SOLUTION_PBAAS_HEADER_SIZE = sizeof(CPBaaSBlockHeader) // size of a processed PBAAS header |
b2a98c42 MT |
174 | }; |
175 | ||
176 | class CPBaaSSolutionDescriptor | |
177 | { | |
178 | public: | |
179 | uint32_t version; | |
180 | uint8_t descrBits; | |
181 | uint8_t numPBaaSHeaders; // these come right after the base and before the stream | |
25eff798 | 182 | uint16_t extraDataSize; // in PoS or possibly future blocks, this is a stream after PBaaS headers |
b2a98c42 | 183 | |
25eff798 | 184 | CPBaaSSolutionDescriptor() : version(0), descrBits(0), numPBaaSHeaders(0), extraDataSize(0) {} |
b2a98c42 | 185 | CPBaaSSolutionDescriptor(uint32_t ver, uint8_t descr, uint8_t numSubHeaders, uint16_t sSize) : |
25eff798 | 186 | version(ver), descrBits(descr), numPBaaSHeaders(numSubHeaders), extraDataSize(sSize) {} |
b2a98c42 MT |
187 | CPBaaSSolutionDescriptor(const std::vector<unsigned char> &vch) |
188 | { | |
189 | version = vch[0] + (vch[1] << 8) + (vch[2] << 16) + (vch[3] << 24); | |
190 | descrBits = vch[4]; | |
191 | numPBaaSHeaders = vch[5]; | |
25eff798 | 192 | extraDataSize = vch[6] | ((uint16_t)(vch[7]) << 8); |
b2a98c42 MT |
193 | } |
194 | void SetVectorBase(std::vector<unsigned char> &vch) | |
195 | { | |
196 | if (vch.size() >= sizeof(*this)) | |
197 | { | |
198 | vch[0] = version & 0xff; | |
199 | vch[1] = (version >> 8) & 0xff; | |
200 | vch[2] = (version >> 16) & 0xff; | |
201 | vch[3] = (version >> 24) & 0xff; | |
202 | vch[4] = descrBits; | |
203 | vch[5] = numPBaaSHeaders; | |
25eff798 MT |
204 | vch[6] = extraDataSize & 0xff; |
205 | vch[7] = (extraDataSize >> 8) & 0xff; | |
b2a98c42 MT |
206 | } |
207 | } | |
208 | }; | |
209 | ||
12217420 | 210 | class CConstVerusSolutionVector |
211 | { | |
212 | public: | |
12217420 | 213 | static const bool SOLUTION_SIZE_FIXED = true; |
b2a98c42 MT |
214 | static const uint32_t HEADER_BASESIZE = 143; |
215 | static const uint32_t SOLUTION_SIZE = 1344; | |
216 | static const uint32_t OVERHEAD_SIZE = sizeof(CPBaaSSolutionDescriptor); | |
217 | ||
218 | static CActivationHeight activationHeight; | |
12217420 | 219 | |
220 | CConstVerusSolutionVector() {} | |
221 | ||
222 | static uint32_t GetVersionByHeight(uint32_t height) | |
223 | { | |
d5040cb1 | 224 | return activationHeight.ActiveVersion(height); |
12217420 | 225 | } |
226 | ||
bd6639fd | 227 | static uint32_t Version(const std::vector<unsigned char> &vch) |
12217420 | 228 | { |
b2a98c42 | 229 | if (activationHeight.ActiveVersion(0x7fffffff) > 0) |
12217420 | 230 | { |
b2a98c42 | 231 | return CPBaaSSolutionDescriptor(vch).version; |
12217420 | 232 | } |
233 | else | |
234 | { | |
235 | return 0; | |
236 | } | |
237 | } | |
238 | ||
bd6639fd | 239 | static bool SetVersion(std::vector<unsigned char> &vch, uint32_t v) |
12217420 | 240 | { |
b2a98c42 MT |
241 | CPBaaSSolutionDescriptor psd = CPBaaSSolutionDescriptor(vch); |
242 | psd.version = v; | |
243 | if (activationHeight.active && vch.size() >= sizeof(CPBaaSSolutionDescriptor)) | |
12217420 | 244 | { |
b2a98c42 | 245 | psd.SetVectorBase(vch); |
12217420 | 246 | return true; |
247 | } | |
248 | else | |
249 | { | |
12217420 | 250 | return false; |
251 | } | |
252 | } | |
253 | ||
bd6639fd | 254 | static bool SetVersionByHeight(std::vector<unsigned char> &vch, uint32_t height) |
12217420 | 255 | { |
256 | return SetVersion(vch, activationHeight.ActiveVersion(height)); | |
257 | } | |
bd6639fd | 258 | |
b2a98c42 | 259 | static bool SetDescriptor(std::vector<unsigned char> &vch, CPBaaSSolutionDescriptor d) |
bd6639fd | 260 | { |
b2a98c42 MT |
261 | d.SetVectorBase(vch); |
262 | } | |
263 | ||
264 | static CPBaaSSolutionDescriptor GetDescriptor(const std::vector<unsigned char> &vch) | |
265 | { | |
266 | return CPBaaSSolutionDescriptor(vch); | |
bd6639fd MT |
267 | } |
268 | ||
b2a98c42 | 269 | static uint32_t DescriptorBits(const std::vector<unsigned char> &vch) |
bd6639fd | 270 | { |
b2a98c42 MT |
271 | return GetDescriptor(vch).descrBits; |
272 | } | |
273 | ||
274 | static uint32_t GetNumPBaaSHeaders(const std::vector<unsigned char> &vch) | |
275 | { | |
276 | return GetDescriptor(vch).numPBaaSHeaders; | |
277 | } | |
278 | ||
25eff798 MT |
279 | static uint32_t MaxPBaaSHeaders(const std::vector<unsigned char> &vch) |
280 | { | |
281 | auto descr = GetDescriptor(vch); | |
282 | ||
85c51d62 | 283 | return descr.extraDataSize ? descr.numPBaaSHeaders : descr.numPBaaSHeaders + (uint32_t)(ExtraDataLen(vch) / sizeof(CPBaaSBlockHeader)); |
25eff798 MT |
284 | } |
285 | ||
b2a98c42 MT |
286 | static bool SetDescriptorBits(std::vector<unsigned char> &vch, uint8_t dBits) |
287 | { | |
288 | CPBaaSSolutionDescriptor psd = CPBaaSSolutionDescriptor(vch); | |
289 | psd.descrBits = dBits; | |
290 | if (activationHeight.active && vch.size() >= sizeof(CPBaaSSolutionDescriptor)) | |
bd6639fd | 291 | { |
b2a98c42 | 292 | psd.SetVectorBase(vch); |
bd6639fd MT |
293 | return true; |
294 | } | |
295 | else | |
296 | { | |
297 | return false; | |
298 | } | |
299 | } | |
300 | ||
301 | // returns 0 if not PBaaS, 1 if PBaaS PoW, -1 if PBaaS PoS | |
302 | static int32_t IsPBaaS(const std::vector<unsigned char> &vch) | |
303 | { | |
304 | if (Version(vch) == CActivationHeight::SOLUTION_VERUSV3) | |
305 | { | |
b2a98c42 | 306 | return (DescriptorBits(vch) & SOLUTION_POW) ? 1 : -1; |
bd6639fd MT |
307 | } |
308 | return 0; | |
309 | } | |
b2a98c42 MT |
310 | |
311 | static const CPBaaSBlockHeader *GetFirstPBaaSHeader(const std::vector<unsigned char> &vch) | |
312 | { | |
313 | return (CPBaaSBlockHeader *)(&vch[0] + sizeof(CPBaaSSolutionDescriptor)); // any headers present are right after descriptor | |
314 | } | |
315 | ||
316 | static void SetPBaaSHeader(std::vector<unsigned char> &vch, const CPBaaSBlockHeader &pbh, int32_t idx); | |
317 | ||
25eff798 MT |
318 | static uint32_t HeadersOverheadSize(const std::vector<unsigned char> &vch) |
319 | { | |
85c51d62 | 320 | return GetDescriptor(vch).numPBaaSHeaders * sizeof(CPBaaSBlockHeader) + OVERHEAD_SIZE; |
25eff798 MT |
321 | } |
322 | ||
b2a98c42 MT |
323 | // return a vector of bytes that contains the internal data for this solution vector |
324 | static uint32_t ExtraDataLen(const std::vector<unsigned char> &vch) | |
325 | { | |
326 | int len; | |
327 | ||
328 | if (Version(vch) < CActivationHeight::SOLUTION_VERUSV3) | |
329 | { | |
330 | len = 0; | |
331 | } | |
332 | else | |
333 | { | |
334 | // calculate number of bytes, minus the OVERHEAD_SIZE byte version and extra nonce at the end of the solution | |
25eff798 | 335 | len = (vch.size() - ((HEADER_BASESIZE + vch.size()) % 32 + HeadersOverheadSize(vch))); |
b2a98c42 MT |
336 | } |
337 | ||
338 | return len < 0 ? 0 : (uint32_t)len; | |
339 | } | |
340 | ||
341 | // return a vector of bytes that contains the internal data for this solution vector | |
342 | const unsigned char *ExtraDataPtr(const std::vector<unsigned char> &vch) | |
343 | { | |
344 | if (ExtraDataLen(vch)) | |
345 | { | |
346 | return &(vch.data()[OVERHEAD_SIZE]); | |
347 | } | |
348 | else | |
349 | { | |
350 | return NULL; | |
351 | } | |
352 | } | |
12217420 | 353 | }; |
354 | ||
355 | class CVerusSolutionVector | |
356 | { | |
357 | private: | |
12217420 | 358 | std::vector<unsigned char> &vch; |
359 | ||
360 | public: | |
b2a98c42 | 361 | static CConstVerusSolutionVector solutionTools; |
12217420 | 362 | |
363 | CVerusSolutionVector(std::vector<unsigned char> &_vch) : vch(_vch) { } | |
364 | ||
365 | static uint32_t GetVersionByHeight(uint32_t height) | |
366 | { | |
b2a98c42 | 367 | return solutionTools.GetVersionByHeight(height); |
12217420 | 368 | } |
369 | ||
370 | uint32_t Version() | |
371 | { | |
b2a98c42 | 372 | return solutionTools.Version(vch); |
12217420 | 373 | } |
374 | ||
375 | bool SetVersion(uint32_t v) | |
376 | { | |
b2a98c42 | 377 | solutionTools.SetVersion(vch, v); |
12217420 | 378 | } |
379 | ||
380 | bool SetVersionByHeight(uint32_t height) | |
381 | { | |
b2a98c42 MT |
382 | return solutionTools.SetVersionByHeight(vch, height); |
383 | } | |
384 | ||
385 | CPBaaSSolutionDescriptor Descriptor() | |
386 | { | |
387 | return solutionTools.GetDescriptor(vch); | |
12217420 | 388 | } |
bd6639fd | 389 | |
b2a98c42 MT |
390 | void SetDescriptor(CPBaaSSolutionDescriptor d) |
391 | { | |
392 | solutionTools.SetDescriptor(vch, d); | |
393 | } | |
394 | ||
395 | uint32_t DescriptorBits() | |
bd6639fd | 396 | { |
b2a98c42 | 397 | return solutionTools.DescriptorBits(vch); |
bd6639fd MT |
398 | } |
399 | ||
b2a98c42 | 400 | bool SetDescriptorBits(uint32_t d) |
bd6639fd | 401 | { |
b2a98c42 | 402 | return solutionTools.SetDescriptorBits(vch, d); |
bd6639fd MT |
403 | } |
404 | ||
405 | // returns 0 if not PBaaS, 1 if PBaaS PoW, -1 if PBaaS PoS | |
406 | int32_t IsPBaaS() | |
407 | { | |
b2a98c42 | 408 | return solutionTools.IsPBaaS(vch); |
bd6639fd MT |
409 | } |
410 | ||
b2a98c42 MT |
411 | const CPBaaSBlockHeader *GetFirstPBaaSHeader() const |
412 | { | |
413 | return solutionTools.GetFirstPBaaSHeader(vch); | |
414 | } | |
415 | ||
416 | uint32_t GetNumPBaaSHeaders() const | |
417 | { | |
418 | return solutionTools.GetNumPBaaSHeaders(vch); | |
419 | } | |
420 | ||
421 | bool GetPBaaSHeader(CPBaaSBlockHeader &pbh, uint32_t idx) const; | |
422 | ||
423 | void SetPBaaSHeader(const CPBaaSBlockHeader &pbh, uint32_t idx) | |
424 | { | |
425 | solutionTools.SetPBaaSHeader(vch, pbh, idx); | |
426 | } | |
427 | ||
25eff798 MT |
428 | uint32_t HeadersOverheadSize() |
429 | { | |
85c51d62 | 430 | return Descriptor().numPBaaSHeaders * sizeof(CPBaaSBlockHeader) + solutionTools.OVERHEAD_SIZE; |
25eff798 MT |
431 | } |
432 | ||
b2a98c42 | 433 | // return length of the internal data for this solution vector |
bd6639fd MT |
434 | uint32_t ExtraDataLen() |
435 | { | |
436 | int len; | |
437 | ||
438 | if (Version() < CActivationHeight::SOLUTION_VERUSV3) | |
439 | { | |
440 | len = 0; | |
441 | } | |
442 | else | |
443 | { | |
444 | // calculate number of bytes, minus the OVERHEAD_SIZE byte version and extra nonce at the end of the solution | |
25eff798 | 445 | len = (vch.size() - ((solutionTools.HEADER_BASESIZE + vch.size()) % 32 + HeadersOverheadSize())); |
bd6639fd MT |
446 | } |
447 | ||
448 | return len < 0 ? 0 : (uint32_t)len; | |
449 | } | |
450 | ||
ec1c84a0 MT |
451 | uint32_t GetRequiredSolutionSize(uint32_t extraDataLen) |
452 | { | |
453 | // round up to nearest 32 bytes | |
25eff798 MT |
454 | uint32_t overhead = HeadersOverheadSize(); |
455 | ||
456 | // make sure we have 15 bytes extra for hashing properly | |
457 | return extraDataLen + overhead + (47 - ((extraDataLen + overhead + solutionTools.HEADER_BASESIZE) % 32)); | |
ec1c84a0 MT |
458 | } |
459 | ||
460 | void ResizeExtraData(uint32_t newSize) | |
461 | { | |
462 | vch.resize(GetRequiredSolutionSize(newSize)); | |
463 | } | |
464 | ||
b2a98c42 | 465 | // return a pointer to bytes that contain the internal data for this solution vector |
bd6639fd MT |
466 | unsigned char *ExtraDataPtr() |
467 | { | |
468 | if (ExtraDataLen()) | |
469 | { | |
25eff798 | 470 | return &(vch.data()[HeadersOverheadSize()]); |
bd6639fd MT |
471 | } |
472 | else | |
473 | { | |
474 | return NULL; | |
475 | } | |
476 | } | |
477 | ||
25eff798 MT |
478 | // return a vector of bytes that contains the extra data for this solution vector, used for |
479 | // stream data typically and stored after PBaaS headers | |
ec1c84a0 | 480 | void GetExtraData(std::vector<unsigned char> &dataVec) |
bd6639fd | 481 | { |
25eff798 | 482 | int len = Descriptor().extraDataSize; |
bd6639fd MT |
483 | |
484 | if (len > 0) | |
485 | { | |
486 | dataVec.resize(len); | |
25eff798 | 487 | std::memcpy(dataVec.data(), ExtraDataPtr(), len); |
bd6639fd MT |
488 | } |
489 | else | |
490 | { | |
491 | dataVec.clear(); | |
492 | } | |
493 | } | |
494 | ||
495 | // set the extra data with a pointer to bytes and length | |
496 | bool SetExtraData(const unsigned char *pbegin, uint32_t len) | |
497 | { | |
25eff798 | 498 | if (Version() < CActivationHeight::SOLUTION_VERUSV3 || len > ExtraDataLen()) |
bd6639fd MT |
499 | { |
500 | return false; | |
501 | } | |
25eff798 MT |
502 | auto descr = Descriptor(); |
503 | descr.extraDataSize = len; | |
504 | SetDescriptor(descr); | |
505 | std::memcpy(&(vch.data()[4]), pbegin, len); | |
506 | return true; | |
bd6639fd | 507 | } |
12217420 | 508 | }; |
509 | ||
510 | #endif // BITCOIN_PRIMITIVES_SOLUTIONDATA_H |