loopdb: static address store

pull/642/head
Slyghtning 6 months ago
parent bb498f42d0
commit c5756001ec
No known key found for this signature in database
GPG Key ID: F82D456EA023C9BF

@ -295,6 +295,12 @@ func (b *BaseDB) FixFaultyTimestamps(ctx context.Context) error {
return tx.Commit()
}
// GetNetwork returns the network(mainnet, testnet...) that the database is
// running on.
func (db *BaseDB) GetNetwork() *chaincfg.Params {
return db.network
}
// TxOptions represents a set of options one can use to control what type of
// database transaction is created. Transaction can whether be read or write.
type TxOptions interface {

@ -0,0 +1,58 @@
package staticaddr
import (
"context"
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/keychain"
)
var (
ErrAddressAlreadyExists = fmt.Errorf("address already exists")
ErrAddressNotFound = fmt.Errorf("address not found")
)
// AddressStore is the database interface that is used to store and retrieve
// static addresses.
type AddressStore interface {
// CreateStaticAddress inserts a new static address with its parameters
// into the store.
CreateStaticAddress(ctx context.Context,
addrParams *AddressParameters) error
// GetStaticAddress fetches static address parameters for a given
// address ID.
GetStaticAddress(ctx context.Context,
pkScript []byte) (*AddressParameters, error)
// GetAllStaticAddresses retrieves all static addresses from the store.
GetAllStaticAddresses(ctx context.Context) (
[]*AddressParameters, error)
}
// AddressParameters holds all the necessary information for the 2-of-2 multisig
// address.
type AddressParameters struct {
// ClientPubkey is the client's pubkey for the static address. It is
// used for the 2-of-2 funding output as well as for the client's
// timeout path.
ClientPubkey *btcec.PublicKey
// ClientPubkey is the client's pubkey for the static address. It is
// used for the 2-of-2 funding output.
ServerPubkey *btcec.PublicKey
// Expiry is the CSV timout value at which the client can claim the
// static address's timout path.
Expiry uint32
// PkScript is the unique static address's output script.
PkScript []byte
// KeyLocator is the locator of the client's key.
KeyLocator keychain.KeyLocator
// ProtocolVersion is the protocol version of the static address.
ProtocolVersion AddressProtocolVersion
}

@ -0,0 +1,146 @@
package staticaddr
import (
"context"
"errors"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/jackc/pgx/v4"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/loopdb/sqlc"
"github.com/lightningnetwork/lnd/keychain"
)
// SqlStore is the backing store for static addresses.
type SqlStore struct {
baseDB *loopdb.BaseDB
}
// NewSqlStore constructs a new SQLStore from a BaseDB. The BaseDB is agnostic
// to the underlying driver which can be postgres or sqlite.
func NewSqlStore(db *loopdb.BaseDB) *SqlStore {
return &SqlStore{
baseDB: db,
}
}
// ExecTx is a wrapper for txBody to abstract the creation and commit of a db
// transaction. The db transaction is embedded in a `*sqlc.Queries` that txBody
// needs to use when executing each one of the queries that need to be applied
// atomically.
func (s *SqlStore) ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
txBody func(queries *sqlc.Queries) error) error {
// Create the db transaction.
tx, err := s.baseDB.BeginTx(ctx, txOptions)
if err != nil {
return err
}
// Rollback is safe to call even if the tx is already closed, so if the
// tx commits successfully, this is a no-op.
defer func() {
err := tx.Rollback()
switch {
// If the tx was already closed (it was successfully executed)
// we do not need to log that error.
case errors.Is(err, pgx.ErrTxClosed):
return
// If this is an unexpected error, log it.
case err != nil:
log.Errorf("unable to rollback db tx: %v", err)
}
}()
if err := txBody(s.baseDB.Queries.WithTx(tx)); err != nil {
return err
}
// Commit transaction.
return tx.Commit()
}
// CreateStaticAddress creates a static address record in the database.
func (s *SqlStore) CreateStaticAddress(ctx context.Context,
addrParams *AddressParameters) error {
createArgs := sqlc.CreateStaticAddressParams{
ClientPubkey: addrParams.ClientPubkey.SerializeCompressed(),
ServerPubkey: addrParams.ServerPubkey.SerializeCompressed(),
Expiry: int32(addrParams.Expiry),
ClientKeyFamily: int32(addrParams.KeyLocator.Family),
ClientKeyIndex: int32(addrParams.KeyLocator.Index),
Pkscript: addrParams.PkScript,
ProtocolVersion: int32(addrParams.ProtocolVersion),
}
return s.baseDB.Queries.CreateStaticAddress(ctx, createArgs)
}
// GetStaticAddress retrieves static address parameters for a given pkScript.
func (s *SqlStore) GetStaticAddress(ctx context.Context,
pkScript []byte) (*AddressParameters, error) {
staticAddress, err := s.baseDB.Queries.GetStaticAddress(ctx, pkScript)
if err != nil {
return nil, err
}
return s.toAddressParameters(staticAddress)
}
// GetAllStaticAddresses returns all address known to the server.
func (s *SqlStore) GetAllStaticAddresses(ctx context.Context) (
[]*AddressParameters, error) {
staticAddresses, err := s.baseDB.Queries.AllStaticAddresses(ctx)
if err != nil {
return nil, err
}
var result []*AddressParameters
for _, address := range staticAddresses {
res, err := s.toAddressParameters(address)
if err != nil {
return nil, err
}
result = append(result, res)
}
return result, nil
}
// Close closes the database connection.
func (s *SqlStore) Close() {
s.baseDB.DB.Close()
}
// toAddressParameters transforms a database representation of a static address
// to an AddressParameters struct.
func (s *SqlStore) toAddressParameters(row sqlc.StaticAddress) (
*AddressParameters, error) {
clientPubkey, err := btcec.ParsePubKey(row.ClientPubkey)
if err != nil {
return nil, err
}
serverPubkey, err := btcec.ParsePubKey(row.ServerPubkey)
if err != nil {
return nil, err
}
return &AddressParameters{
ClientPubkey: clientPubkey,
ServerPubkey: serverPubkey,
PkScript: row.Pkscript,
Expiry: uint32(row.Expiry),
KeyLocator: keychain.KeyLocator{
Family: keychain.KeyFamily(row.ClientKeyFamily),
Index: uint32(row.ClientKeyIndex),
},
ProtocolVersion: AddressProtocolVersion(row.ProtocolVersion),
}, nil
}
Loading…
Cancel
Save