mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-17 04:04:21 +01:00
Rename folders (#97)
* Rename arkd folder & drop cli * Rename ark cli folder & update docs * Update readme * Fix * scripts: add build-all * Add target to build cli for all platforms * Update build scripts --------- Co-authored-by: tiero <3596602+tiero@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
0d8c7bffb2
commit
dc00d60585
254
server/internal/core/application/utils.go
Normal file
254
server/internal/core/application/utils.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/internal/core/domain"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"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
|
||||
genesisBlockHash *chainhash.Hash
|
||||
}
|
||||
|
||||
func newForfeitTxsMap(genesisBlockHash *chainhash.Hash) *forfeitTxsMap {
|
||||
return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx), genesisBlockHash}
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) push(txs []string) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
faucetTxID, _ := hex.DecodeString(faucetVtxo.Txid)
|
||||
|
||||
for _, tx := range txs {
|
||||
ptx, _ := psetv2.NewPsetFromBase64(tx)
|
||||
utx, _ := ptx.UnsignedTx()
|
||||
|
||||
signed := false
|
||||
|
||||
// find the faucet vtxos, and mark them as signed
|
||||
for _, input := range ptx.Inputs {
|
||||
if bytes.Equal(input.PreviousTxid, faucetTxID) {
|
||||
signed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
m.forfeitTxs[utx.TxHash().String()] = &signedTx{tx, signed}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) sign(txs []string) error {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
for _, tx := range txs {
|
||||
ptx, _ := psetv2.NewPsetFromBase64(tx)
|
||||
utx, _ := ptx.UnsignedTx()
|
||||
txid := utx.TxHash().String()
|
||||
|
||||
if _, ok := m.forfeitTxs[txid]; ok {
|
||||
for index, input := range ptx.Inputs {
|
||||
if len(input.TapScriptSig) > 0 {
|
||||
for _, tapScriptSig := range input.TapScriptSig {
|
||||
leafHash, err := chainhash.NewHash(tapScriptSig.LeafHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
preimage, err := common.TaprootPreimage(
|
||||
m.genesisBlockHash,
|
||||
ptx,
|
||||
index,
|
||||
leafHash,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := schnorr.ParseSignature(tapScriptSig.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubkey, err := schnorr.ParsePubKey(tapScriptSig.PubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sig.Verify(preimage, pubkey) {
|
||||
m.forfeitTxs[txid].signed = true
|
||||
} else {
|
||||
return fmt.Errorf("invalid signature")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user