multi: make sure previous inconsitent states are fixed

We make sure that nodes previously suffering from this error will
have a consitent db view when restarting their node.
This commit is contained in:
ziggie committed 2026-01-06 14:34:52 +01:00
1 parent 51f3c6f528
commit d9fb9092b6
4 files changed
+438 -3

No files matched your search

+91
View File
@@ -2,6 +2,8 @@ package channeldb
import (
"bytes"
"errors"
"fmt"
"io"
"net"
"time"
@@ -134,6 +136,95 @@ type LinkNodeDB struct {
backend kvdb.Backend
}
// FindMissingLinkNodes checks which of the provided public keys do not have
// corresponding link nodes in the database. If tx is nil, a new read
// transaction will be created. Otherwise, the provided transaction is used,
// allowing this to be part of a larger batch operation.
func (l *LinkNodeDB) FindMissingLinkNodes(tx kvdb.RTx,
pubKeys []*btcec.PublicKey) ([]*btcec.PublicKey, error) {
var missing []*btcec.PublicKey
findMissing := func(readTx kvdb.RTx) error {
nodeMetaBucket := readTx.ReadBucket(nodeInfoBucket)
if nodeMetaBucket == nil {
// If the bucket doesn't exist, all peers are missing.
missing = pubKeys
return nil
}
for _, pubKey := range pubKeys {
_, err := fetchLinkNode(readTx, pubKey)
if err == nil {
// Link node exists.
continue
}
if !errors.Is(err, ErrNodeNotFound) {
return fmt.Errorf("unable to check link node "+
"for peer %x: %w",
pubKey.SerializeCompressed(), err)
}
// Link node doesn't exist.
missing = append(missing, pubKey)
}
return nil
}
// If no transaction provided, create our own.
if tx == nil {
err := kvdb.View(l.backend, findMissing, func() {
missing = nil
})
return missing, err
}
// Use the provided transaction.
err := findMissing(tx)
return missing, err
}
// CreateLinkNodes creates multiple link nodes. If tx is nil, a new write
// transaction will be created. Otherwise, the provided transaction is used,
// allowing this to be part of a larger batch operation.
func (l *LinkNodeDB) CreateLinkNodes(tx kvdb.RwTx,
linkNodes []*LinkNode) error {
createNodes := func(writeTx kvdb.RwTx) error {
nodeMetaBucket, err := writeTx.CreateTopLevelBucket(
nodeInfoBucket,
)
if err != nil {
return err
}
for _, linkNode := range linkNodes {
err := putLinkNode(nodeMetaBucket, linkNode)
if err != nil {
pubKey := linkNode.IdentityPub.
SerializeCompressed()
return fmt.Errorf("unable to create link "+
"node for peer %x: %w", pubKey, err)
}
}
return nil
}
// If no transaction provided, create our own.
if tx == nil {
return kvdb.Update(l.backend, createNodes, func() {})
}
// Use the provided transaction.
return createNodes(tx)
}
// DeleteLinkNode removes the link node with the given identity from the
// database.
func (l *LinkNodeDB) DeleteLinkNode(identity *btcec.PublicKey) error {