netwatch.h raw

   1  // Copyright (c) 2017-2021 The Limenka developers
   2  // Copyright (c) 2011-2013 David Krauss (std::align substitute from c-plus)
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #ifndef LIMENKA_QT_NETWATCH_H
   7  #define LIMENKA_QT_NETWATCH_H
   8  
   9  #include <qt/limenkaunits.h>
  10  
  11  #include <primitives/transaction.h>
  12  #include <sync.h>
  13  #include <validationinterface.h>
  14  
  15  #include <QAbstractTableModel>
  16  #include <QWidget>
  17  
  18  QT_BEGIN_NAMESPACE
  19  class QLineEdit;
  20  class QTableView;
  21  QT_END_NAMESPACE
  22  
  23  class CBlock;
  24  class CBlockIndex;
  25  class ClientModel;
  26  class LogEntry;
  27  class NetworkStyle;
  28  class PlatformStyle;
  29  
  30  static constexpr int LONGEST_BASE58_ADDRESS{35};
  31  static constexpr int LONGEST_BECH32_ADDRESS{62};  // NOTE: Up to 74 in theory, but 62 in practice
  32  
  33  class LogEntry {
  34  private:
  35      /**
  36       * m_data is a uint32_t (meta_t) with the top two bits used for:
  37       *   1: CBlockIndex*
  38       *   2: CTransactionRef
  39       *   3: weak_ptr<const CTransaction>
  40       * The subsequent 30 bits are the timestamp, assumed to be most recent to the current time.
  41       * Following this, and any padding necessary for alignment, the object itself is stored
  42       */
  43      uint8_t *m_data{nullptr};
  44  
  45      typedef uint32_t meta_t;
  46      typedef std::weak_ptr<const CTransaction> CTransactionWeakref;
  47      static constexpr uint32_t rel_ts_mask{0x3fffffff};
  48      static constexpr uint64_t rel_ts_mask64{rel_ts_mask};
  49  
  50      template<typename T> static size_t data_sizeof(size_t& offset) {
  51          void *p = (void *)intptr_t(sizeof(meta_t));
  52          size_t dummy_bufsize = sizeof(T) * 2;
  53          p = align(std::alignment_of<T>::value, sizeof(T), p, dummy_bufsize);
  54          assert(p);
  55          offset = size_t(p);
  56          return offset + sizeof(T);
  57      }
  58  
  59      // std::align (missing in at least GCC 4.9) substitute from c-plus
  60      static inline void *align(std::size_t alignment, std::size_t size, void *&ptr, std::size_t &space) {
  61          auto pn = reinterpret_cast<std::uintptr_t>(ptr);
  62          auto aligned = (pn + alignment - 1) & -alignment;
  63          auto new_space = space - (aligned - pn);
  64          if (new_space < size) {
  65              return nullptr;
  66          }
  67          space = new_space;
  68          return ptr = reinterpret_cast<void *>(aligned);
  69      }
  70  
  71      void init(const LogEntry&);
  72      void init(int32_t relTimestamp, const CBlockIndex&);
  73      void init(int32_t relTimestamp, const CTransactionWeakref&, bool weak);
  74      void clear();
  75  
  76  public:
  77      enum class Type {
  78          Block,
  79          Transaction,
  80      };
  81      static QString LogEntryTypeAbbreviation(Type);
  82  
  83      LogEntry(const LogEntry&);
  84      LogEntry() = default;
  85      explicit LogEntry(int32_t relTimestamp, const CBlockIndex&);
  86      explicit LogEntry(int32_t relTimestamp, const CTransactionWeakref&, bool weak = true);
  87      explicit LogEntry(int32_t relTimestamp, const CTransactionRef&, bool weak = false);
  88      ~LogEntry();
  89  
  90      LogEntry& operator=(const LogEntry& other);
  91  
  92      explicit operator bool() const;
  93      int32_t getRelTimestamp() const;
  94      uint64_t getTimestamp(uint64_t now) const;
  95      Type getType() const;
  96  
  97      template <typename T> T* get() const {
  98          void *p = m_data + sizeof(meta_t);
  99          size_t dummy_bufsize = sizeof(T) * 2;
 100          p = align(std::alignment_of<T>::value, sizeof(T), p, dummy_bufsize);
 101          assert(p);
 102          return (T*)p;
 103      }
 104  
 105      const CBlockIndex& getBlockIndex() const;
 106      CTransactionRef getTransactionRef() const;
 107      bool isWeak() const;
 108      bool expired() const;
 109      void makeWeak();
 110  };
 111  
 112  class NetWatchLogModel;
 113  
 114  class NetWatchLogSearch {
 115  public:
 116      QString m_query;
 117  
 118      bool m_check_type;
 119      bool m_check_id;
 120      bool m_check_addr;
 121      bool m_check_value;
 122  
 123      NetWatchLogSearch(const QString& query, LimenkaUnit display_unit);
 124      bool match(const NetWatchLogModel& model, int row) const;
 125  };
 126  
 127  class NetWatchValidationInterface;
 128  
 129  class NetWatchLogModel : public QAbstractTableModel
 130  {
 131      Q_OBJECT
 132  
 133  private:
 134      QWidget * const m_widget;
 135      ClientModel *m_client_model{nullptr};
 136  
 137      NetWatchValidationInterface *m_validation_interface{nullptr};
 138  
 139      mutable RecursiveMutex cs;
 140      std::vector<LogEntry> m_log GUARDED_BY(cs);
 141      static constexpr size_t logsizelimit{0x400};
 142      size_t m_logpos GUARDED_BY(cs) {0};
 143      size_t m_logskip GUARDED_BY(cs) {0};
 144  
 145      static constexpr size_t max_nonweak_txouts{0x200};
 146      static constexpr size_t max_vout_per_tx{0x100};
 147  
 148      NetWatchLogSearch *m_current_search GUARDED_BY(cs) {nullptr};
 149  
 150      const LogEntry& getLogEntryRow(int row) const EXCLUSIVE_LOCKS_REQUIRED(cs);
 151      LogEntry& getLogEntryRow(int row) EXCLUSIVE_LOCKS_REQUIRED(cs);
 152      void log_append(const LogEntry&, size_t& rows_used) EXCLUSIVE_LOCKS_REQUIRED(cs);
 153  
 154  public:
 155      static constexpr int HeaderCount{5};
 156      enum class Header {
 157          Time,
 158          Type,
 159          Id,
 160          Address,
 161          Value,
 162      };
 163  
 164      explicit NetWatchLogModel(QWidget *parent);
 165      ~NetWatchLogModel();
 166  
 167      void setClientModel(ClientModel *model);
 168      void OrphanedValidationInterface();
 169  
 170      bool isLogRowContinuation(int row) const EXCLUSIVE_LOCKS_REQUIRED(cs);
 171      const LogEntry& findLogEntry(int row, int& out_entry_row) const EXCLUSIVE_LOCKS_REQUIRED(cs);
 172  
 173      int rowCount(const QModelIndex& parent = QModelIndex()) const override;
 174      int columnCount(const QModelIndex& parent) const override;
 175      QVariant data(const CBlockIndex&, int txout_index, const Header) const;
 176      QVariant data(const CTransactionRef&, int txout_index, const Header) const;
 177      QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override;
 178      QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const override;
 179  
 180      void searchRows(const QString& query, QList<int>& results);
 181      void searchDisable();
 182  
 183      void LogAddEntry(const LogEntry& le, size_t vout_count);
 184      void LogBlock(const CBlockIndex*, const std::shared_ptr<const CBlock>&);
 185      void LogTransaction(const CTransactionRef&);
 186  
 187  Q_SIGNALS:
 188      void moreSearchResults(const QList<int>& rows);
 189  
 190  public Q_SLOTS:
 191      void updateDisplayUnit();
 192  };
 193  
 194  class NetWatchLogTestModel : public NetWatchLogModel
 195  {
 196      Q_OBJECT
 197  
 198  public:
 199      NetWatchLogTestModel() : NetWatchLogModel(nullptr) { }
 200  
 201      int rowCount(const QModelIndex& parent) const override;
 202      QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override;
 203  };
 204  
 205  class GuiNetWatch: public QWidget
 206  {
 207      Q_OBJECT
 208  
 209  private:
 210      bool m_adjust_scroll;
 211  
 212  public:
 213      GuiNetWatch(const PlatformStyle *, const NetworkStyle *, QWidget * parent = nullptr);
 214  
 215      void setClientModel(ClientModel *model);
 216  
 217      NetWatchLogModel *log_model;
 218      bool m_dont_cancel_search{false};
 219  
 220      QLineEdit *m_search_editor;
 221      QTableView *m_log_view;
 222  
 223  public Q_SLOTS:
 224      void rowsRemoved(const QModelIndex& parent, int start, int end);
 225      void aboutToInsert();
 226      void maybeScrollToBottom();
 227      void doSearch(const QString& query);
 228      void moreSearchResults(const QList<int>& rows);
 229      void maybeCancelSearch();
 230  };
 231  
 232  #endif // LIMENKA_QT_NETWATCH_H
 233