Files
ark/asp/internal/core/application/utils.go
Pietralberto Mazza d150c4bbac Add support for collaborative redemption of vtxos & Changes to ark wallet (#72)
* Add internal support for collaborative exit

* Update protos and interface layer

* Fixes after proto updates

* Fix printing json & Do not print ark pubkey in config

* Add collaborative redeem command

* Polish

* Add address validation

* Fix building tree without right branch

* Fixes and validation checks

* Fixes

* Fix counting complete queued payments

* Add relays

* Add and compute onchain balance concurrently

* Tiny refactor

* Merge `config connect` into `init` cmd
2023-12-29 17:09:50 +01:00

203 lines
4.1 KiB
Go

package application
import (
"fmt"
"sort"
"sync"
"time"
"github.com/ark-network/ark/internal/core/domain"
"github.com/vulpemventures/go-elements/psetv2"
)
type timedPayment struct {
domain.Payment
timestamp time.Time
pingTimestamp time.Time
}
type paymentsMap struct {
lock *sync.RWMutex
payments map[string]*timedPayment
}
func newPaymentsMap(payments []domain.Payment) *paymentsMap {
paymentsById := make(map[string]*timedPayment)
for _, p := range payments {
paymentsById[p.Id] = &timedPayment{p, time.Now(), time.Time{}}
}
lock := &sync.RWMutex{}
return &paymentsMap{lock, paymentsById}
}
func (m *paymentsMap) len() int64 {
m.lock.RLock()
defer m.lock.RUnlock()
count := int64(0)
for _, p := range m.payments {
if len(p.Receivers) > 0 {
count++
}
}
return count
}
func (m *paymentsMap) push(payment domain.Payment) error {
m.lock.Lock()
defer m.lock.Unlock()
if _, ok := m.payments[payment.Id]; ok {
return fmt.Errorf("duplicated inputs")
}
m.payments[payment.Id] = &timedPayment{payment, time.Now(), time.Time{}}
return nil
}
func (m *paymentsMap) pop(num int64) []domain.Payment {
m.lock.Lock()
defer m.lock.Unlock()
paymentsByTime := make([]timedPayment, 0, len(m.payments))
for _, p := range m.payments {
// Skip payments without registered receivers.
if len(p.Receivers) <= 0 {
continue
}
// Skip payments for which users didn't notify to be online in the last minute.
if p.pingTimestamp.IsZero() || time.Since(p.pingTimestamp).Minutes() > 1 {
continue
}
paymentsByTime = append(paymentsByTime, *p)
}
sort.SliceStable(paymentsByTime, func(i, j int) bool {
return paymentsByTime[i].timestamp.Before(paymentsByTime[j].timestamp)
})
if num < 0 || num > int64(len(paymentsByTime)) {
num = int64(len(paymentsByTime))
}
payments := make([]domain.Payment, 0, num)
for _, p := range paymentsByTime[:num] {
payments = append(payments, p.Payment)
delete(m.payments, p.Id)
}
return payments
}
func (m *paymentsMap) update(payment domain.Payment) error {
m.lock.Lock()
defer m.lock.Unlock()
p, ok := m.payments[payment.Id]
if !ok {
return fmt.Errorf("payment %s not found", payment.Id)
}
p.Payment = payment
return nil
}
func (m *paymentsMap) updatePingTimestamp(id string) error {
m.lock.Lock()
defer m.lock.Unlock()
payment, ok := m.payments[id]
if !ok {
return fmt.Errorf("payment %s not found", id)
}
payment.pingTimestamp = time.Now()
return nil
}
func (m *paymentsMap) view(id string) (*domain.Payment, bool) {
m.lock.RLock()
defer m.lock.RUnlock()
payment, ok := m.payments[id]
if !ok {
return nil, false
}
return &domain.Payment{
Id: payment.Id,
Inputs: payment.Inputs,
Receivers: payment.Receivers,
}, true
}
type signedTx struct {
tx string
signed bool
}
type forfeitTxsMap struct {
lock *sync.RWMutex
forfeitTxs map[string]*signedTx
}
func newForfeitTxsMap() *forfeitTxsMap {
return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx)}
}
func (m *forfeitTxsMap) push(txs []string) {
m.lock.Lock()
defer m.lock.Unlock()
for _, tx := range txs {
ptx, _ := psetv2.NewPsetFromBase64(tx)
utx, _ := ptx.UnsignedTx()
m.forfeitTxs[utx.TxHash().String()] = &signedTx{tx, false}
}
}
func (m *forfeitTxsMap) sign(txs []string) error {
m.lock.Lock()
defer m.lock.Unlock()
for _, tx := range txs {
ptx, err := psetv2.NewPsetFromBase64(tx)
if err != nil {
return fmt.Errorf("invalid forfeit tx format")
}
utx, _ := ptx.UnsignedTx()
txid := utx.TxHash().String()
if _, ok := m.forfeitTxs[txid]; !ok {
return fmt.Errorf("forfeit tx %s not found", txid)
}
m.forfeitTxs[txid].signed = true
}
return nil
}
func (m *forfeitTxsMap) pop() (signed, unsigned []string) {
m.lock.Lock()
defer m.lock.Unlock()
for _, t := range m.forfeitTxs {
if t.signed {
signed = append(signed, t.tx)
} else {
unsigned = append(unsigned, t.tx)
}
}
m.forfeitTxs = make(map[string]*signedTx)
return signed, unsigned
}
func (m *forfeitTxsMap) view() []string {
m.lock.RLock()
defer m.lock.RUnlock()
txs := make([]string, 0, len(m.forfeitTxs))
for _, tx := range m.forfeitTxs {
txs = append(txs, tx.tx)
}
return txs
}