|
6 | 6 |
|
7 | 7 | #include <boost/variant.hpp> |
8 | 8 | #include <boost/functional/hash/hash.hpp> |
| 9 | +#include <iostream> |
9 | 10 | #include <vector> |
10 | 11 | #include <cstring> // memcmp |
11 | 12 | #include <sstream> |
|
27 | 28 |
|
28 | 29 | namespace cryptonote |
29 | 30 | { |
| 31 | + struct block; |
| 32 | + class transaction; |
| 33 | + struct tx_extra_merge_mining_tag; |
| 34 | + |
| 35 | + // Implemented in cryptonote_format_utils.cpp |
| 36 | + bool get_transaction_hash(const transaction& t, crypto::hash& res); |
| 37 | + bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx, tx_extra_merge_mining_tag& mm_tag); |
30 | 38 |
|
31 | 39 | const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); |
32 | 40 | const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); |
@@ -346,35 +354,148 @@ namespace cryptonote |
346 | 354 | /************************************************************************/ |
347 | 355 | /* */ |
348 | 356 | /************************************************************************/ |
| 357 | + |
| 358 | + const uint8_t CURRENT_BYTECOIN_BLOCK_MAJOR_VERSION = 1; |
| 359 | + |
| 360 | + struct bytecoin_block |
| 361 | + { |
| 362 | + uint8_t major_version; |
| 363 | + uint8_t minor_version; |
| 364 | + crypto::hash prev_id; |
| 365 | + uint32_t nonce; |
| 366 | + size_t number_of_transactions; |
| 367 | + std::vector<crypto::hash> miner_tx_branch; |
| 368 | + transaction miner_tx; |
| 369 | + std::vector<crypto::hash> blockchain_branch; |
| 370 | + }; |
| 371 | + |
| 372 | + struct serializable_bytecoin_block |
| 373 | + { |
| 374 | + bytecoin_block& b; |
| 375 | + uint64_t& timestamp; |
| 376 | + bool hashing_serialization; |
| 377 | + bool header_only; |
| 378 | + |
| 379 | + serializable_bytecoin_block(bytecoin_block& b_, uint64_t& timestamp_, bool hashing_serialization_, bool header_only_) : |
| 380 | + b(b_), timestamp(timestamp_), hashing_serialization(hashing_serialization_), header_only(header_only_) |
| 381 | + { |
| 382 | + } |
| 383 | + |
| 384 | + BEGIN_SERIALIZE_OBJECT() |
| 385 | + VARINT_FIELD_N("major_version", b.major_version); |
| 386 | + if(b.major_version > CURRENT_BYTECOIN_BLOCK_MAJOR_VERSION) return false; |
| 387 | + VARINT_FIELD_N("minor_version", b.minor_version); |
| 388 | + VARINT_FIELD(timestamp); |
| 389 | + FIELD_N("prev_id", b.prev_id); |
| 390 | + FIELD_N("nonce", b.nonce); |
| 391 | + |
| 392 | + if (hashing_serialization) |
| 393 | + { |
| 394 | + crypto::hash miner_tx_hash; |
| 395 | + if (!get_transaction_hash(b.miner_tx, miner_tx_hash)) |
| 396 | + return false; |
| 397 | + |
| 398 | + crypto::hash merkle_root; |
| 399 | + crypto::tree_hash_from_branch(b.miner_tx_branch.data(), b.miner_tx_branch.size(), miner_tx_hash, 0, merkle_root); |
| 400 | + |
| 401 | + FIELD(merkle_root); |
| 402 | + } |
| 403 | + |
| 404 | + VARINT_FIELD_N("number_of_transactions", b.number_of_transactions); |
| 405 | + if (b.number_of_transactions < 1) |
| 406 | + return false; |
| 407 | + |
| 408 | + if (!header_only) |
| 409 | + { |
| 410 | + ar.tag("miner_tx_branch"); |
| 411 | + ar.begin_array(); |
| 412 | + size_t branch_size = crypto::tree_depth(b.number_of_transactions); |
| 413 | + PREPARE_CUSTOM_VECTOR_SERIALIZATION(branch_size, const_cast<bytecoin_block&>(b).miner_tx_branch); |
| 414 | + if (b.miner_tx_branch.size() != branch_size) |
| 415 | + return false; |
| 416 | + for (size_t i = 0; i < branch_size; ++i) |
| 417 | + { |
| 418 | + FIELDS(b.miner_tx_branch[i]); |
| 419 | + if (i + 1 < branch_size) |
| 420 | + ar.delimit_array(); |
| 421 | + } |
| 422 | + ar.end_array(); |
| 423 | + |
| 424 | + FIELD(b.miner_tx); |
| 425 | + |
| 426 | + tx_extra_merge_mining_tag mm_tag; |
| 427 | + if (!get_mm_tag_from_extra(b.miner_tx.extra, mm_tag)) |
| 428 | + return false; |
| 429 | + |
| 430 | + ar.tag("blockchain_branch"); |
| 431 | + ar.begin_array(); |
| 432 | + PREPARE_CUSTOM_VECTOR_SERIALIZATION(mm_tag.depth, const_cast<bytecoin_block&>(b).blockchain_branch); |
| 433 | + if (mm_tag.depth != b.blockchain_branch.size()) |
| 434 | + return false; |
| 435 | + for (size_t i = 0; i < mm_tag.depth; ++i) |
| 436 | + { |
| 437 | + FIELDS(b.blockchain_branch[i]); |
| 438 | + if (i + 1 < mm_tag.depth) |
| 439 | + ar.delimit_array(); |
| 440 | + } |
| 441 | + ar.end_array(); |
| 442 | + } |
| 443 | + END_SERIALIZE() |
| 444 | + }; |
| 445 | + |
| 446 | + // Implemented below |
| 447 | + inline serializable_bytecoin_block make_serializable_bytecoin_block(const block& b, bool hashing_serialization, bool header_only); |
| 448 | + |
349 | 449 | struct block_header |
350 | 450 | { |
351 | 451 | uint8_t major_version; |
352 | 452 | uint8_t minor_version; |
353 | 453 | uint64_t timestamp; |
354 | | - crypto::hash prev_id; |
| 454 | + crypto::hash prev_id; |
355 | 455 | uint32_t nonce; |
356 | 456 |
|
357 | 457 | BEGIN_SERIALIZE() |
358 | 458 | VARINT_FIELD(major_version) |
| 459 | + if(major_version > BLOCK_MAJOR_VERSION_2) return false; |
359 | 460 | VARINT_FIELD(minor_version) |
360 | | - VARINT_FIELD(timestamp) |
| 461 | + if (BLOCK_MAJOR_VERSION_1 == major_version) |
| 462 | + { |
| 463 | + VARINT_FIELD(timestamp) |
| 464 | + } |
361 | 465 | FIELD(prev_id) |
362 | | - FIELD(nonce) |
| 466 | + if (BLOCK_MAJOR_VERSION_1 == major_version) |
| 467 | + { |
| 468 | + FIELD(nonce) |
| 469 | + } |
363 | 470 | END_SERIALIZE() |
364 | 471 | }; |
365 | 472 |
|
366 | 473 | struct block: public block_header |
367 | 474 | { |
| 475 | + bytecoin_block parent_block; |
| 476 | + |
368 | 477 | transaction miner_tx; |
369 | 478 | std::vector<crypto::hash> tx_hashes; |
370 | 479 |
|
371 | 480 | BEGIN_SERIALIZE_OBJECT() |
372 | 481 | FIELDS(*static_cast<block_header *>(this)) |
| 482 | + if (BLOCK_MAJOR_VERSION_2 <= major_version) |
| 483 | + { |
| 484 | + auto sbb = make_serializable_bytecoin_block(*this, false, false); |
| 485 | + FIELD_N("parent_block", sbb); |
| 486 | + } |
373 | 487 | FIELD(miner_tx) |
374 | 488 | FIELD(tx_hashes) |
375 | 489 | END_SERIALIZE() |
376 | 490 | }; |
377 | 491 |
|
| 492 | + inline serializable_bytecoin_block make_serializable_bytecoin_block(const block& b, bool hashing_serialization, bool header_only) |
| 493 | + { |
| 494 | + block& block_ref = const_cast<block&>(b); |
| 495 | + return serializable_bytecoin_block(block_ref.parent_block, block_ref.timestamp, hashing_serialization, header_only); |
| 496 | + } |
| 497 | + |
| 498 | + |
378 | 499 | struct bb_block_header |
379 | 500 | { |
380 | 501 | uint8_t major_version; |
|
0 commit comments