gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/skynetfees.go (about)

     1  package renter
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"sync"
     7  	"time"
     8  
     9  	"gitlab.com/NebulousLabs/errors"
    10  	"go.sia.tech/siad/persist"
    11  	"go.sia.tech/siad/types"
    12  )
    13  
    14  // TODO: To improve reliability, keep the txns in memory until they are
    15  // confirmed and reapply them regularly. After failing too many times, send a
    16  // new txn.
    17  
    18  type (
    19  	// spendingHistory tracks the history of the renter spending relevant to
    20  	// skynet fees.
    21  	spendingHistory struct {
    22  		recentSpending spendingEntry
    23  
    24  		staticAop *persist.AppendOnlyPersist
    25  		mu        sync.Mutex
    26  	}
    27  
    28  	// spendingEntry is the definition of a persisted entry.
    29  	spendingEntry struct {
    30  		// Value resembles the total spending at the time of persisting the
    31  		// entry.
    32  		Value types.Currency `json:"value"`
    33  
    34  		// Txn is the txn that was used to pay the delta between the previous
    35  		// spending entry and this one. It's currently not used but in the future
    36  		// it can be used for rebroadcasting the txn.
    37  		Txn []types.Transaction `json:"txn"`
    38  
    39  		// Time is the time at which the last entry was saved. That way we can
    40  		// determine whether or not a txn is old enough to be replaced.
    41  		Time time.Time `json:"time"`
    42  	}
    43  )
    44  
    45  var (
    46  	// spendingHistoryMDHeader is the header of the metadata for the persist file
    47  	spendingHistoryMDHeader = types.NewSpecifier("SpendingHistory")
    48  )
    49  
    50  // loadSpendingHistory loads the spending history from the reader.
    51  func loadSpendingHistory(r io.Reader) (spendingEntry, error) {
    52  	decoder := json.NewDecoder(r)
    53  
    54  	var recentSpending spendingEntry
    55  	for {
    56  		var spending spendingEntry
    57  		err := decoder.Decode(&spending)
    58  		if errors.Contains(err, io.EOF) {
    59  			break
    60  		} else if err != nil {
    61  			return spendingEntry{}, err
    62  		}
    63  		recentSpending = spending
    64  	}
    65  	return recentSpending, nil
    66  }
    67  
    68  // NewSpendingHistory creates a new spending history or loads an existing one
    69  // from disk.
    70  func NewSpendingHistory(dir, filename string) (*spendingHistory, error) {
    71  	// Open persistence.
    72  	aop, r, err := persist.NewAppendOnlyPersist(dir, filename, spendingHistoryMDHeader, persist.MetadataVersionv156)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	// Load existing accumulated fees.
    77  	spending, err := loadSpendingHistory(r)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	return &spendingHistory{
    82  		staticAop:      aop,
    83  		recentSpending: spending,
    84  	}, nil
    85  }
    86  
    87  // Close closes the underlying persistence.
    88  func (sh *spendingHistory) Close() error {
    89  	return sh.staticAop.Close()
    90  }
    91  
    92  // AddSpending adds a new entry. This includes the value and the txn used to pay
    93  // for the delta since the last value.
    94  func (sh *spendingHistory) AddSpending(spending types.Currency, txn []types.Transaction, t time.Time) error {
    95  	sh.mu.Lock()
    96  	defer sh.mu.Unlock()
    97  
    98  	// Marshal the entry.
    99  	entry := spendingEntry{
   100  		Time:  t,
   101  		Txn:   txn,
   102  		Value: spending,
   103  	}
   104  	entryBytes, err := json.Marshal(entry)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	// Write it to disk.
   109  	_, err = sh.staticAop.Write(entryBytes)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	// Update it in memory.
   114  	sh.recentSpending = entry
   115  	return nil
   116  }
   117  
   118  // LastSpending returns the last saved spending entry value and timestamp.
   119  func (sh *spendingHistory) LastSpending() (types.Currency, time.Time) {
   120  	sh.mu.Lock()
   121  	defer sh.mu.Unlock()
   122  	return sh.recentSpending.Value, sh.recentSpending.Time
   123  }