bitcoinkernel_wrapper.h
1 // Copyright (c) 2024-present The Bitcoin Core developers 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_KERNEL_BITCOINKERNEL_WRAPPER_H 6 #define BITCOIN_KERNEL_BITCOINKERNEL_WRAPPER_H 7 8 #include <kernel/bitcoinkernel.h> 9 10 #include <array> 11 #include <exception> 12 #include <functional> 13 #include <memory> 14 #include <optional> 15 #include <span> 16 #include <stdexcept> 17 #include <string> 18 #include <string_view> 19 #include <type_traits> 20 #include <utility> 21 #include <vector> 22 23 namespace btck { 24 25 enum class LogCategory : btck_LogCategory { 26 ALL = btck_LogCategory_ALL, 27 BENCH = btck_LogCategory_BENCH, 28 BLOCKSTORAGE = btck_LogCategory_BLOCKSTORAGE, 29 COINDB = btck_LogCategory_COINDB, 30 LEVELDB = btck_LogCategory_LEVELDB, 31 MEMPOOL = btck_LogCategory_MEMPOOL, 32 PRUNE = btck_LogCategory_PRUNE, 33 RAND = btck_LogCategory_RAND, 34 REINDEX = btck_LogCategory_REINDEX, 35 VALIDATION = btck_LogCategory_VALIDATION, 36 KERNEL = btck_LogCategory_KERNEL 37 }; 38 39 enum class LogLevel : btck_LogLevel { 40 TRACE_LEVEL = btck_LogLevel_TRACE, 41 DEBUG_LEVEL = btck_LogLevel_DEBUG, 42 INFO_LEVEL = btck_LogLevel_INFO 43 }; 44 45 enum class ChainType : btck_ChainType { 46 MAINNET = btck_ChainType_MAINNET, 47 TESTNET = btck_ChainType_TESTNET, 48 TESTNET_4 = btck_ChainType_TESTNET_4, 49 SIGNET = btck_ChainType_SIGNET, 50 REGTEST = btck_ChainType_REGTEST 51 }; 52 53 enum class SynchronizationState : btck_SynchronizationState { 54 INIT_REINDEX = btck_SynchronizationState_INIT_REINDEX, 55 INIT_DOWNLOAD = btck_SynchronizationState_INIT_DOWNLOAD, 56 POST_INIT = btck_SynchronizationState_POST_INIT 57 }; 58 59 enum class Warning : btck_Warning { 60 UNKNOWN_NEW_RULES_ACTIVATED = btck_Warning_UNKNOWN_NEW_RULES_ACTIVATED, 61 LARGE_WORK_INVALID_CHAIN = btck_Warning_LARGE_WORK_INVALID_CHAIN 62 }; 63 64 enum class ValidationMode : btck_ValidationMode { 65 VALID = btck_ValidationMode_VALID, 66 INVALID = btck_ValidationMode_INVALID, 67 INTERNAL_ERROR = btck_ValidationMode_INTERNAL_ERROR 68 }; 69 70 enum class BlockValidationResult : btck_BlockValidationResult { 71 UNSET = btck_BlockValidationResult_UNSET, 72 CONSENSUS = btck_BlockValidationResult_CONSENSUS, 73 CACHED_INVALID = btck_BlockValidationResult_CACHED_INVALID, 74 INVALID_HEADER = btck_BlockValidationResult_INVALID_HEADER, 75 MUTATED = btck_BlockValidationResult_MUTATED, 76 MISSING_PREV = btck_BlockValidationResult_MISSING_PREV, 77 INVALID_PREV = btck_BlockValidationResult_INVALID_PREV, 78 TIME_FUTURE = btck_BlockValidationResult_TIME_FUTURE, 79 HEADER_LOW_WORK = btck_BlockValidationResult_HEADER_LOW_WORK 80 }; 81 82 enum class ScriptVerifyStatus : btck_ScriptVerifyStatus { 83 OK = btck_ScriptVerifyStatus_OK, 84 ERROR_INVALID_FLAGS_COMBINATION = btck_ScriptVerifyStatus_ERROR_INVALID_FLAGS_COMBINATION, 85 ERROR_SPENT_OUTPUTS_REQUIRED = btck_ScriptVerifyStatus_ERROR_SPENT_OUTPUTS_REQUIRED, 86 }; 87 88 enum class ScriptVerificationFlags : btck_ScriptVerificationFlags { 89 NONE = btck_ScriptVerificationFlags_NONE, 90 P2SH = btck_ScriptVerificationFlags_P2SH, 91 DERSIG = btck_ScriptVerificationFlags_DERSIG, 92 NULLDUMMY = btck_ScriptVerificationFlags_NULLDUMMY, 93 CHECKLOCKTIMEVERIFY = btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY, 94 CHECKSEQUENCEVERIFY = btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY, 95 WITNESS = btck_ScriptVerificationFlags_WITNESS, 96 TAPROOT = btck_ScriptVerificationFlags_TAPROOT, 97 ALL = btck_ScriptVerificationFlags_ALL 98 }; 99 100 enum class BlockCheckFlags : btck_BlockCheckFlags { 101 BASE = btck_BlockCheckFlags_BASE, 102 POW = btck_BlockCheckFlags_POW, 103 MERKLE = btck_BlockCheckFlags_MERKLE, 104 ALL = btck_BlockCheckFlags_ALL 105 }; 106 107 template <typename T> 108 struct is_bitmask_enum : std::false_type { 109 }; 110 111 template <> 112 struct is_bitmask_enum<ScriptVerificationFlags> : std::true_type { 113 }; 114 115 template <> 116 struct is_bitmask_enum<BlockCheckFlags> : std::true_type { 117 }; 118 119 template <typename T> 120 concept BitmaskEnum = is_bitmask_enum<T>::value; 121 122 template <BitmaskEnum T> 123 constexpr T operator|(T lhs, T rhs) 124 { 125 return static_cast<T>( 126 static_cast<std::underlying_type_t<T>>(lhs) | static_cast<std::underlying_type_t<T>>(rhs)); 127 } 128 129 template <BitmaskEnum T> 130 constexpr T operator&(T lhs, T rhs) 131 { 132 return static_cast<T>( 133 static_cast<std::underlying_type_t<T>>(lhs) & static_cast<std::underlying_type_t<T>>(rhs)); 134 } 135 136 template <BitmaskEnum T> 137 constexpr T operator^(T lhs, T rhs) 138 { 139 return static_cast<T>( 140 static_cast<std::underlying_type_t<T>>(lhs) ^ static_cast<std::underlying_type_t<T>>(rhs)); 141 } 142 143 template <BitmaskEnum T> 144 constexpr T operator~(T value) 145 { 146 return static_cast<T>(~static_cast<std::underlying_type_t<T>>(value)); 147 } 148 149 template <BitmaskEnum T> 150 constexpr T& operator|=(T& lhs, T rhs) 151 { 152 return lhs = lhs | rhs; 153 } 154 155 template <BitmaskEnum T> 156 constexpr T& operator&=(T& lhs, T rhs) 157 { 158 return lhs = lhs & rhs; 159 } 160 161 template <BitmaskEnum T> 162 constexpr T& operator^=(T& lhs, T rhs) 163 { 164 return lhs = lhs ^ rhs; 165 } 166 167 template <typename T> 168 T check(T ptr) 169 { 170 if (ptr == nullptr) { 171 throw std::runtime_error("failed to instantiate btck object"); 172 } 173 return ptr; 174 } 175 176 template <typename Collection, typename ValueType> 177 class Iterator 178 { 179 public: 180 using iterator_category = std::random_access_iterator_tag; 181 using iterator_concept = std::random_access_iterator_tag; 182 using difference_type = std::ptrdiff_t; 183 using value_type = ValueType; 184 185 private: 186 const Collection* m_collection; 187 size_t m_idx; 188 189 public: 190 Iterator() = default; 191 Iterator(const Collection* ptr) : m_collection{ptr}, m_idx{0} {} 192 Iterator(const Collection* ptr, size_t idx) : m_collection{ptr}, m_idx{idx} {} 193 194 // This is just a view, so return a copy. 195 auto operator*() const { return (*m_collection)[m_idx]; } 196 auto operator->() const { return (*m_collection)[m_idx]; } 197 198 auto& operator++() { m_idx++; return *this; } 199 auto operator++(int) { Iterator tmp = *this; ++(*this); return tmp; } 200 201 auto& operator--() { m_idx--; return *this; } 202 auto operator--(int) { auto temp = *this; --m_idx; return temp; } 203 204 auto& operator+=(difference_type n) { m_idx += n; return *this; } 205 auto& operator-=(difference_type n) { m_idx -= n; return *this; } 206 207 auto operator+(difference_type n) const { return Iterator(m_collection, m_idx + n); } 208 auto operator-(difference_type n) const { return Iterator(m_collection, m_idx - n); } 209 210 auto operator-(const Iterator& other) const { return static_cast<difference_type>(m_idx) - static_cast<difference_type>(other.m_idx); } 211 212 ValueType operator[](difference_type n) const { return (*m_collection)[m_idx + n]; } 213 214 auto operator<=>(const Iterator& other) const { return m_idx <=> other.m_idx; } 215 216 bool operator==(const Iterator& other) const { return m_collection == other.m_collection && m_idx == other.m_idx; } 217 218 private: 219 friend Iterator operator+(difference_type n, const Iterator& it) { return it + n; } 220 }; 221 222 template <typename Container, typename SizeFunc, typename GetFunc> 223 concept IndexedContainer = requires(const Container& c, SizeFunc size_func, GetFunc get_func, std::size_t i) { 224 { std::invoke(size_func, c) } -> std::convertible_to<std::size_t>; 225 { std::invoke(get_func, c, i) }; // Return type is deduced 226 }; 227 228 template <typename Container, auto SizeFunc, auto GetFunc> 229 requires IndexedContainer<Container, decltype(SizeFunc), decltype(GetFunc)> 230 class Range 231 { 232 public: 233 using value_type = std::invoke_result_t<decltype(GetFunc), const Container&, size_t>; 234 using difference_type = std::ptrdiff_t; 235 using iterator = Iterator<Range, value_type>; 236 using const_iterator = iterator; 237 238 private: 239 const Container* m_container; 240 241 public: 242 explicit Range(const Container& container) : m_container(&container) 243 { 244 static_assert(std::ranges::random_access_range<Range>); 245 } 246 247 iterator begin() const { return iterator(this, 0); } 248 iterator end() const { return iterator(this, size()); } 249 250 const_iterator cbegin() const { return begin(); } 251 const_iterator cend() const { return end(); } 252 253 size_t size() const { return std::invoke(SizeFunc, *m_container); } 254 255 bool empty() const { return size() == 0; } 256 257 value_type operator[](size_t index) const { return std::invoke(GetFunc, *m_container, index); } 258 259 value_type at(size_t index) const 260 { 261 if (index >= size()) { 262 throw std::out_of_range("Index out of range"); 263 } 264 return (*this)[index]; 265 } 266 267 value_type front() const { return (*this)[0]; } 268 value_type back() const { return (*this)[size() - 1]; } 269 }; 270 271 #define MAKE_RANGE_METHOD(method_name, ContainerType, SizeFunc, GetFunc, container_expr) \ 272 auto method_name() const & { \ 273 return Range<ContainerType, SizeFunc, GetFunc>{container_expr}; \ 274 } \ 275 auto method_name() const && = delete; 276 277 template <typename T> 278 std::vector<std::byte> write_bytes(const T* object, int (*to_bytes)(const T*, btck_WriteBytes, void*)) 279 { 280 std::vector<std::byte> bytes; 281 struct UserData { 282 std::vector<std::byte>* bytes; 283 std::exception_ptr exception; 284 }; 285 UserData user_data = UserData{.bytes = &bytes, .exception = nullptr}; 286 287 constexpr auto const write = +[](const void* buffer, size_t len, void* user_data) -> int { 288 auto& data = *reinterpret_cast<UserData*>(user_data); 289 auto& bytes = *data.bytes; 290 try { 291 auto const* first = static_cast<const std::byte*>(buffer); 292 auto const* last = first + len; 293 bytes.insert(bytes.end(), first, last); 294 return 0; 295 } catch (...) { 296 data.exception = std::current_exception(); 297 return -1; 298 } 299 }; 300 301 if (to_bytes(object, write, &user_data) != 0) { 302 std::rethrow_exception(user_data.exception); 303 } 304 return bytes; 305 } 306 307 template <typename CType> 308 class View 309 { 310 protected: 311 const CType* m_ptr; 312 313 public: 314 explicit View(const CType* ptr) : m_ptr{check(ptr)} {} 315 316 const CType* get() const { return m_ptr; } 317 }; 318 319 template <typename CType, CType* (*CopyFunc)(const CType*), void (*DestroyFunc)(CType*)> 320 class Handle 321 { 322 protected: 323 CType* m_ptr; 324 325 public: 326 explicit Handle(CType* ptr) : m_ptr{check(ptr)} {} 327 328 // Copy constructors 329 Handle(const Handle& other) 330 : m_ptr{check(CopyFunc(other.m_ptr))} {} 331 Handle& operator=(const Handle& other) 332 { 333 if (this != &other) { 334 Handle temp(other); 335 std::swap(m_ptr, temp.m_ptr); 336 } 337 return *this; 338 } 339 340 // Move constructors 341 Handle(Handle&& other) noexcept : m_ptr(other.m_ptr) { other.m_ptr = nullptr; } 342 Handle& operator=(Handle&& other) noexcept 343 { 344 if (this != &other) { 345 DestroyFunc(m_ptr); 346 m_ptr = std::exchange(other.m_ptr, nullptr); 347 } 348 return *this; 349 } 350 351 template <typename ViewType> 352 requires std::derived_from<ViewType, View<CType>> 353 Handle(const ViewType& view) 354 : Handle{CopyFunc(view.get())} 355 { 356 } 357 358 ~Handle() { DestroyFunc(m_ptr); } 359 360 CType* get() { return m_ptr; } 361 const CType* get() const { return m_ptr; } 362 }; 363 364 template <typename CType, void (*DestroyFunc)(CType*)> 365 class UniqueHandle 366 { 367 protected: 368 struct Deleter { 369 void operator()(CType* ptr) const noexcept 370 { 371 if (ptr) DestroyFunc(ptr); 372 } 373 }; 374 std::unique_ptr<CType, Deleter> m_ptr; 375 376 public: 377 explicit UniqueHandle(CType* ptr) : m_ptr{check(ptr)} {} 378 379 CType* get() { return m_ptr.get(); } 380 const CType* get() const { return m_ptr.get(); } 381 }; 382 383 class PrecomputedTransactionData; 384 class Transaction; 385 class TransactionOutput; 386 class BlockValidationState; 387 388 template <typename Derived> 389 class ScriptPubkeyApi 390 { 391 private: 392 auto impl() const 393 { 394 return static_cast<const Derived*>(this)->get(); 395 } 396 397 friend Derived; 398 ScriptPubkeyApi() = default; 399 400 public: 401 bool Verify(int64_t amount, 402 const Transaction& tx_to, 403 const PrecomputedTransactionData* precomputed_txdata, 404 unsigned int input_index, 405 ScriptVerificationFlags flags, 406 ScriptVerifyStatus& status) const; 407 408 std::vector<std::byte> ToBytes() const 409 { 410 return write_bytes(impl(), btck_script_pubkey_to_bytes); 411 } 412 }; 413 414 class ScriptPubkeyView : public View<btck_ScriptPubkey>, public ScriptPubkeyApi<ScriptPubkeyView> 415 { 416 public: 417 explicit ScriptPubkeyView(const btck_ScriptPubkey* ptr) : View{ptr} {} 418 }; 419 420 class ScriptPubkey : public Handle<btck_ScriptPubkey, btck_script_pubkey_copy, btck_script_pubkey_destroy>, public ScriptPubkeyApi<ScriptPubkey> 421 { 422 public: 423 explicit ScriptPubkey(std::span<const std::byte> raw) 424 : Handle{btck_script_pubkey_create(raw.data(), raw.size())} {} 425 426 ScriptPubkey(const ScriptPubkeyView& view) 427 : Handle(view) {} 428 }; 429 430 template <typename Derived> 431 class TransactionOutputApi 432 { 433 private: 434 auto impl() const 435 { 436 return static_cast<const Derived*>(this)->get(); 437 } 438 439 friend Derived; 440 TransactionOutputApi() = default; 441 442 public: 443 int64_t Amount() const 444 { 445 return btck_transaction_output_get_amount(impl()); 446 } 447 448 ScriptPubkeyView GetScriptPubkey() const 449 { 450 return ScriptPubkeyView{btck_transaction_output_get_script_pubkey(impl())}; 451 } 452 }; 453 454 class TransactionOutputView : public View<btck_TransactionOutput>, public TransactionOutputApi<TransactionOutputView> 455 { 456 public: 457 explicit TransactionOutputView(const btck_TransactionOutput* ptr) : View{ptr} {} 458 }; 459 460 class TransactionOutput : public Handle<btck_TransactionOutput, btck_transaction_output_copy, btck_transaction_output_destroy>, public TransactionOutputApi<TransactionOutput> 461 { 462 public: 463 explicit TransactionOutput(const ScriptPubkey& script_pubkey, int64_t amount) 464 : Handle{btck_transaction_output_create(script_pubkey.get(), amount)} {} 465 466 TransactionOutput(const TransactionOutputView& view) 467 : Handle(view) {} 468 }; 469 470 template <typename Derived> 471 class TxidApi 472 { 473 private: 474 auto impl() const 475 { 476 return static_cast<const Derived*>(this)->get(); 477 } 478 479 friend Derived; 480 TxidApi() = default; 481 482 public: 483 bool operator==(const TxidApi& other) const 484 { 485 return btck_txid_equals(impl(), other.impl()) != 0; 486 } 487 488 bool operator!=(const TxidApi& other) const 489 { 490 return btck_txid_equals(impl(), other.impl()) == 0; 491 } 492 493 std::array<std::byte, 32> ToBytes() const 494 { 495 std::array<std::byte, 32> hash; 496 btck_txid_to_bytes(impl(), reinterpret_cast<unsigned char*>(hash.data())); 497 return hash; 498 } 499 }; 500 501 class TxidView : public View<btck_Txid>, public TxidApi<TxidView> 502 { 503 public: 504 explicit TxidView(const btck_Txid* ptr) : View{ptr} {} 505 }; 506 507 class Txid : public Handle<btck_Txid, btck_txid_copy, btck_txid_destroy>, public TxidApi<Txid> 508 { 509 public: 510 Txid(const TxidView& view) 511 : Handle(view) {} 512 }; 513 514 template <typename Derived> 515 class OutPointApi 516 { 517 private: 518 auto impl() const 519 { 520 return static_cast<const Derived*>(this)->get(); 521 } 522 523 friend Derived; 524 OutPointApi() = default; 525 526 public: 527 uint32_t index() const 528 { 529 return btck_transaction_out_point_get_index(impl()); 530 } 531 532 TxidView Txid() const 533 { 534 return TxidView{btck_transaction_out_point_get_txid(impl())}; 535 } 536 }; 537 538 class OutPointView : public View<btck_TransactionOutPoint>, public OutPointApi<OutPointView> 539 { 540 public: 541 explicit OutPointView(const btck_TransactionOutPoint* ptr) : View{ptr} {} 542 }; 543 544 class OutPoint : public Handle<btck_TransactionOutPoint, btck_transaction_out_point_copy, btck_transaction_out_point_destroy>, public OutPointApi<OutPoint> 545 { 546 public: 547 OutPoint(const OutPointView& view) 548 : Handle(view) {} 549 }; 550 551 template <typename Derived> 552 class TransactionInputApi 553 { 554 private: 555 auto impl() const 556 { 557 return static_cast<const Derived*>(this)->get(); 558 } 559 560 friend Derived; 561 TransactionInputApi() = default; 562 563 public: 564 OutPointView OutPoint() const 565 { 566 return OutPointView{btck_transaction_input_get_out_point(impl())}; 567 } 568 569 uint32_t GetSequence() const 570 { 571 return btck_transaction_input_get_sequence(impl()); 572 } 573 }; 574 575 class TransactionInputView : public View<btck_TransactionInput>, public TransactionInputApi<TransactionInputView> 576 { 577 public: 578 explicit TransactionInputView(const btck_TransactionInput* ptr) : View{ptr} {} 579 }; 580 581 class TransactionInput : public Handle<btck_TransactionInput, btck_transaction_input_copy, btck_transaction_input_destroy>, public TransactionInputApi<TransactionInput> 582 { 583 public: 584 TransactionInput(const TransactionInputView& view) 585 : Handle(view) {} 586 }; 587 588 template <typename Derived> 589 class TransactionApi 590 { 591 private: 592 auto impl() const 593 { 594 return static_cast<const Derived*>(this)->get(); 595 } 596 597 public: 598 size_t CountOutputs() const 599 { 600 return btck_transaction_count_outputs(impl()); 601 } 602 603 size_t CountInputs() const 604 { 605 return btck_transaction_count_inputs(impl()); 606 } 607 608 TransactionOutputView GetOutput(size_t index) const 609 { 610 return TransactionOutputView{btck_transaction_get_output_at(impl(), index)}; 611 } 612 613 TransactionInputView GetInput(size_t index) const 614 { 615 return TransactionInputView{btck_transaction_get_input_at(impl(), index)}; 616 } 617 618 uint32_t GetLocktime() const 619 { 620 return btck_transaction_get_locktime(impl()); 621 } 622 623 TxidView Txid() const 624 { 625 return TxidView{btck_transaction_get_txid(impl())}; 626 } 627 628 MAKE_RANGE_METHOD(Outputs, Derived, &TransactionApi<Derived>::CountOutputs, &TransactionApi<Derived>::GetOutput, *static_cast<const Derived*>(this)) 629 630 MAKE_RANGE_METHOD(Inputs, Derived, &TransactionApi<Derived>::CountInputs, &TransactionApi<Derived>::GetInput, *static_cast<const Derived*>(this)) 631 632 std::vector<std::byte> ToBytes() const 633 { 634 return write_bytes(impl(), btck_transaction_to_bytes); 635 } 636 }; 637 638 class TransactionView : public View<btck_Transaction>, public TransactionApi<TransactionView> 639 { 640 public: 641 explicit TransactionView(const btck_Transaction* ptr) : View{ptr} {} 642 }; 643 644 class Transaction : public Handle<btck_Transaction, btck_transaction_copy, btck_transaction_destroy>, public TransactionApi<Transaction> 645 { 646 public: 647 explicit Transaction(std::span<const std::byte> raw_transaction) 648 : Handle{btck_transaction_create(raw_transaction.data(), raw_transaction.size())} {} 649 650 Transaction(const TransactionView& view) 651 : Handle{view} {} 652 }; 653 654 class PrecomputedTransactionData : public Handle<btck_PrecomputedTransactionData, btck_precomputed_transaction_data_copy, btck_precomputed_transaction_data_destroy> 655 { 656 public: 657 explicit PrecomputedTransactionData(const Transaction& tx_to, std::span<const TransactionOutput> spent_outputs) 658 : Handle{btck_precomputed_transaction_data_create( 659 tx_to.get(), 660 reinterpret_cast<const btck_TransactionOutput**>( 661 const_cast<TransactionOutput*>(spent_outputs.data())), 662 spent_outputs.size())} {} 663 }; 664 665 template <typename Derived> 666 bool ScriptPubkeyApi<Derived>::Verify(int64_t amount, 667 const Transaction& tx_to, 668 const PrecomputedTransactionData* precomputed_txdata, 669 unsigned int input_index, 670 ScriptVerificationFlags flags, 671 ScriptVerifyStatus& status) const 672 { 673 auto result = btck_script_pubkey_verify( 674 impl(), 675 amount, 676 tx_to.get(), 677 precomputed_txdata ? precomputed_txdata->get() : nullptr, 678 input_index, 679 static_cast<btck_ScriptVerificationFlags>(flags), 680 reinterpret_cast<btck_ScriptVerifyStatus*>(&status)); 681 return result == 1; 682 } 683 684 template <typename Derived> 685 class BlockHashApi 686 { 687 private: 688 auto impl() const 689 { 690 return static_cast<const Derived*>(this)->get(); 691 } 692 693 public: 694 bool operator==(const Derived& other) const 695 { 696 return btck_block_hash_equals(impl(), other.get()) != 0; 697 } 698 699 bool operator!=(const Derived& other) const 700 { 701 return btck_block_hash_equals(impl(), other.get()) == 0; 702 } 703 704 std::array<std::byte, 32> ToBytes() const 705 { 706 std::array<std::byte, 32> hash; 707 btck_block_hash_to_bytes(impl(), reinterpret_cast<unsigned char*>(hash.data())); 708 return hash; 709 } 710 }; 711 712 class BlockHashView : public View<btck_BlockHash>, public BlockHashApi<BlockHashView> 713 { 714 public: 715 explicit BlockHashView(const btck_BlockHash* ptr) : View{ptr} {} 716 }; 717 718 class BlockHash : public Handle<btck_BlockHash, btck_block_hash_copy, btck_block_hash_destroy>, public BlockHashApi<BlockHash> 719 { 720 public: 721 explicit BlockHash(const std::array<std::byte, 32>& hash) 722 : Handle{btck_block_hash_create(reinterpret_cast<const unsigned char*>(hash.data()))} {} 723 724 explicit BlockHash(btck_BlockHash* hash) 725 : Handle{hash} {} 726 727 BlockHash(const BlockHashView& view) 728 : Handle{view} {} 729 }; 730 731 template <typename Derived> 732 class BlockHeaderApi 733 { 734 private: 735 auto impl() const 736 { 737 return static_cast<const Derived*>(this)->get(); 738 } 739 740 friend Derived; 741 BlockHeaderApi() = default; 742 743 public: 744 BlockHash Hash() const 745 { 746 return BlockHash{btck_block_header_get_hash(impl())}; 747 } 748 749 BlockHashView PrevHash() const 750 { 751 return BlockHashView{btck_block_header_get_prev_hash(impl())}; 752 } 753 754 uint32_t Timestamp() const 755 { 756 return btck_block_header_get_timestamp(impl()); 757 } 758 759 uint32_t Bits() const 760 { 761 return btck_block_header_get_bits(impl()); 762 } 763 764 int32_t Version() const 765 { 766 return btck_block_header_get_version(impl()); 767 } 768 769 uint32_t Nonce() const 770 { 771 return btck_block_header_get_nonce(impl()); 772 } 773 774 std::array<std::byte, 80> ToBytes() const 775 { 776 std::array<std::byte, 80> header; 777 int res{btck_block_header_to_bytes(impl(), reinterpret_cast<unsigned char*>(header.data()))}; 778 if (res != 0) { 779 throw std::runtime_error("Failed to serialize block header"); 780 } 781 return header; 782 } 783 }; 784 785 class BlockHeaderView : public View<btck_BlockHeader>, public BlockHeaderApi<BlockHeaderView> 786 { 787 public: 788 explicit BlockHeaderView(const btck_BlockHeader* ptr) : View{ptr} {} 789 }; 790 791 class BlockHeader : public Handle<btck_BlockHeader, btck_block_header_copy, btck_block_header_destroy>, public BlockHeaderApi<BlockHeader> 792 { 793 public: 794 explicit BlockHeader(std::span<const std::byte> raw_header) 795 : Handle{btck_block_header_create(reinterpret_cast<const unsigned char*>(raw_header.data()), raw_header.size())} {} 796 797 BlockHeader(const BlockHeaderView& view) 798 : Handle{view} {} 799 800 BlockHeader(btck_BlockHeader* header) 801 : Handle{header} {} 802 }; 803 804 class ConsensusParamsView : public View<btck_ConsensusParams> 805 { 806 public: 807 explicit ConsensusParamsView(const btck_ConsensusParams* ptr) : View{ptr} {} 808 }; 809 810 class Block : public Handle<btck_Block, btck_block_copy, btck_block_destroy> 811 { 812 public: 813 Block(const std::span<const std::byte> raw_block) 814 : Handle{btck_block_create(raw_block.data(), raw_block.size())} 815 { 816 } 817 818 Block(btck_Block* block) : Handle{block} {} 819 820 size_t CountTransactions() const 821 { 822 return btck_block_count_transactions(get()); 823 } 824 825 TransactionView GetTransaction(size_t index) const 826 { 827 return TransactionView{btck_block_get_transaction_at(get(), index)}; 828 } 829 830 bool Check(const ConsensusParamsView& consensus_params, 831 BlockCheckFlags flags, 832 BlockValidationState& state) const; 833 834 MAKE_RANGE_METHOD(Transactions, Block, &Block::CountTransactions, &Block::GetTransaction, *this) 835 836 BlockHash GetHash() const 837 { 838 return BlockHash{btck_block_get_hash(get())}; 839 } 840 841 BlockHeader GetHeader() const 842 { 843 return BlockHeader{btck_block_get_header(get())}; 844 } 845 846 std::vector<std::byte> ToBytes() const 847 { 848 return write_bytes(get(), btck_block_to_bytes); 849 } 850 }; 851 852 inline void logging_disable() 853 { 854 btck_logging_disable(); 855 } 856 857 inline void logging_set_options(const btck_LoggingOptions& logging_options) 858 { 859 btck_logging_set_options(logging_options); 860 } 861 862 inline void logging_set_level_category(LogCategory category, LogLevel level) 863 { 864 btck_logging_set_level_category(static_cast<btck_LogCategory>(category), static_cast<btck_LogLevel>(level)); 865 } 866 867 inline void logging_enable_category(LogCategory category) 868 { 869 btck_logging_enable_category(static_cast<btck_LogCategory>(category)); 870 } 871 872 inline void logging_disable_category(LogCategory category) 873 { 874 btck_logging_disable_category(static_cast<btck_LogCategory>(category)); 875 } 876 877 template <typename T> 878 concept Log = requires(T a, std::string_view message) { 879 { a.LogMessage(message) } -> std::same_as<void>; 880 }; 881 882 template <Log T> 883 class Logger : UniqueHandle<btck_LoggingConnection, btck_logging_connection_destroy> 884 { 885 public: 886 Logger(std::unique_ptr<T> log) 887 : UniqueHandle{btck_logging_connection_create( 888 +[](void* user_data, const char* message, size_t message_len) { static_cast<T*>(user_data)->LogMessage({message, message_len}); }, 889 log.release(), 890 +[](void* user_data) { delete static_cast<T*>(user_data); })} 891 { 892 } 893 }; 894 895 class BlockTreeEntry : public View<btck_BlockTreeEntry> 896 { 897 public: 898 BlockTreeEntry(const btck_BlockTreeEntry* entry) 899 : View{entry} 900 { 901 } 902 903 bool operator==(const BlockTreeEntry& other) const 904 { 905 return btck_block_tree_entry_equals(get(), other.get()) != 0; 906 } 907 908 std::optional<BlockTreeEntry> GetPrevious() const 909 { 910 auto entry{btck_block_tree_entry_get_previous(get())}; 911 if (!entry) return std::nullopt; 912 return entry; 913 } 914 915 int32_t GetHeight() const 916 { 917 return btck_block_tree_entry_get_height(get()); 918 } 919 920 BlockHashView GetHash() const 921 { 922 return BlockHashView{btck_block_tree_entry_get_block_hash(get())}; 923 } 924 925 BlockHeader GetHeader() const 926 { 927 return BlockHeader{btck_block_tree_entry_get_block_header(get())}; 928 } 929 930 BlockTreeEntry GetAncestor(int32_t height) const 931 { 932 return BlockTreeEntry{btck_block_tree_entry_get_ancestor(get(), height)}; 933 } 934 935 }; 936 937 class KernelNotifications 938 { 939 public: 940 virtual ~KernelNotifications() = default; 941 942 virtual void BlockTipHandler(SynchronizationState state, BlockTreeEntry entry, double verification_progress) {} 943 944 virtual void HeaderTipHandler(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {} 945 946 virtual void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) {} 947 948 virtual void WarningSetHandler(Warning warning, std::string_view message) {} 949 950 virtual void WarningUnsetHandler(Warning warning) {} 951 952 virtual void FlushErrorHandler(std::string_view error) {} 953 954 virtual void FatalErrorHandler(std::string_view error) {} 955 }; 956 957 template <typename Derived> 958 class BlockValidationStateApi 959 { 960 private: 961 auto impl() const 962 { 963 return static_cast<const Derived*>(this)->get(); 964 } 965 966 friend Derived; 967 BlockValidationStateApi() = default; 968 969 public: 970 ValidationMode GetValidationMode() const 971 { 972 return static_cast<ValidationMode>(btck_block_validation_state_get_validation_mode(impl())); 973 } 974 975 BlockValidationResult GetBlockValidationResult() const 976 { 977 return static_cast<BlockValidationResult>(btck_block_validation_state_get_block_validation_result(impl())); 978 } 979 }; 980 981 class BlockValidationStateView : public View<btck_BlockValidationState>, public BlockValidationStateApi<BlockValidationStateView> 982 { 983 public: 984 explicit BlockValidationStateView(const btck_BlockValidationState* ptr) : View{ptr} {} 985 }; 986 987 class BlockValidationState : public Handle<btck_BlockValidationState, btck_block_validation_state_copy, btck_block_validation_state_destroy>, public BlockValidationStateApi<BlockValidationState> 988 { 989 public: 990 explicit BlockValidationState() : Handle{btck_block_validation_state_create()} {} 991 992 BlockValidationState(const BlockValidationStateView& view) : Handle{view} {} 993 }; 994 995 inline bool Block::Check(const ConsensusParamsView& consensus_params, 996 BlockCheckFlags flags, 997 BlockValidationState& state) const 998 { 999 return btck_block_check(get(), consensus_params.get(), static_cast<btck_BlockCheckFlags>(flags), state.get()) == 1; 1000 } 1001 1002 class ValidationInterface 1003 { 1004 public: 1005 virtual ~ValidationInterface() = default; 1006 1007 virtual void BlockChecked(Block block, BlockValidationStateView state) {} 1008 1009 virtual void PowValidBlock(BlockTreeEntry entry, Block block) {} 1010 1011 virtual void BlockConnected(Block block, BlockTreeEntry entry) {} 1012 1013 virtual void BlockDisconnected(Block block, BlockTreeEntry entry) {} 1014 }; 1015 1016 class ChainParams : public Handle<btck_ChainParameters, btck_chain_parameters_copy, btck_chain_parameters_destroy> 1017 { 1018 public: 1019 ChainParams(ChainType chain_type) 1020 : Handle{btck_chain_parameters_create(static_cast<btck_ChainType>(chain_type))} {} 1021 1022 ConsensusParamsView GetConsensusParams() const 1023 { 1024 return ConsensusParamsView{btck_chain_parameters_get_consensus_params(get())}; 1025 } 1026 }; 1027 1028 class ContextOptions : public UniqueHandle<btck_ContextOptions, btck_context_options_destroy> 1029 { 1030 public: 1031 ContextOptions() : UniqueHandle{btck_context_options_create()} {} 1032 1033 void SetChainParams(ChainParams& chain_params) 1034 { 1035 btck_context_options_set_chainparams(get(), chain_params.get()); 1036 } 1037 1038 template <typename T> 1039 void SetNotifications(std::shared_ptr<T> notifications) 1040 { 1041 static_assert(std::is_base_of_v<KernelNotifications, T>); 1042 auto heap_notifications = std::make_unique<std::shared_ptr<T>>(std::move(notifications)); 1043 using user_type = std::shared_ptr<T>*; 1044 btck_context_options_set_notifications( 1045 get(), 1046 btck_NotificationInterfaceCallbacks{ 1047 .user_data = heap_notifications.release(), 1048 .user_data_destroy = +[](void* user_data) { delete static_cast<user_type>(user_data); }, 1049 .block_tip = +[](void* user_data, btck_SynchronizationState state, const btck_BlockTreeEntry* entry, double verification_progress) { (*static_cast<user_type>(user_data))->BlockTipHandler(static_cast<SynchronizationState>(state), BlockTreeEntry{entry}, verification_progress); }, 1050 .header_tip = +[](void* user_data, btck_SynchronizationState state, int64_t height, int64_t timestamp, int presync) { (*static_cast<user_type>(user_data))->HeaderTipHandler(static_cast<SynchronizationState>(state), height, timestamp, presync == 1); }, 1051 .progress = +[](void* user_data, const char* title, size_t title_len, int progress_percent, int resume_possible) { (*static_cast<user_type>(user_data))->ProgressHandler({title, title_len}, progress_percent, resume_possible == 1); }, 1052 .warning_set = +[](void* user_data, btck_Warning warning, const char* message, size_t message_len) { (*static_cast<user_type>(user_data))->WarningSetHandler(static_cast<Warning>(warning), {message, message_len}); }, 1053 .warning_unset = +[](void* user_data, btck_Warning warning) { (*static_cast<user_type>(user_data))->WarningUnsetHandler(static_cast<Warning>(warning)); }, 1054 .flush_error = +[](void* user_data, const char* error, size_t error_len) { (*static_cast<user_type>(user_data))->FlushErrorHandler({error, error_len}); }, 1055 .fatal_error = +[](void* user_data, const char* error, size_t error_len) { (*static_cast<user_type>(user_data))->FatalErrorHandler({error, error_len}); }, 1056 }); 1057 } 1058 1059 template <typename T> 1060 void SetValidationInterface(std::shared_ptr<T> validation_interface) 1061 { 1062 static_assert(std::is_base_of_v<ValidationInterface, T>); 1063 auto heap_vi = std::make_unique<std::shared_ptr<T>>(std::move(validation_interface)); 1064 using user_type = std::shared_ptr<T>*; 1065 btck_context_options_set_validation_interface( 1066 get(), 1067 btck_ValidationInterfaceCallbacks{ 1068 .user_data = heap_vi.release(), 1069 .user_data_destroy = +[](void* user_data) { delete static_cast<user_type>(user_data); }, 1070 .block_checked = +[](void* user_data, btck_Block* block, const btck_BlockValidationState* state) { (*static_cast<user_type>(user_data))->BlockChecked(Block{block}, BlockValidationStateView{state}); }, 1071 .pow_valid_block = +[](void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry) { (*static_cast<user_type>(user_data))->PowValidBlock(BlockTreeEntry{entry}, Block{block}); }, 1072 .block_connected = +[](void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry) { (*static_cast<user_type>(user_data))->BlockConnected(Block{block}, BlockTreeEntry{entry}); }, 1073 .block_disconnected = +[](void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry) { (*static_cast<user_type>(user_data))->BlockDisconnected(Block{block}, BlockTreeEntry{entry}); }, 1074 }); 1075 } 1076 }; 1077 1078 class Context : public Handle<btck_Context, btck_context_copy, btck_context_destroy> 1079 { 1080 public: 1081 Context(ContextOptions& opts) 1082 : Handle{btck_context_create(opts.get())} {} 1083 1084 Context() 1085 : Handle{btck_context_create(ContextOptions{}.get())} {} 1086 1087 bool interrupt() 1088 { 1089 return btck_context_interrupt(get()) == 0; 1090 } 1091 }; 1092 1093 class ChainstateManagerOptions : public UniqueHandle<btck_ChainstateManagerOptions, btck_chainstate_manager_options_destroy> 1094 { 1095 public: 1096 ChainstateManagerOptions(const Context& context, std::string_view data_dir, std::string_view blocks_dir) 1097 : UniqueHandle{btck_chainstate_manager_options_create( 1098 context.get(), data_dir.data(), data_dir.length(), blocks_dir.data(), blocks_dir.length())} 1099 { 1100 } 1101 1102 void SetWorkerThreads(int worker_threads) 1103 { 1104 btck_chainstate_manager_options_set_worker_threads_num(get(), worker_threads); 1105 } 1106 1107 bool SetWipeDbs(bool wipe_block_tree, bool wipe_chainstate) 1108 { 1109 return btck_chainstate_manager_options_set_wipe_dbs(get(), wipe_block_tree, wipe_chainstate) == 0; 1110 } 1111 1112 void UpdateBlockTreeDbInMemory(bool block_tree_db_in_memory) 1113 { 1114 btck_chainstate_manager_options_update_block_tree_db_in_memory(get(), block_tree_db_in_memory); 1115 } 1116 1117 void UpdateChainstateDbInMemory(bool chainstate_db_in_memory) 1118 { 1119 btck_chainstate_manager_options_update_chainstate_db_in_memory(get(), chainstate_db_in_memory); 1120 } 1121 }; 1122 1123 class ChainView : public View<btck_Chain> 1124 { 1125 public: 1126 explicit ChainView(const btck_Chain* ptr) : View{ptr} {} 1127 1128 int32_t Height() const 1129 { 1130 return btck_chain_get_height(get()); 1131 } 1132 1133 int32_t CountEntries() const 1134 { 1135 return btck_chain_get_height(get()) + 1; 1136 } 1137 1138 BlockTreeEntry GetByHeight(int32_t height) const 1139 { 1140 auto index{btck_chain_get_by_height(get(), height)}; 1141 if (!index) throw std::runtime_error("No entry in the chain at the provided height"); 1142 return index; 1143 } 1144 1145 bool Contains(BlockTreeEntry& entry) const 1146 { 1147 return btck_chain_contains(get(), entry.get()); 1148 } 1149 1150 MAKE_RANGE_METHOD(Entries, ChainView, &ChainView::CountEntries, &ChainView::GetByHeight, *this) 1151 }; 1152 1153 template <typename Derived> 1154 class CoinApi 1155 { 1156 private: 1157 auto impl() const 1158 { 1159 return static_cast<const Derived*>(this)->get(); 1160 } 1161 1162 friend Derived; 1163 CoinApi() = default; 1164 1165 public: 1166 uint32_t GetConfirmationHeight() const { return btck_coin_confirmation_height(impl()); } 1167 1168 bool IsCoinbase() const { return btck_coin_is_coinbase(impl()) == 1; } 1169 1170 TransactionOutputView GetOutput() const 1171 { 1172 return TransactionOutputView{btck_coin_get_output(impl())}; 1173 } 1174 }; 1175 1176 class CoinView : public View<btck_Coin>, public CoinApi<CoinView> 1177 { 1178 public: 1179 explicit CoinView(const btck_Coin* ptr) : View{ptr} {} 1180 }; 1181 1182 class Coin : public Handle<btck_Coin, btck_coin_copy, btck_coin_destroy>, public CoinApi<Coin> 1183 { 1184 public: 1185 Coin(btck_Coin* coin) : Handle{coin} {} 1186 1187 Coin(const CoinView& view) : Handle{view} {} 1188 }; 1189 1190 template <typename Derived> 1191 class TransactionSpentOutputsApi 1192 { 1193 private: 1194 auto impl() const 1195 { 1196 return static_cast<const Derived*>(this)->get(); 1197 } 1198 1199 friend Derived; 1200 TransactionSpentOutputsApi() = default; 1201 1202 public: 1203 size_t Count() const 1204 { 1205 return btck_transaction_spent_outputs_count(impl()); 1206 } 1207 1208 CoinView GetCoin(size_t index) const 1209 { 1210 return CoinView{btck_transaction_spent_outputs_get_coin_at(impl(), index)}; 1211 } 1212 1213 MAKE_RANGE_METHOD(Coins, Derived, &TransactionSpentOutputsApi<Derived>::Count, &TransactionSpentOutputsApi<Derived>::GetCoin, *static_cast<const Derived*>(this)) 1214 }; 1215 1216 class TransactionSpentOutputsView : public View<btck_TransactionSpentOutputs>, public TransactionSpentOutputsApi<TransactionSpentOutputsView> 1217 { 1218 public: 1219 explicit TransactionSpentOutputsView(const btck_TransactionSpentOutputs* ptr) : View{ptr} {} 1220 }; 1221 1222 class TransactionSpentOutputs : public Handle<btck_TransactionSpentOutputs, btck_transaction_spent_outputs_copy, btck_transaction_spent_outputs_destroy>, 1223 public TransactionSpentOutputsApi<TransactionSpentOutputs> 1224 { 1225 public: 1226 TransactionSpentOutputs(btck_TransactionSpentOutputs* transaction_spent_outputs) : Handle{transaction_spent_outputs} {} 1227 1228 TransactionSpentOutputs(const TransactionSpentOutputsView& view) : Handle{view} {} 1229 }; 1230 1231 class BlockSpentOutputs : public Handle<btck_BlockSpentOutputs, btck_block_spent_outputs_copy, btck_block_spent_outputs_destroy> 1232 { 1233 public: 1234 BlockSpentOutputs(btck_BlockSpentOutputs* block_spent_outputs) 1235 : Handle{block_spent_outputs} 1236 { 1237 } 1238 1239 size_t Count() const 1240 { 1241 return btck_block_spent_outputs_count(get()); 1242 } 1243 1244 TransactionSpentOutputsView GetTxSpentOutputs(size_t tx_undo_index) const 1245 { 1246 return TransactionSpentOutputsView{btck_block_spent_outputs_get_transaction_spent_outputs_at(get(), tx_undo_index)}; 1247 } 1248 1249 MAKE_RANGE_METHOD(TxsSpentOutputs, BlockSpentOutputs, &BlockSpentOutputs::Count, &BlockSpentOutputs::GetTxSpentOutputs, *this) 1250 }; 1251 1252 class ChainMan : UniqueHandle<btck_ChainstateManager, btck_chainstate_manager_destroy> 1253 { 1254 public: 1255 ChainMan(const Context& context, const ChainstateManagerOptions& chainman_opts) 1256 : UniqueHandle{btck_chainstate_manager_create(chainman_opts.get())} 1257 { 1258 } 1259 1260 bool ImportBlocks(const std::span<const std::string> paths) 1261 { 1262 std::vector<const char*> c_paths; 1263 std::vector<size_t> c_paths_lens; 1264 c_paths.reserve(paths.size()); 1265 c_paths_lens.reserve(paths.size()); 1266 for (const auto& path : paths) { 1267 c_paths.push_back(path.c_str()); 1268 c_paths_lens.push_back(path.length()); 1269 } 1270 1271 return btck_chainstate_manager_import_blocks(get(), c_paths.data(), c_paths_lens.data(), c_paths.size()) == 0; 1272 } 1273 1274 bool ProcessBlock(const Block& block, bool* new_block) 1275 { 1276 int _new_block; 1277 int res = btck_chainstate_manager_process_block(get(), block.get(), &_new_block); 1278 if (new_block) *new_block = _new_block == 1; 1279 return res == 0; 1280 } 1281 1282 bool ProcessBlockHeader(const BlockHeader& header, BlockValidationState& state) 1283 { 1284 return btck_chainstate_manager_process_block_header(get(), header.get(), state.get()) == 0; 1285 } 1286 1287 ChainView GetChain() const 1288 { 1289 return ChainView{btck_chainstate_manager_get_active_chain(get())}; 1290 } 1291 1292 std::optional<BlockTreeEntry> GetBlockTreeEntry(const BlockHash& block_hash) const 1293 { 1294 auto entry{btck_chainstate_manager_get_block_tree_entry_by_hash(get(), block_hash.get())}; 1295 if (!entry) return std::nullopt; 1296 return entry; 1297 } 1298 1299 BlockTreeEntry GetBestEntry() const 1300 { 1301 return btck_chainstate_manager_get_best_entry(get()); 1302 } 1303 1304 std::optional<Block> ReadBlock(const BlockTreeEntry& entry) const 1305 { 1306 auto block{btck_block_read(get(), entry.get())}; 1307 if (!block) return std::nullopt; 1308 return block; 1309 } 1310 1311 BlockSpentOutputs ReadBlockSpentOutputs(const BlockTreeEntry& entry) const 1312 { 1313 return btck_block_spent_outputs_read(get(), entry.get()); 1314 } 1315 }; 1316 1317 } // namespace btck 1318 1319 #endif // BITCOIN_KERNEL_BITCOINKERNEL_WRAPPER_H