lightning-terminal/rules/mock.go
Elle Mouton f8a36010e2
rules: add on-chain budget
This adds an on-chain budget that handles requests and responses for the
following endpoints:

* OpenChannelSync
* BatchOpenChannel

The budget rule checks that the onchain fee rate is not violated and
that pending and confirmed amounts are handled correctly.

An edge case can occur when lit crashes or shuts down after the budget
rule has forwarded a request but didn't receive a response yet. The
pending budget is not removed in case the request didn't go through and
is not accounted towards the spent budget in case the request did go
through. To be able to handle these cases in the future we add a unique
identifier to the request, that can be checked by calling LND's channel
bookkeeping APIs. Not all of them expose the identifier yet, which is
why pending actions cannot be deleted yet. This leads to underspending
of the budget and can be fixed by user intervention by creating a new
session. The memo prefix is removed when reading forwarding the
bookkeeping requests for privacy reasons.
2024-07-02 18:21:41 +02:00

107 lines
2.2 KiB
Go

package rules
import (
"context"
"sync"
"github.com/lightninglabs/lightning-terminal/firewalldb"
)
type mockKVStoresTX struct {
firewalldb.KVStoreTx
global firewalldb.KVStore
local firewalldb.KVStore
globalTemp firewalldb.KVStore
localTemp firewalldb.KVStore
}
func newMockKVStoresTx() *mockKVStoresTX {
return &mockKVStoresTX{
global: newInMemKVStore(),
local: newInMemKVStore(),
globalTemp: newInMemKVStore(),
localTemp: newInMemKVStore(),
}
}
func (m *mockKVStoresTX) Global() firewalldb.KVStore {
return m.global
}
func (m *mockKVStoresTX) Local() firewalldb.KVStore {
return m.local
}
func (m *mockKVStoresTX) GlobalTemp() firewalldb.KVStore {
return m.globalTemp
}
func (m *mockKVStoresTX) LocalTemp() firewalldb.KVStore {
return m.localTemp
}
var _ firewalldb.KVStoreTx = (*mockKVStoresTX)(nil)
type mockKVStores struct {
tx *mockKVStoresTX
}
func (m *mockKVStores) Update(f func(tx firewalldb.KVStoreTx) error) error {
return f(m.tx)
}
func (m *mockKVStores) View(f func(tx firewalldb.KVStoreTx) error) error {
return f(m.tx)
}
var _ firewalldb.KVStores = (*mockKVStores)(nil)
// memKVStore is an in-memory key value store.
type memKVStore struct {
store map[string][]byte
sync.RWMutex
}
// newInMemKVStore constructs a new memKVStore.
func newInMemKVStore() *memKVStore {
return &memKVStore{
store: make(map[string][]byte),
}
}
// Get fetches the value for the given key from the kv store if it exists.
func (m *memKVStore) Get(_ context.Context, key string) ([]byte, error) {
m.RLock()
defer m.RUnlock()
v, ok := m.store[key]
if !ok {
// We don't error if the key doesn't exist.
return nil, nil
}
return v, nil
}
// Set sets the value for the given key in the kv store.
func (m *memKVStore) Set(_ context.Context, key string, value []byte) error {
m.Lock()
defer m.Unlock()
m.store[key] = value
return nil
}
// Del deletes the value for the given key from the kv store if it exists.
func (m *memKVStore) Del(_ context.Context, key string) error {
m.Lock()
defer m.Unlock()
delete(m.store, key)
return nil
}
// A compile-time check to assert that memKVStore implements the KVStore
// interface.
var _ firewalldb.KVStore = (*memKVStore)(nil)