mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-17 04:04:21 +01:00
[Server] Validate forfeit txs without re-building them (#382)
* compute forfeit partial tx client-side first * fix conflict * go work sync * move verify sig in VerifyForfeits * move check after len(inputs)
This commit is contained in:
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip19"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type timedPayment struct {
|
||||
@@ -28,14 +27,13 @@ type timedPayment struct {
|
||||
type paymentsMap struct {
|
||||
lock *sync.RWMutex
|
||||
payments map[string]*timedPayment
|
||||
descriptors map[domain.VtxoKey]string
|
||||
ephemeralKeys map[string]*secp256k1.PublicKey
|
||||
}
|
||||
|
||||
func newPaymentsMap() *paymentsMap {
|
||||
paymentsById := make(map[string]*timedPayment)
|
||||
lock := &sync.RWMutex{}
|
||||
return &paymentsMap{lock, paymentsById, make(map[domain.VtxoKey]string), make(map[string]*secp256k1.PublicKey)}
|
||||
return &paymentsMap{lock, paymentsById, make(map[string]*secp256k1.PublicKey)}
|
||||
}
|
||||
|
||||
func (m *paymentsMap) len() int64 {
|
||||
@@ -88,7 +86,6 @@ func (m *paymentsMap) pushWithNotes(payment domain.Payment, notes []note.Note) e
|
||||
func (m *paymentsMap) push(
|
||||
payment domain.Payment,
|
||||
boardingInputs []ports.BoardingInput,
|
||||
descriptors map[domain.VtxoKey]string,
|
||||
) error {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
@@ -117,10 +114,6 @@ func (m *paymentsMap) push(
|
||||
}
|
||||
}
|
||||
|
||||
for key, desc := range descriptors {
|
||||
m.descriptors[key] = desc
|
||||
}
|
||||
|
||||
m.payments[payment.Id] = &timedPayment{payment, boardingInputs, make([]note.Note, 0), time.Now(), time.Time{}}
|
||||
return nil
|
||||
}
|
||||
@@ -137,7 +130,7 @@ func (m *paymentsMap) pushEphemeralKey(paymentId string, pubkey *secp256k1.Publi
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, map[domain.VtxoKey]string, []*secp256k1.PublicKey, []note.Note) {
|
||||
func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, []*secp256k1.PublicKey, []note.Note) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
@@ -164,7 +157,6 @@ func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, m
|
||||
payments := make([]domain.Payment, 0, num)
|
||||
boardingInputs := make([]ports.BoardingInput, 0)
|
||||
cosigners := make([]*secp256k1.PublicKey, 0, num)
|
||||
descriptors := make(map[domain.VtxoKey]string)
|
||||
notes := make([]note.Note, 0)
|
||||
for _, p := range paymentsByTime[:num] {
|
||||
boardingInputs = append(boardingInputs, p.boardingInputs...)
|
||||
@@ -174,13 +166,9 @@ func (m *paymentsMap) pop(num int64) ([]domain.Payment, []ports.BoardingInput, m
|
||||
delete(m.ephemeralKeys, p.Payment.Id)
|
||||
}
|
||||
notes = append(notes, p.notes...)
|
||||
for _, vtxo := range p.Payment.Inputs {
|
||||
descriptors[vtxo.VtxoKey] = m.descriptors[vtxo.VtxoKey]
|
||||
delete(m.descriptors, vtxo.VtxoKey)
|
||||
}
|
||||
delete(m.payments, p.Id)
|
||||
}
|
||||
return payments, boardingInputs, descriptors, cosigners, notes
|
||||
return payments, boardingInputs, cosigners, notes
|
||||
}
|
||||
|
||||
func (m *paymentsMap) update(payment domain.Payment) error {
|
||||
@@ -250,73 +238,84 @@ func (m *paymentsMap) view(id string) (*domain.Payment, bool) {
|
||||
}, true
|
||||
}
|
||||
|
||||
type signedTx struct {
|
||||
tx string
|
||||
signed bool
|
||||
}
|
||||
|
||||
type forfeitTxsMap struct {
|
||||
lock *sync.RWMutex
|
||||
forfeitTxs map[string]*signedTx
|
||||
builder ports.TxBuilder
|
||||
lock *sync.RWMutex
|
||||
builder ports.TxBuilder
|
||||
|
||||
forfeitTxs map[domain.VtxoKey][]string
|
||||
connectors []string
|
||||
vtxos []domain.Vtxo
|
||||
}
|
||||
|
||||
func newForfeitTxsMap(txBuilder ports.TxBuilder) *forfeitTxsMap {
|
||||
return &forfeitTxsMap{&sync.RWMutex{}, make(map[string]*signedTx), txBuilder}
|
||||
return &forfeitTxsMap{&sync.RWMutex{}, txBuilder, make(map[domain.VtxoKey][]string), nil, nil}
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) push(txs []string) error {
|
||||
func (m *forfeitTxsMap) init(connectors []string, payments []domain.Payment) {
|
||||
vtxosToSign := make([]domain.Vtxo, 0)
|
||||
for _, payment := range payments {
|
||||
vtxosToSign = append(vtxosToSign, payment.Inputs...)
|
||||
}
|
||||
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
for _, tx := range txs {
|
||||
txid, err := m.builder.GetTxID(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.forfeitTxs[txid] = &signedTx{tx, false}
|
||||
m.vtxos = vtxosToSign
|
||||
m.connectors = connectors
|
||||
for _, vtxo := range vtxosToSign {
|
||||
m.forfeitTxs[vtxo.VtxoKey] = make([]string, 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) sign(txs []string) error {
|
||||
if len(txs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(m.vtxos) == 0 || len(m.connectors) == 0 {
|
||||
return fmt.Errorf("forfeit txs map not initialized")
|
||||
}
|
||||
|
||||
// verify the txs are valid
|
||||
validTxs, err := m.builder.VerifyForfeitTxs(m.vtxos, m.connectors, txs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
for _, tx := range txs {
|
||||
valid, txid, err := m.builder.VerifyTapscriptPartialSigs(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := m.forfeitTxs[txid]; ok {
|
||||
if valid {
|
||||
m.forfeitTxs[txid].tx = tx
|
||||
m.forfeitTxs[txid].signed = true
|
||||
} else {
|
||||
logrus.Warnf("invalid forfeit tx signature (%s)", txid)
|
||||
}
|
||||
}
|
||||
for vtxoKey, txs := range validTxs {
|
||||
m.forfeitTxs[vtxoKey] = txs
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) pop() (signed, unsigned []string) {
|
||||
func (m *forfeitTxsMap) reset() {
|
||||
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[domain.VtxoKey][]string)
|
||||
m.connectors = nil
|
||||
}
|
||||
|
||||
func (m *forfeitTxsMap) pop() ([]string, error) {
|
||||
m.lock.Lock()
|
||||
defer func() {
|
||||
m.lock.Unlock()
|
||||
m.reset()
|
||||
}()
|
||||
|
||||
txs := make([]string, 0)
|
||||
for vtxoKey, signed := range m.forfeitTxs {
|
||||
if len(signed) == 0 {
|
||||
return nil, fmt.Errorf("missing forfeit txs for vtxo %s", vtxoKey)
|
||||
}
|
||||
txs = append(txs, signed...)
|
||||
}
|
||||
|
||||
m.forfeitTxs = make(map[string]*signedTx)
|
||||
return signed, unsigned
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
// onchainOutputs iterates over all the nodes' outputs in the congestion tree and checks their onchain state
|
||||
|
||||
Reference in New Issue
Block a user