package state import ( "time" "ripple/bug" "ripple/config" "ripple/errmsgs" "ripple/types" ) const ( Commit = 0 Seal = 1 Finalize = 2 Cancel = 3 Cleanup = 4 ) type User struct { types.UserIdentifier SecretKey [32]byte Counter uint32 } type Sync struct { CommitOut bool AckPreimage bool FinalizeOut uint64 AckSync bool Synced bool } type Payment struct { Amount uint64 Incoming types.UserIdentifier Outgoing types.UserIdentifier Counterpart types.UserIdentifier PenaltyRate uint32 CommitPenalty uint64 FeeIn uint64 FeeOut uint64 Preimage [32]byte Status byte Sync CreatedAt int64 } type Account struct { Port int SecretKey [32]byte CounterIn uint32 CounterOut uint32 Balance int64 Creditlimit uint64 Pending map[[32]byte]struct{} } type Receipt struct { Identifier [32]byte Counterpart types.UserIdentifier Amount int64 Timestamp int64 } type Storage struct { Port int User User Accounts map[types.UserIdentifier]Account Payments map[[32]byte]Payment Receipts [config.BufferSize]Receipt } func (s *Storage) MustGetAccount(id types.UserIdentifier) Account { acc, ok := s.Accounts[id] if !ok { panic(bug.BugStateViolated) } return acc } func (s *Storage) AccountExists(id types.UserIdentifier) bool { _, ok := s.Accounts[id] return ok } func (s *Storage) AddAccount(id types.UserIdentifier, port int, secretKey [32]byte) error { if s.AccountExists(id) { panic(bug.BugStateViolated) } if len(s.Accounts) >= config.BufferSize { return errmsgs.ErrBufferFull } s.Accounts[id] = Account{ Port: port, SecretKey: secretKey, Pending: make(map[[32]byte]struct{}), } return nil } func (s *Storage) RemoveAccount(id types.UserIdentifier) { if !s.AccountExists(id) { panic(bug.BugStateViolated) } delete(s.Accounts, id) } func (s *Storage) MustGetPayment(paymentID [32]byte) Payment { payment, ok := s.Payments[paymentID] if !ok { panic(bug.BugStateViolated) } return payment } func (s *Storage) GetBandwidthIn(id types.UserIdentifier) int64 { acc := s.MustGetAccount(id) bandwidth := int64(acc.Creditlimit) - acc.Balance for paymentID := range acc.Pending { payment := s.MustGetPayment(paymentID) if payment.Incoming == id { bandwidth -= int64(payment.Amount+payment.FeeIn) } } if bandwidth < 0 { panic(bug.BugStateViolated) } return bandwidth } func (s *Storage) AddReceipt(r Receipt) { copy(s.Receipts[1:], s.Receipts[:]) s.Receipts[0] = r } func (s *Storage) MustSetPending(id types.UserIdentifier, paymentID [32]byte) { acc := s.MustGetAccount(id) acc.Pending[paymentID] = struct{}{} s.Accounts[id] = acc } func (s *Storage) RemovePending(id types.UserIdentifier, paymentID [32]byte) { acc := s.MustGetAccount(id) delete(acc.Pending, paymentID) s.Accounts[id] = acc } func (s *Storage) MustFinalizePayment(userID types.UserIdentifier, paymentID [32]byte, amount int64) { acc := s.MustGetAccount(userID) if _, ok := acc.Pending[paymentID]; !ok { panic(bug.BugStateViolated) } acc.Balance += amount delete(acc.Pending, paymentID) s.Accounts[userID] = acc } func (p *Payment) CounterpartIn() bool { return p.Counterpart.IsSet() && p.Incoming.IsEmpty() } func (p *Payment) CounterpartOut() bool { return p.Counterpart.IsSet() && p.Outgoing.IsEmpty() } func (p *Payment) SynchronizedIn() bool { ackPreimage := !p.Finalizing() || p.AckPreimage return p.Synced && ackPreimage || p.CounterpartIn() } func (p *Payment) SynchronizedOut() bool { ackPreimage := !p.Cancelling() || p.AckPreimage commitOut := p.Finalizing() || p.CommitOut return p.AckSync && ackPreimage && commitOut || p.CounterpartOut() } func (p *Payment) Seal() { p.Status = Seal } func (p *Payment) Finalize() { p.Status = Finalize } func (p *Payment) Cancel() { p.Status = Cancel } func (p *Payment) Cleanup() { p.Status = Cleanup } func (p *Payment) Committing() bool { return p.Status == Commit } func (p *Payment) Sealing() bool { return p.Status == Seal } func (p *Payment) Finalizing() bool { return p.Status == Finalize } func (p *Payment) Cancelling() bool { return p.Status == Cancel } func (p *Payment) Cleaning() bool { return p.Status == Cleanup } func (p *Payment) Syncing() bool { return p.Finalizing() || p.Cancelling() || p.Cleaning() } func (p *Payment) PenaltyTicker() uint64 { now := time.Now().Unix() if now > p.CreatedAt && p.PenaltyRate > 0 { penaltyTicker := uint64((now - p.CreatedAt)/int64(p.PenaltyRate)) if penaltyTicker > p.Amount { return p.Amount } return penaltyTicker } return 0 } func (p *Payment) SealPenalty(penaltyTicker uint64) uint64 { if penaltyTicker > p.CommitPenalty { return penaltyTicker - p.CommitPenalty } return 0 }