mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 12:44:19 +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:
@@ -463,7 +463,7 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp
|
||||
now := time.Now().Unix()
|
||||
|
||||
boardingTxs := make(map[string]wire.MsgTx, 0) // txid -> txhex
|
||||
descriptors := make(map[domain.VtxoKey]string)
|
||||
|
||||
for _, input := range inputs {
|
||||
vtxosResult, err := s.repoManager.Vtxos().GetVtxos(ctx, []domain.VtxoKey{input.VtxoKey})
|
||||
if err != nil || len(vtxosResult) == 0 {
|
||||
@@ -520,7 +520,24 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp
|
||||
return "", fmt.Errorf("input %s:%d already swept", vtxo.Txid, vtxo.VOut)
|
||||
}
|
||||
|
||||
descriptors[vtxo.VtxoKey] = input.Descriptor
|
||||
vtxoScript, err := bitcointree.ParseVtxoScript(input.Descriptor)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse boarding descriptor: %s", err)
|
||||
}
|
||||
|
||||
tapKey, _, err := vtxoScript.TapTree()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get taproot key: %s", err)
|
||||
}
|
||||
|
||||
expectedTapKey, err := vtxo.TapKey()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get taproot key: %s", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(schnorr.SerializePubKey(tapKey), schnorr.SerializePubKey(expectedTapKey)) {
|
||||
return "", fmt.Errorf("descriptor does not match vtxo pubkey")
|
||||
}
|
||||
|
||||
vtxosInputs = append(vtxosInputs, vtxo)
|
||||
}
|
||||
@@ -529,7 +546,7 @@ func (s *covenantlessService) SpendVtxos(ctx context.Context, inputs []ports.Inp
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := s.paymentRequests.push(*payment, boardingInputs, descriptors); err != nil {
|
||||
if err := s.paymentRequests.push(*payment, boardingInputs); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return payment.Id, nil
|
||||
@@ -872,7 +889,7 @@ func (s *covenantlessService) startFinalization() {
|
||||
if num > paymentsThreshold {
|
||||
num = paymentsThreshold
|
||||
}
|
||||
payments, boardingInputs, descriptors, cosigners, paymentsNotes := s.paymentRequests.pop(num)
|
||||
payments, boardingInputs, cosigners, paymentsNotes := s.paymentRequests.pop(num)
|
||||
if len(payments) > len(cosigners) {
|
||||
err := fmt.Errorf("missing ephemeral key for payments")
|
||||
round.Fail(fmt.Errorf("round aborted: %s", err))
|
||||
@@ -904,13 +921,21 @@ func (s *covenantlessService) startFinalization() {
|
||||
|
||||
cosigners = append(cosigners, ephemeralKey.PubKey())
|
||||
|
||||
unsignedRoundTx, tree, connectorAddress, err := s.builder.BuildRoundTx(s.pubkey, payments, boardingInputs, sweptRounds, cosigners...)
|
||||
unsignedRoundTx, tree, connectorAddress, connectors, err := s.builder.BuildRoundTx(
|
||||
s.pubkey,
|
||||
payments,
|
||||
boardingInputs,
|
||||
sweptRounds,
|
||||
cosigners...,
|
||||
)
|
||||
if err != nil {
|
||||
round.Fail(fmt.Errorf("failed to create pool tx: %s", err))
|
||||
log.WithError(err).Warn("failed to create pool tx")
|
||||
round.Fail(fmt.Errorf("failed to create round tx: %s", err))
|
||||
log.WithError(err).Warn("failed to create round tx")
|
||||
return
|
||||
}
|
||||
log.Debugf("pool tx created for round %s", round.Id)
|
||||
log.Debugf("round tx created for round %s", round.Id)
|
||||
|
||||
s.forfeitTxs.init(connectors, payments)
|
||||
|
||||
if len(tree) > 0 {
|
||||
log.Debugf("signing congestion tree for round %s", round.Id)
|
||||
@@ -1063,34 +1088,6 @@ func (s *covenantlessService) startFinalization() {
|
||||
tree = signedTree
|
||||
}
|
||||
|
||||
needForfeits := false
|
||||
for _, pay := range payments {
|
||||
if len(pay.Inputs) > 0 {
|
||||
needForfeits = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var forfeitTxs, connectors []string
|
||||
|
||||
minRelayFeeRate := s.wallet.MinRelayFeeRate(ctx)
|
||||
|
||||
if needForfeits {
|
||||
connectors, forfeitTxs, err = s.builder.BuildForfeitTxs(unsignedRoundTx, payments, descriptors, minRelayFeeRate)
|
||||
if err != nil {
|
||||
round.Fail(fmt.Errorf("failed to create connectors and forfeit txs: %s", err))
|
||||
log.WithError(err).Warn("failed to create connectors and forfeit txs")
|
||||
return
|
||||
}
|
||||
log.Debugf("forfeit transactions created for round %s", round.Id)
|
||||
|
||||
if err := s.forfeitTxs.push(forfeitTxs); err != nil {
|
||||
round.Fail(fmt.Errorf("failed to store forfeit txs: %s", err))
|
||||
log.WithError(err).Warn("failed to store forfeit txs")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := round.StartFinalization(
|
||||
connectorAddress, connectors, tree, unsignedRoundTx,
|
||||
); err != nil {
|
||||
@@ -1143,9 +1140,8 @@ func (s *covenantlessService) finalizeRound(notes []note.Note) {
|
||||
}
|
||||
}()
|
||||
|
||||
forfeitTxs, leftUnsigned := s.forfeitTxs.pop()
|
||||
if len(leftUnsigned) > 0 {
|
||||
err := fmt.Errorf("%d forfeit txs left to sign", len(leftUnsigned))
|
||||
forfeitTxs, err := s.forfeitTxs.pop()
|
||||
if err != nil {
|
||||
changes = round.Fail(fmt.Errorf("failed to finalize round: %s", err))
|
||||
log.WithError(err).Warn("failed to finalize round")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user