github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/settlement_history_storage.go (about)

     1  /*
     2   * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package pingpong
    19  
    20  import (
    21  	"errors"
    22  	"math/big"
    23  	"time"
    24  
    25  	"github.com/asdine/storm/v3"
    26  	"github.com/asdine/storm/v3/q"
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/mysteriumnetwork/node/core/storage/boltdb"
    29  	"github.com/mysteriumnetwork/node/identity"
    30  	"github.com/mysteriumnetwork/payments/crypto"
    31  )
    32  
    33  // HistoryType settlement history type
    34  // swagger:model HistoryType
    35  type HistoryType string
    36  
    37  const (
    38  	// SettlementType settlement type
    39  	SettlementType HistoryType = "settlement"
    40  	// WithdrawalType withdrawal type
    41  	WithdrawalType HistoryType = "withdrawal"
    42  )
    43  
    44  // SettlementHistoryStorage stores the settlement events for historical purposes.
    45  type SettlementHistoryStorage struct {
    46  	bolt *boltdb.Bolt
    47  }
    48  
    49  // NewSettlementHistoryStorage returns a new instance of the SettlementHistoryStorage.
    50  func NewSettlementHistoryStorage(bolt *boltdb.Bolt) *SettlementHistoryStorage {
    51  	return &SettlementHistoryStorage{
    52  		bolt: bolt,
    53  	}
    54  }
    55  
    56  // SettlementHistoryEntry represents a settlement history entry
    57  type SettlementHistoryEntry struct {
    58  	TxHash           common.Hash `storm:"id"`
    59  	BlockExplorerURL string
    60  	ProviderID       identity.Identity
    61  	HermesID         common.Address
    62  	ChannelAddress   common.Address
    63  	Time             time.Time
    64  	Promise          crypto.Promise
    65  	Beneficiary      common.Address
    66  	Amount           *big.Int
    67  	TotalSettled     *big.Int
    68  	Fees             *big.Int
    69  	IsWithdrawal     bool
    70  	Error            string
    71  }
    72  
    73  const settlementHistoryBucket = "settlement-history"
    74  
    75  // Store stores a given settlement history entry.
    76  func (shs *SettlementHistoryStorage) Store(she SettlementHistoryEntry) error {
    77  	shs.bolt.Lock()
    78  	defer shs.bolt.Unlock()
    79  	return shs.bolt.DB().From(settlementHistoryBucket).Save(&she)
    80  }
    81  
    82  // SettlementHistoryFilter defines all flags for filtering in settlement history storage.
    83  type SettlementHistoryFilter struct {
    84  	TimeFrom   *time.Time
    85  	TimeTo     *time.Time
    86  	ProviderID *identity.Identity
    87  	HermesID   *common.Address
    88  	Types      []HistoryType
    89  }
    90  
    91  // List retrieves stored entries.
    92  func (shs *SettlementHistoryStorage) List(filter SettlementHistoryFilter) (result []SettlementHistoryEntry, err error) {
    93  	where := make([]q.Matcher, 0)
    94  	if filter.TimeFrom != nil {
    95  		where = append(where, q.Gte("Time", filter.TimeFrom.UTC()))
    96  	}
    97  	if filter.TimeTo != nil {
    98  		where = append(where, q.Lte("Time", filter.TimeTo.UTC()))
    99  	}
   100  	if filter.ProviderID != nil {
   101  		id := filter.ProviderID
   102  		where = append(where, q.Eq("ProviderID", *id))
   103  	}
   104  	if filter.HermesID != nil {
   105  		where = append(where, q.Eq("HermesID", filter.HermesID))
   106  	}
   107  	if len(filter.Types) > 0 {
   108  		if contains(filter.Types, WithdrawalType) {
   109  			where = append(where, q.Eq("IsWithdrawal", true))
   110  		}
   111  		if contains(filter.Types, SettlementType) {
   112  			where = append(where, q.Eq("IsWithdrawal", false))
   113  		}
   114  	}
   115  
   116  	shs.bolt.RLock()
   117  	defer shs.bolt.RUnlock()
   118  	sq := shs.bolt.DB().
   119  		From(settlementHistoryBucket).
   120  		Select(q.And(where...)).
   121  		OrderBy("Time").
   122  		Reverse()
   123  
   124  	err = sq.Find(&result)
   125  	if errors.Is(err, storm.ErrNotFound) {
   126  		return []SettlementHistoryEntry{}, nil
   127  	}
   128  
   129  	return result, err
   130  }
   131  
   132  func contains(sources []HistoryType, target HistoryType) bool {
   133  	for _, source := range sources {
   134  		if source == target {
   135  			return true
   136  		}
   137  	}
   138  
   139  	return false
   140  }