Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Peer backup #8490

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,10 @@ type DatabaseInstances struct {
// configuration.
TowerServerDB watchtower.DB

// PeerStorageDB is the database that stores the data that peers shares
// with us for backup.
PeerStorageDB kvdb.Backend

// WalletDB is the configuration for loading the wallet database using
// the btcwallet's loader.
WalletDB btcwallet.LoaderOption
Expand Down Expand Up @@ -941,6 +945,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
DecayedLogDB: databaseBackends.DecayedLogDB,
WalletDB: databaseBackends.WalletDB,
NativeSQLStore: databaseBackends.NativeSQLStore,
PeerStorageDB: databaseBackends.PeerStorageDB,
}
cleanUp := func() {
// We can just close the returned close functions directly. Even
Expand Down
6 changes: 6 additions & 0 deletions docs/release-notes/release-notes-0.18.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,12 @@
[spec change](https://github.com/lightning/bolts/pull/1092/commits/e0ee59f3c92b7c98be8dfc47b7db358b45baf9de)
that meant we shouldn't require it.

* [Implement feature bits, message and functionality to backup peer data in the
peer backup proposal](https://github.com/lightningnetwork/lnd/pull/8490)
This PR implements the feature bits, messages and functionality to backup
peer data referenced in the peer backup proposal here:
https://github.com/lightning/bolts/pull/1110

## Testing

* Added fuzz tests for [onion
Expand Down
4 changes: 4 additions & 0 deletions feature/default_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,8 @@ var defaultSetDesc = setDesc{
SetInit: {}, // I
SetNodeAnn: {}, // N
},
lnwire.ProvideStorageOptional: {
SetInit: {}, // I
SetNodeAnn: {}, // N
},
Chinwendu20 marked this conversation as resolved.
Show resolved Hide resolved
}
7 changes: 7 additions & 0 deletions feature/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ type Config struct {
// CustomFeatures is a set of custom features to advertise in each
// set.
CustomFeatures map[Set][]lnwire.FeatureBit

// NoPeerStorage unsets any bits signalling support for peer storage.
NoPeerStorage bool
}

// Manager is responsible for generating feature vectors for different requested
Expand Down Expand Up @@ -188,6 +191,10 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
raw.Unset(lnwire.RouteBlindingOptional)
raw.Unset(lnwire.RouteBlindingRequired)
}
if cfg.NoPeerStorage {
raw.Unset(lnwire.ProvideStorageOptional)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also unset the ProvideStorageRequired

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not add that in the default config yet. Just thought we should only add the optional flag for now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at all the code immediately above here though... when the config variable that disables PeerStorage is set, it should Unset both feature bits. Unset is an idempotent operation and so can be performed even when the bit is not already set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsetting the required bit is something that would eventually done when it is part of the default config though but I can still added it here since it makes no difference

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unaddressed 🙏

but I can still added it here since it makes no difference

Important to note here that we want code to be maintainable in the long term. If we ever change that default to be Required - we dont want to have to remember to come and change things here. A user setting the NoPeerStorage option, should always work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially did not include it because I do not think maybe it makes sense to unset what was not initially set. If in the future the required bit is added to the default set. Then I think it would make sense to add the unsetting code here as well. Flows naturally to me and does not make this code unmaintainable in any way IMO.

}

for _, custom := range cfg.CustomFeatures[set] {
if custom > set.Maximum() {
return nil, fmt.Errorf("feature bit: %v "+
Expand Down
70 changes: 64 additions & 6 deletions lncfg/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ const (
TowerClientDBName = "wtclient.db"
TowerServerDBName = "watchtower.db"
WalletDBName = "wallet.db"
PeerStorageDBName = "peer_storage.db"

SqliteChannelDBName = "channel.sqlite"
SqliteChainDBName = "chain.sqlite"
SqliteNeutrinoDBName = "neutrino.sqlite"
SqliteTowerDBName = "watchtower.sqlite"
SqliteNativeDBName = "lnd.sqlite"
SqliteChannelDBName = "channel.sqlite"
SqliteChainDBName = "chain.sqlite"
SqliteNeutrinoDBName = "neutrino.sqlite"
SqliteTowerDBName = "watchtower.sqlite"
SqliteNativeDBName = "lnd.sqlite"
SqlitePeerStorageDBName = "peerStorage.sqlite"

BoltBackend = "bolt"
EtcdBackend = "etcd"
Expand Down Expand Up @@ -67,6 +69,10 @@ const (

// NSNeutrinoDB is the namespace name that we use for the neutrino DB.
NSNeutrinoDB = "neutrinodb"

// NSPeerStorageDB is the namespace name that we use for peer storage
// DB.
NSPeerStorageDB = "peerstoragedb"
)

// DB holds database configuration for LND.
Expand Down Expand Up @@ -227,6 +233,10 @@ type DatabaseBackends struct {
// server data. This might be nil if the watchtower server is disabled.
TowerServerDB kvdb.Backend

// PeerStorageDB points to the database backend that stores the backup
// data that peers share with us.
PeerStorageDB kvdb.Backend

// WalletDB is an option that instructs the wallet loader where to load
// the underlying wallet database from.
WalletDB btcwallet.LoaderOption
Expand Down Expand Up @@ -349,6 +359,16 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
}
closeFuncs[NSTowerServerDB] = etcdTowerServerBackend.Close

etcdPeerStorageBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.CloneWithSubNamespace(NSPeerStorageDB),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd "+
"peer storage DB: %w", err)
}
closeFuncs[NSPeerStorageDB] = etcdPeerStorageBackend.Close

etcdWalletBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.
Expand All @@ -357,7 +377,7 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
)
if err != nil {
return nil, fmt.Errorf("error opening etcd macaroon "+
"DB: %v", err)
"DB: %w", err)
}
closeFuncs[NSWalletDB] = etcdWalletBackend.Close

Expand All @@ -371,6 +391,7 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
DecayedLogDB: etcdDecayedLogBackend,
TowerClientDB: etcdTowerClientBackend,
TowerServerDB: etcdTowerServerBackend,
PeerStorageDB: etcdPeerStorageBackend,
// The wallet loader will attempt to use/create the
// wallet in the replicated remote DB if we're running
// in a clustered environment. This will ensure that all
Expand Down Expand Up @@ -439,6 +460,16 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
}
closeFuncs[NSTowerServerDB] = postgresTowerServerBackend.Close

postgresPeerStorageBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSPeerStorageDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres "+
"peer storage server DB: %w", err)
}
closeFuncs[NSPeerStorageDB] = postgresPeerStorageBackend.Close

postgresWalletBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSWalletDB,
Expand Down Expand Up @@ -482,6 +513,7 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
DecayedLogDB: postgresDecayedLogBackend,
TowerClientDB: postgresTowerClientBackend,
TowerServerDB: postgresTowerServerBackend,
PeerStorageDB: postgresPeerStorageBackend,
// The wallet loader will attempt to use/create the
// wallet in the replicated remote DB if we're running
// in a clustered environment. This will ensure that all
Expand Down Expand Up @@ -561,6 +593,16 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
}
closeFuncs[NSTowerServerDB] = sqliteTowerServerBackend.Close

sqlitePeerStorageBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
SqlitePeerStorageDBName, NSPeerStorageDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite peer "+
"storage server DB: %w", err)
}
closeFuncs[NSPeerStorageDB] = sqlitePeerStorageBackend.Close

sqliteWalletBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
SqliteChainDBName, NSWalletDB,
Expand Down Expand Up @@ -605,6 +647,7 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
DecayedLogDB: sqliteDecayedLogBackend,
TowerClientDB: sqliteTowerClientBackend,
TowerServerDB: sqliteTowerServerBackend,
PeerStorageDB: sqlitePeerStorageBackend,
// The wallet loader will attempt to use/create the
// wallet in the replicated remote DB if we're running
// in a clustered environment. This will ensure that all
Expand Down Expand Up @@ -645,6 +688,20 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
}
closeFuncs[NSMacaroonDB] = macaroonBackend.Close

peerStorageBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: chanDBPath,
ProofOfKeags marked this conversation as resolved.
Show resolved Hide resolved
DBFileName: PeerStorageDBName,
DBTimeout: db.Bolt.DBTimeout,
NoFreelistSync: db.Bolt.NoFreelistSync,
AutoCompact: db.Bolt.AutoCompact,
AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
})
if err != nil {
return nil, fmt.Errorf("error opening peer storage DB: "+
"%w", err)
}
closeFuncs[NSPeerStorageDB] = peerStorageBackend.Close

decayedLogBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: chanDBPath,
DBFileName: DecayedLogDbName,
Expand Down Expand Up @@ -710,6 +767,7 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
DecayedLogDB: decayedLogBackend,
TowerClientDB: towerClientBackend,
TowerServerDB: towerServerBackend,
PeerStorageDB: peerStorageBackend,
// When "running locally", LND will use the bbolt wallet.db to
// store the wallet located in the chain data dir, parametrized
// by the active network. The wallet loader has its own cleanup
Expand Down
10 changes: 10 additions & 0 deletions lncfg/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ type ProtocolOptions struct {

// NoRouteBlindingOption disables forwarding of payments in blinded routes.
NoRouteBlindingOption bool `long:"no-route-blinding" description:"do not forward payments that are a part of a blinded route"`

// OptionPeerStorage, when set to true, enables storage of backup data
// shared by peers.
OptionPeerStorage bool `long:"peer-storage" description:"store peer's backup data'"`
}

// Wumbo returns true if lnd should permit the creation and acceptance of wumbo
Expand Down Expand Up @@ -105,3 +109,9 @@ func (l *ProtocolOptions) NoTimestampsQuery() bool {
func (l *ProtocolOptions) NoRouteBlinding() bool {
return l.NoRouteBlindingOption
}

// PeerStorage returns true if we want to enable storage of backup data
// shared by peers.
func (l *ProtocolOptions) PeerStorage() bool {
return l.OptionPeerStorage
}
10 changes: 10 additions & 0 deletions lncfg/protocol_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ type ProtocolOptions struct {

// NoRouteBlindingOption disables forwarding of payments in blinded routes.
NoRouteBlindingOption bool `long:"no-route-blinding" description:"do not forward payments that are a part of a blinded route"`

// OptionPeerStorage, when set to true, enables storage of backup data
// shared by peers.
OptionPeerStorage bool `long:"peer-storage" description:"store peer's backup data'"`
}

// Wumbo returns true if lnd should permit the creation and acceptance of wumbo
Expand Down Expand Up @@ -100,3 +104,9 @@ func (l *ProtocolOptions) NoAnySegwit() bool {
func (l *ProtocolOptions) NoRouteBlinding() bool {
return l.NoRouteBlindingOption
}

// PeerStorage returns true if we want to enable storage of backup data
// shared by peers.
func (l *ProtocolOptions) PeerStorage() bool {
return l.OptionPeerStorage
}
12 changes: 12 additions & 0 deletions lnwire/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ const (
// sender-generated preimages according to BOLT XX.
AMPOptional FeatureBit = 31

// ProvideStorageRequired is a required feature bit that
// indicates that a node offers storing arbitrary data for their peers.
// See: https://github.com/lightning/bolts/pull/1110/
ProvideStorageRequired FeatureBit = 42

// ProvideStorageOptional is an optional feature bit that
// indicates that a node offers storing arbitrary data for their peers.
// See: https://github.com/lightning/bolts/pull/1110/
ProvideStorageOptional FeatureBit = 43

// ExplicitChannelTypeRequired is a required bit that denotes that a
// connection established with this node is to use explicit channel
// commitment types for negotiation instead of the existing implicit
Expand Down Expand Up @@ -331,6 +341,8 @@ var Features = map[FeatureBit]string{
SimpleTaprootChannelsOptionalFinal: "simple-taproot-chans",
SimpleTaprootChannelsRequiredStaging: "simple-taproot-chans-x",
SimpleTaprootChannelsOptionalStaging: "simple-taproot-chans-x",
ProvideStorageOptional: "provide-storage",
ProvideStorageRequired: "provide-storage",
}

// RawFeatureVector represents a set of feature bits as defined in BOLT-09. A
Expand Down
22 changes: 22 additions & 0 deletions lnwire/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -900,3 +900,25 @@ func FuzzClosingComplete(f *testing.F) {
harness(t, data)
})
}

func FuzzPeerStorage(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
// Prefix with PeerStorage.
data = prefixWithMsgType(data, MsgPeerStorage)

// Pass the message into our general fuzz harness for wire
// messages!
harness(t, data)
})
}

func FuzzPeerStorageRetrieval(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
// Prefix with PeerStorage.
data = prefixWithMsgType(data, MsgPeerStorageRetrieval)

// Pass the message into our general fuzz harness for wire
// messages!
harness(t, data)
})
}
6 changes: 6 additions & 0 deletions lnwire/lnwire.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ func WriteElement(w *bytes.Buffer, element interface{}) error {
case ExtraOpaqueData:
return e.Encode(w)

case PeerStorageBlob:
return e.Encode(w)

default:
return fmt.Errorf("unknown type in WriteElement: %T", e)
}
Expand Down Expand Up @@ -939,6 +942,9 @@ func ReadElement(r io.Reader, element interface{}) error {
case *ExtraOpaqueData:
return e.Decode(r)

case *PeerStorageBlob:
return e.Decode(r)

default:
return fmt.Errorf("unknown type in ReadElement: %T", e)
}
Expand Down
12 changes: 12 additions & 0 deletions lnwire/lnwire_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,18 @@ func TestLightningWireProtocol(t *testing.T) {
return mainScenario(&m)
},
},
{
msgType: MsgPeerStorage,
scenario: func(m PeerStorage) bool {
return mainScenario(&m)
},
},
{
msgType: MsgPeerStorageRetrieval,
scenario: func(m PeerStorageRetrieval) bool {
return mainScenario(&m)
},
},
}
for _, test := range tests {
var config *quick.Config
Expand Down
10 changes: 10 additions & 0 deletions lnwire/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type MessageType uint16
// Lightning protocol.
const (
MsgWarning MessageType = 1
MsgPeerStorage = 7
MsgPeerStorageRetrieval = 9
MsgInit = 16
MsgError = 17
MsgPing = 18
Expand Down Expand Up @@ -152,6 +154,10 @@ func (t MessageType) String() string {
return "ClosingComplete"
case MsgClosingSig:
return "ClosingSig"
case MsgPeerStorage:
return "PeerStorage"
case MsgPeerStorageRetrieval:
return "PeerStorageRetrieval"
default:
return "<unknown>"
}
Expand Down Expand Up @@ -279,6 +285,10 @@ func makeEmptyMessage(msgType MessageType) (Message, error) {
msg = &ClosingComplete{}
case MsgClosingSig:
msg = &ClosingSig{}
case MsgPeerStorage:
msg = &PeerStorage{}
case MsgPeerStorageRetrieval:
msg = &PeerStorageRetrieval{}
default:
// If the message is not within our custom range and has not
// specifically been overridden, return an unknown message.
Expand Down
Loading
Loading