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