bitcoinkernel_wrapper.h raw

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