[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:
Louis Singer
2024-11-18 19:08:10 +01:00
committed by GitHub
parent 6ed4e30b6d
commit 0d2db92173
14 changed files with 712 additions and 729 deletions

View File

@@ -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