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 }