294d253923
All code on known satellites at this moment in time should know how to populate and use the new numeric columns on the stripecoinpayments_tx_conversion_rates and coinpayments_transactions tables in the satellite db. However, there are still gob-encoded big.Float values in the database from before these columns existed. To get rid of those values, so that we can excise the gob-decoding code from the relevant sections, however, we need something to read the gob bytestrings and convert them to numeric values, a few at a time, until they're all gone. To accomplish that, this change adds two chores to be run in the satellite core process- one for the coinpayments_transactions table, and one for the stripecoinpayments_tx_conversion_rates table. They should run relatively infrequently, so that we do not impose any undue load on processing resources or the db. Both of these chores work without using explicit sql transactions, but should still be concurrent-safe, since they work by way of compare-and-swap type operations. If the satellite core process needs to be restarted, both of these chores will start scanning for migrateable rows from the beginning of the id space again. This is not ideal, but shouldn't be a problem (as far as I can tell, there are only a few thousand rows at most in either of these tables on any production satellite). Change-Id: I733b7cd96760d506a1cf52735f598c6c3aa19735
106 lines
4.5 KiB
Go
106 lines
4.5 KiB
Go
// Copyright (C) 2019 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package stripecoinpayments
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"github.com/zeebo/errs"
|
|
|
|
"storj.io/common/uuid"
|
|
"storj.io/storj/satellite/payments/coinpayments"
|
|
"storj.io/storj/satellite/payments/monetary"
|
|
)
|
|
|
|
// ErrTransactionConsumed is thrown when trying to consume already consumed transaction.
|
|
var ErrTransactionConsumed = errs.New("error transaction already consumed")
|
|
|
|
// TransactionsDB is an interface which defines functionality
|
|
// of DB which stores coinpayments transactions.
|
|
//
|
|
// architecture: Database
|
|
type TransactionsDB interface {
|
|
// Insert inserts new coinpayments transaction into DB.
|
|
Insert(ctx context.Context, tx Transaction) (time.Time, error)
|
|
// Update updates status and received for set of transactions.
|
|
Update(ctx context.Context, updates []TransactionUpdate, applies coinpayments.TransactionIDList) error
|
|
// Consume marks transaction as consumed, so it won't participate in apply account balance loop.
|
|
Consume(ctx context.Context, id coinpayments.TransactionID) error
|
|
// LockRate locks conversion rate for transaction.
|
|
LockRate(ctx context.Context, id coinpayments.TransactionID, rate decimal.Decimal) error
|
|
// GetLockedRate returns locked conversion rate for transaction or error if non exists.
|
|
GetLockedRate(ctx context.Context, id coinpayments.TransactionID) (decimal.Decimal, error)
|
|
// ListAccount returns all transaction for specific user.
|
|
ListAccount(ctx context.Context, userID uuid.UUID) ([]Transaction, error)
|
|
// ListPending returns TransactionsPage with pending transactions.
|
|
ListPending(ctx context.Context, offset int64, limit int, before time.Time) (TransactionsPage, error)
|
|
// ListUnapplied returns TransactionsPage with completed transaction that should be applied to account balance.
|
|
ListUnapplied(ctx context.Context, offset int64, limit int, before time.Time) (TransactionsPage, error)
|
|
|
|
// MigrateGobFloatTransactionRecords is a strictly-temporary task that will, with time, eliminate gob-encoded big.Float records from the coinpayments_transactions table. It should be called repeatedly, passing back nextRangeStart for the next rangeStart parameter, until it encounters an error or returns nextRangeStart = "".
|
|
MigrateGobFloatTransactionRecords(ctx context.Context, rangeStart string, limit int) (migrated int, nextRangeStart string, err error)
|
|
// MigrateGobFloatConversionRateRecords is a strictly-temporary task that will, with time, eliminate gob-encoded big.Float records from the stripecoinpayments_tx_conversion_rates table. It should be called repeatedly, passing back nextRangeStart for the next rangeStart parameter, until it encounters an error or returns nextRangeStart = "".
|
|
MigrateGobFloatConversionRateRecords(ctx context.Context, rangeStart string, limit int) (migrated int, nextRangeStart string, err error)
|
|
}
|
|
|
|
// Transaction defines coinpayments transaction info that is stored in the DB.
|
|
type Transaction struct {
|
|
ID coinpayments.TransactionID
|
|
AccountID uuid.UUID
|
|
Address string
|
|
Amount monetary.Amount
|
|
Received monetary.Amount
|
|
Status coinpayments.Status
|
|
Key string
|
|
Timeout time.Duration
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// TransactionUpdate holds transaction update info.
|
|
type TransactionUpdate struct {
|
|
TransactionID coinpayments.TransactionID
|
|
Status coinpayments.Status
|
|
Received monetary.Amount
|
|
}
|
|
|
|
// TransactionsPage holds set of transaction and indicates if
|
|
// there are more transactions to fetch.
|
|
type TransactionsPage struct {
|
|
Transactions []Transaction
|
|
Next bool
|
|
NextOffset int64
|
|
}
|
|
|
|
// IDList returns transaction id list of page's transactions.
|
|
func (page *TransactionsPage) IDList() TransactionAndUserList {
|
|
var ids = make(TransactionAndUserList)
|
|
for _, tx := range page.Transactions {
|
|
ids[tx.ID] = tx.AccountID
|
|
}
|
|
return ids
|
|
}
|
|
|
|
// CreationTimes returns a map of creation times of page's transactions.
|
|
func (page *TransactionsPage) CreationTimes() map[coinpayments.TransactionID]time.Time {
|
|
creationTimes := make(map[coinpayments.TransactionID]time.Time)
|
|
for _, tx := range page.Transactions {
|
|
creationTimes[tx.ID] = tx.CreatedAt
|
|
}
|
|
return creationTimes
|
|
}
|
|
|
|
// TransactionAndUserList is a composite type for storing userID and txID.
|
|
type TransactionAndUserList map[coinpayments.TransactionID]uuid.UUID
|
|
|
|
// IDList returns transaction id list.
|
|
func (idMap TransactionAndUserList) IDList() coinpayments.TransactionIDList {
|
|
var list coinpayments.TransactionIDList
|
|
for transactionID := range idMap {
|
|
list = append(list, transactionID)
|
|
}
|
|
return list
|
|
}
|