staticaddr: static address manager

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

@ -0,0 +1,188 @@
package staticaddr
import (
"context"
"sync"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/staticaddr/script"
"github.com/lightninglabs/loop/swap"
staticaddressrpc "github.com/lightninglabs/loop/swapserverrpc"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
)
// ManagerConfig holds the configuration for the address manager.
type ManagerConfig struct {
// AddressClient is the client that communicates with the loop server
// to manage static addresses.
AddressClient staticaddressrpc.StaticAddressServerClient
// SwapClient provides loop rpc functionality.
SwapClient *loop.Client
// Store is the database store that is used to store static address
// related records.
Store AddressStore
// WalletKit is the wallet client that is used to derive new keys from
// lnd's wallet.
WalletKit lndclient.WalletKitClient
// ChainParams is the chain configuration(mainnet, testnet...) this
// manager uses.
ChainParams *chaincfg.Params
}
// Manager manages the address state machines.
type Manager struct {
cfg *ManagerConfig
initChan chan struct{}
sync.Mutex
}
// NewAddressManager creates a new address manager.
func NewAddressManager(cfg *ManagerConfig) *Manager {
return &Manager{
cfg: cfg,
initChan: make(chan struct{}),
}
}
// Run runs the address manager.
func (m *Manager) Run(ctx context.Context) error {
log.Debugf("Starting address manager.")
defer log.Debugf("Address manager stopped.")
// Communicate to the caller that the address manager has completed its
// initialization.
close(m.initChan)
<-ctx.Done()
return nil
}
// NewAddress starts a new address creation flow.
func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
error) {
// If there's already a static address in the database, we can return
// it.
m.Lock()
addresses, err := m.cfg.Store.GetAllStaticAddresses(ctx)
if err != nil {
m.Unlock()
return nil, err
}
if len(addresses) > 0 {
clientPubKey := addresses[0].ClientPubkey
serverPubKey := addresses[0].ServerPubkey
expiry := int64(addresses[0].Expiry)
m.Unlock()
return m.getTaprootAddress(clientPubKey, serverPubKey, expiry)
}
m.Unlock()
// We are fetching a new L402 token from the server. There is one static
// address per L402 token allowed.
err = m.cfg.SwapClient.Server.FetchL402(ctx)
if err != nil {
return nil, err
}
clientPubKey, err := m.cfg.WalletKit.DeriveNextKey(
ctx, swap.StaticAddressKeyFamily,
)
if err != nil {
return nil, err
}
// Send our clientPubKey to the server and wait for the server to
// respond with he serverPubKey and the static address CSV expiry.
protocolVersion := CurrentRPCProtocolVersion()
resp, err := m.cfg.AddressClient.ServerNewAddress(
ctx, &staticaddressrpc.ServerNewAddressRequest{
ProtocolVersion: protocolVersion,
ClientKey: clientPubKey.PubKey.SerializeCompressed(), //nolint:lll
},
)
if err != nil {
return nil, err
}
serverParams := resp.GetParams()
serverPubKey, err := btcec.ParsePubKey(serverParams.ServerKey)
if err != nil {
return nil, err
}
staticAddress, err := script.NewStaticAddress(
input.MuSig2Version100RC2, int64(serverParams.Expiry),
clientPubKey.PubKey, serverPubKey,
)
if err != nil {
return nil, err
}
pkScript, err := staticAddress.StaticAddressScript()
if err != nil {
return nil, err
}
// Create the static address from the parameters the server provided and
// store all parameters in the database.
addrParams := &AddressParameters{
ClientPubkey: clientPubKey.PubKey,
ServerPubkey: serverPubKey,
PkScript: pkScript,
Expiry: serverParams.Expiry,
KeyLocator: keychain.KeyLocator{
Family: clientPubKey.Family,
Index: clientPubKey.Index,
},
ProtocolVersion: AddressProtocolVersion(protocolVersion),
}
err = m.cfg.Store.CreateStaticAddress(ctx, addrParams)
if err != nil {
return nil, err
}
return m.getTaprootAddress(
clientPubKey.PubKey, serverPubKey, int64(serverParams.Expiry),
)
}
func (m *Manager) getTaprootAddress(clientPubkey,
serverPubkey *btcec.PublicKey, expiry int64) (*btcutil.AddressTaproot,
error) {
staticAddress, err := script.NewStaticAddress(
input.MuSig2Version100RC2, expiry, clientPubkey, serverPubkey,
)
if err != nil {
return nil, err
}
return btcutil.NewAddressTaproot(
schnorr.SerializePubKey(staticAddress.TaprootKey),
m.cfg.ChainParams,
)
}
// WaitInitComplete waits until the address manager has completed its setup.
func (m *Manager) WaitInitComplete() {
defer log.Debugf("Address manager initiation complete.")
<-m.initChan
}
Loading…
Cancel
Save