diff --git a/liquidity/autoloop_testcontext_test.go b/liquidity/autoloop_testcontext_test.go index a0c608af9..598acef3d 100644 --- a/liquidity/autoloop_testcontext_test.go +++ b/liquidity/autoloop_testcontext_test.go @@ -10,6 +10,7 @@ import ( "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop" "github.com/lightninglabs/loop/loopdb" + "github.com/lightninglabs/loop/loopdb/sqlc" "github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/test" "github.com/lightningnetwork/lnd/clock" @@ -188,10 +189,14 @@ func newAutoloopTestCtx(t *testing.T, parameters Parameters, MinimumConfirmations: loop.DefaultSweepConfTarget, Lnd: &testCtx.lnd.LndServices, Clock: testCtx.testClock, - PutLiquidityParams: func(_ context.Context, _ []byte) error { + PutLiquidityParams: func(_ context.Context, _ string, + _ []byte) error { + return nil }, - FetchLiquidityParams: func(context.Context) ([]byte, error) { + FetchLiquidityParams: func(context.Context) ( + []sqlc.LiquidityParam, error) { + return nil, nil }, } diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index fbd842b1f..514aa78be 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -46,6 +46,7 @@ import ( "github.com/lightninglabs/loop" "github.com/lightninglabs/loop/labels" "github.com/lightninglabs/loop/loopdb" + "github.com/lightninglabs/loop/loopdb/sqlc" clientrpc "github.com/lightninglabs/loop/looprpc" "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/clock" @@ -229,13 +230,15 @@ type Config struct { // // NOTE: the params are encoded using `proto.Marshal` over an RPC // request. - PutLiquidityParams func(ctx context.Context, params []byte) error + PutLiquidityParams func(ctx context.Context, assetId string, + params []byte) error // FetchLiquidityParams reads the serialized `Parameters` from db. // // NOTE: the params are decoded using `proto.Unmarshal` over a // serialized RPC request. - FetchLiquidityParams func(ctx context.Context) ([]byte, error) + FetchLiquidityParams func(ctx context.Context) ([]sqlc.LiquidityParam, + error) } // Manager contains a set of desired liquidity rules for our channel @@ -392,7 +395,8 @@ func (m *Manager) saveParams(ctx context.Context, req proto.Message) error { } // Save the params on disk. - if err := m.cfg.PutLiquidityParams(ctx, paramsBytes); err != nil { + err = m.cfg.PutLiquidityParams(ctx, swap.DefaultBtcAssetID, paramsBytes) + if err != nil { return fmt.Errorf("failed to save params: %v", err) } @@ -404,19 +408,24 @@ func (m *Manager) saveParams(ctx context.Context, req proto.Message) error { func (m *Manager) loadParams(ctx context.Context) ( *clientrpc.LiquidityParameters, error) { - paramsBytes, err := m.cfg.FetchLiquidityParams(ctx) + params, err := m.cfg.FetchLiquidityParams(ctx) if err != nil { return nil, fmt.Errorf("failed to read params: %v", err) } // Return early if there's nothing saved. - if paramsBytes == nil { + if params == nil { return nil, nil } + if len(params) != 1 { + return nil, fmt.Errorf("expected 1 param, got %v", len(params)) + } + // Unmarshal the params. req := &clientrpc.LiquidityParameters{} - err = proto.Unmarshal(paramsBytes, req) + + err = proto.Unmarshal(params[0].Params, req) if err != nil { return nil, fmt.Errorf("failed to unmarshal params: %v", err) } diff --git a/liquidity/liquidity_test.go b/liquidity/liquidity_test.go index f3fae1e65..806f40239 100644 --- a/liquidity/liquidity_test.go +++ b/liquidity/liquidity_test.go @@ -10,6 +10,7 @@ import ( "github.com/lightninglabs/loop" "github.com/lightninglabs/loop/labels" "github.com/lightninglabs/loop/loopdb" + "github.com/lightninglabs/loop/loopdb/sqlc" clientrpc "github.com/lightninglabs/loop/looprpc" "github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/test" @@ -268,10 +269,12 @@ func TestPersistParams(t *testing.T) { ctxb := context.Background() - var paramsBytes []byte + var paramsBytes []sqlc.LiquidityParam // Mock the read method to return empty data. - manager.cfg.FetchLiquidityParams = func(context.Context) ([]byte, error) { + manager.cfg.FetchLiquidityParams = func(context.Context) ( + []sqlc.LiquidityParam, error) { + return paramsBytes, nil } @@ -282,9 +285,14 @@ func TestPersistParams(t *testing.T) { // Mock the write method to return no error. manager.cfg.PutLiquidityParams = func(ctx context.Context, - data []byte) error { + assetId string, data []byte) error { - paramsBytes = data + paramsBytes = []sqlc.LiquidityParam{ + { + AssetID: swap.DefaultBtcAssetID, + Params: data, + }, + } return nil } diff --git a/loopdb/interface.go b/loopdb/interface.go index 9684035bc..60f3babb6 100644 --- a/loopdb/interface.go +++ b/loopdb/interface.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/lightninglabs/loop/loopdb/sqlc" "github.com/lightningnetwork/lnd/lntypes" ) @@ -61,14 +62,15 @@ type SwapStore interface { // // NOTE: it's the caller's responsibility to encode the param. Atm, // it's encoding using the proto package's `Marshal` method. - PutLiquidityParams(ctx context.Context, params []byte) error + PutLiquidityParams(ctx context.Context, assetId string, + params []byte) error // FetchLiquidityParams reads the serialized `manager.Parameters` bytes // from the bucket. // // NOTE: it's the caller's responsibility to decode the param. Atm, // it's decoding using the proto package's `Unmarshal` method. - FetchLiquidityParams(ctx context.Context) ([]byte, error) + FetchLiquidityParams(ctx context.Context) ([]sqlc.LiquidityParam, error) // BatchUpdateLoopOutSwapCosts updates the swap costs for a batch of // loop out swaps. diff --git a/loopdb/migrate.go b/loopdb/migrate.go index 36d36944a..662c5d5d3 100644 --- a/loopdb/migrate.go +++ b/loopdb/migrate.go @@ -7,6 +7,7 @@ import ( "fmt" "sort" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" ) @@ -184,7 +185,9 @@ func (m *MigratorManager) migrateLiquidityParams(ctx context.Context) error { } // Put the liquidity parameters in the toStore. - err = m.toStore.PutLiquidityParams(ctx, params) + err = m.toStore.PutLiquidityParams( + ctx, swap.DefaultBtcAssetID, params[0].Params, + ) if err != nil { return err } @@ -295,11 +298,14 @@ func (m *MigratorManager) checkLiquidityParams(ctx context.Context) error { return err } - // Check that the liquidity parameters are the same. - if !bytes.Equal(fromParams, toParams) { - return NewMigrationError( - fmt.Errorf("from: %v, to: %v", fromParams, toParams), - ) + for i, fromParam := range fromParams { + // Check that the liquidity parameters are the same. + if !bytes.Equal(fromParam.Params, toParams[i].Params) { + return NewMigrationError( + fmt.Errorf("from: %v, to: %v", fromParams, + toParams), + ) + } } return nil diff --git a/loopdb/sql_store.go b/loopdb/sql_store.go index 4a41fea81..b00019af0 100644 --- a/loopdb/sql_store.go +++ b/loopdb/sql_store.go @@ -342,10 +342,15 @@ func (db *BaseDB) UpdateLoopIn(ctx context.Context, hash lntypes.Hash, // // NOTE: it's the caller's responsibility to encode the param. Atm, // it's encoding using the proto package's `Marshal` method. -func (db *BaseDB) PutLiquidityParams(ctx context.Context, +func (db *BaseDB) PutLiquidityParams(ctx context.Context, assetId string, params []byte) error { - err := db.Queries.UpsertLiquidityParams(ctx, params) + err := db.Queries.UpsertLiquidityParams( + ctx, sqlc.UpsertLiquidityParamsParams{ + AssetID: assetId, + Params: params, + }, + ) if err != nil { return err } @@ -358,10 +363,10 @@ func (db *BaseDB) PutLiquidityParams(ctx context.Context, // // NOTE: it's the caller's responsibility to decode the param. Atm, // it's decoding using the proto package's `Unmarshal` method. -func (db *BaseDB) FetchLiquidityParams(ctx context.Context) ([]byte, - error) { +func (db *BaseDB) FetchLiquidityParams(ctx context.Context) ( + []sqlc.LiquidityParam, error) { - var params []byte + var params []sqlc.LiquidityParam params, err := db.Queries.FetchLiquidityParams(ctx) if errors.Is(err, sql.ErrNoRows) { return params, nil diff --git a/loopdb/sql_test.go b/loopdb/sql_test.go index 225dc1756..2903d9e6b 100644 --- a/loopdb/sql_test.go +++ b/loopdb/sql_test.go @@ -317,16 +317,17 @@ func TestSqliteLiquidityParams(t *testing.T) { require.Empty(t, params, "expect empty bytes") require.Nil(t, params, "expected nil byte array") - params = []byte("test") + insertParams := []byte("test") // Test we can save the params. - err = store.PutLiquidityParams(ctxb, params) + err = store.PutLiquidityParams(ctxb, "test", insertParams) require.NoError(t, err, "failed to put params") // Now fetch the db again should return the above saved bytes. paramsRead, err := store.FetchLiquidityParams(ctxb) require.NoError(t, err, "failed to fetch params") - require.Equal(t, params, paramsRead, "unexpected return value") + require.Equal(t, insertParams, paramsRead[0].Params, + "unexpected return value") } // TestSqliteTypeConversion is a small test that checks that we can safely diff --git a/loopdb/sqlc/liquidity_params.sql.go b/loopdb/sqlc/liquidity_params.sql.go index ac36bbe6e..0c0463412 100644 --- a/loopdb/sqlc/liquidity_params.sql.go +++ b/loopdb/sqlc/liquidity_params.sql.go @@ -9,27 +9,48 @@ import ( "context" ) -const fetchLiquidityParams = `-- name: FetchLiquidityParams :one -SELECT params FROM liquidity_params WHERE id = 1 +const fetchLiquidityParams = `-- name: FetchLiquidityParams :many +SELECT asset_id, params FROM liquidity_params ` -func (q *Queries) FetchLiquidityParams(ctx context.Context) ([]byte, error) { - row := q.db.QueryRowContext(ctx, fetchLiquidityParams) - var params []byte - err := row.Scan(¶ms) - return params, err +func (q *Queries) FetchLiquidityParams(ctx context.Context) ([]LiquidityParam, error) { + rows, err := q.db.QueryContext(ctx, fetchLiquidityParams) + if err != nil { + return nil, err + } + defer rows.Close() + var items []LiquidityParam + for rows.Next() { + var i LiquidityParam + if err := rows.Scan(&i.AssetID, &i.Params); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil } const upsertLiquidityParams = `-- name: UpsertLiquidityParams :exec INSERT INTO liquidity_params ( - id, params + asset_id, params ) VALUES ( - 1, $1 -) ON CONFLICT (id) DO UPDATE SET - params = excluded.params + $1, $2 +) ON CONFLICT (asset_id) DO UPDATE SET + params = $2 ` -func (q *Queries) UpsertLiquidityParams(ctx context.Context, params []byte) error { - _, err := q.db.ExecContext(ctx, upsertLiquidityParams, params) +type UpsertLiquidityParamsParams struct { + AssetID string + Params []byte +} + +func (q *Queries) UpsertLiquidityParams(ctx context.Context, arg UpsertLiquidityParamsParams) error { + _, err := q.db.ExecContext(ctx, upsertLiquidityParams, arg.AssetID, arg.Params) return err } diff --git a/loopdb/sqlc/migrations/000013_liquidity_assets.down.sql b/loopdb/sqlc/migrations/000013_liquidity_assets.down.sql new file mode 100644 index 000000000..ae8424a26 --- /dev/null +++ b/loopdb/sqlc/migrations/000013_liquidity_assets.down.sql @@ -0,0 +1,13 @@ +ALTER TABLE liquidity_params RENAME TO liquidity_params_assets_backup; + +CREATE TABLE liquidity_params ( + id INTEGER PRIMARY KEY, + params BLOB +); + +INSERT INTO liquidity_params (id, params) +SELECT 1, params +FROM liquidity_params_assets_backup +WHERE asset_id = 'btc'; + +DROP TABLE liquidity_params_assets_backup; diff --git a/loopdb/sqlc/migrations/000013_liquidity_assets.up.sql b/loopdb/sqlc/migrations/000013_liquidity_assets.up.sql new file mode 100644 index 000000000..193a8c0fb --- /dev/null +++ b/loopdb/sqlc/migrations/000013_liquidity_assets.up.sql @@ -0,0 +1,15 @@ +-- Create a new table with the desired schema +CREATE TABLE new_liquidity_params ( + asset_id TEXT NOT NULL PRIMARY KEY, + params BLOB +); + +-- Copy data from the old table to the new table +INSERT INTO new_liquidity_params (asset_id, params) +SELECT 'btc', params FROM liquidity_params; + +-- Drop the old table +DROP TABLE liquidity_params; + +-- Rename the new table to the old table name +ALTER TABLE new_liquidity_params RENAME TO liquidity_params; \ No newline at end of file diff --git a/loopdb/sqlc/models.go b/loopdb/sqlc/models.go index 88aca93fb..487765864 100644 --- a/loopdb/sqlc/models.go +++ b/loopdb/sqlc/models.go @@ -60,8 +60,8 @@ type InstantoutUpdate struct { } type LiquidityParam struct { - ID int32 - Params []byte + AssetID string + Params []byte } type LoopinSwap struct { diff --git a/loopdb/sqlc/querier.go b/loopdb/sqlc/querier.go index a805196c6..52298b58c 100644 --- a/loopdb/sqlc/querier.go +++ b/loopdb/sqlc/querier.go @@ -17,7 +17,7 @@ type Querier interface { CreateReservation(ctx context.Context, arg CreateReservationParams) error CreateStaticAddress(ctx context.Context, arg CreateStaticAddressParams) error DropBatch(ctx context.Context, id int32) error - FetchLiquidityParams(ctx context.Context) ([]byte, error) + FetchLiquidityParams(ctx context.Context) ([]LiquidityParam, error) GetBatchSweeps(ctx context.Context, batchID int32) ([]Sweep, error) GetBatchSweptAmount(ctx context.Context, batchID int32) (int64, error) GetDeposit(ctx context.Context, depositID []byte) (Deposit, error) @@ -64,7 +64,7 @@ type Querier interface { UpdateLoopOutAssetOffchainPayments(ctx context.Context, arg UpdateLoopOutAssetOffchainPaymentsParams) error UpdateReservation(ctx context.Context, arg UpdateReservationParams) error UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error - UpsertLiquidityParams(ctx context.Context, params []byte) error + UpsertLiquidityParams(ctx context.Context, arg UpsertLiquidityParamsParams) error UpsertSweep(ctx context.Context, arg UpsertSweepParams) error } diff --git a/loopdb/sqlc/queries/liquidity_params.sql b/loopdb/sqlc/queries/liquidity_params.sql index a7da99a06..163c184cb 100644 --- a/loopdb/sqlc/queries/liquidity_params.sql +++ b/loopdb/sqlc/queries/liquidity_params.sql @@ -1,10 +1,10 @@ -- name: UpsertLiquidityParams :exec INSERT INTO liquidity_params ( - id, params + asset_id, params ) VALUES ( - 1, $1 -) ON CONFLICT (id) DO UPDATE SET - params = excluded.params; + $1, $2 +) ON CONFLICT (asset_id) DO UPDATE SET + params = $2; --- name: FetchLiquidityParams :one -SELECT params FROM liquidity_params WHERE id = 1; \ No newline at end of file +-- name: FetchLiquidityParams :many +SELECT * FROM liquidity_params; \ No newline at end of file diff --git a/loopdb/store.go b/loopdb/store.go index 60cce0fb1..6e888399d 100644 --- a/loopdb/store.go +++ b/loopdb/store.go @@ -14,6 +14,8 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/coreos/bbolt" + "github.com/lightninglabs/loop/loopdb/sqlc" + "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/lntypes" ) @@ -723,7 +725,7 @@ func (s *boltSwapStore) Close() error { // // NOTE: it's the caller's responsibility to encode the param. Atm, it's // encoding using the proto package's `Marshal` method. -func (s *boltSwapStore) PutLiquidityParams(ctx context.Context, +func (s *boltSwapStore) PutLiquidityParams(ctx context.Context, assetId string, params []byte) error { return s.db.Update(func(tx *bbolt.Tx) error { @@ -741,10 +743,10 @@ func (s *boltSwapStore) PutLiquidityParams(ctx context.Context, // // NOTE: it's the caller's responsibility to decode the param. Atm, it's // decoding using the proto package's `Unmarshal` method. -func (s *boltSwapStore) FetchLiquidityParams(ctx context.Context) ([]byte, - error) { +func (s *boltSwapStore) FetchLiquidityParams(ctx context.Context) ( + []sqlc.LiquidityParam, error) { - var params []byte + var params []sqlc.LiquidityParam err := s.db.View(func(tx *bbolt.Tx) error { // Read the root bucket. @@ -753,7 +755,13 @@ func (s *boltSwapStore) FetchLiquidityParams(ctx context.Context) ([]byte, return errors.New("liquidity bucket does not exist") } - params = rootBucket.Get(liquidtyParamsKey) + paramBytes := rootBucket.Get(liquidtyParamsKey) + if paramBytes != nil { + params = append(params, sqlc.LiquidityParam{ + AssetID: swap.DefaultBtcAssetID, + Params: paramBytes, + }) + } return nil }) diff --git a/loopdb/store_mock.go b/loopdb/store_mock.go index 0f3dcc66d..0d338b827 100644 --- a/loopdb/store_mock.go +++ b/loopdb/store_mock.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/lightninglabs/loop/loopdb/sqlc" "github.com/lightninglabs/loop/test" "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" @@ -242,7 +243,7 @@ func (s *StoreMock) UpdateLoopIn(ctx context.Context, hash lntypes.Hash, // bucket. // // NOTE: Part of the SwapStore interface. -func (s *StoreMock) PutLiquidityParams(ctx context.Context, +func (s *StoreMock) PutLiquidityParams(ctx context.Context, assetId string, params []byte) error { return nil @@ -252,7 +253,9 @@ func (s *StoreMock) PutLiquidityParams(ctx context.Context, // the bucket. // // NOTE: Part of the SwapStore interface. -func (s *StoreMock) FetchLiquidityParams(ctx context.Context) ([]byte, error) { +func (s *StoreMock) FetchLiquidityParams(ctx context.Context) ( + []sqlc.LiquidityParam, error) { + return nil, nil } diff --git a/loopdb/store_test.go b/loopdb/store_test.go index 2a5a61a19..0417d22a9 100644 --- a/loopdb/store_test.go +++ b/loopdb/store_test.go @@ -12,6 +12,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/coreos/bbolt" + "github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/test" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lntypes" @@ -486,14 +487,16 @@ func TestLiquidityParams(t *testing.T) { require.Empty(t, params, "expect empty bytes") require.Nil(t, params) - params = []byte("test") + insertParams := []byte("test") // Test we can save the params. - err = store.PutLiquidityParams(ctxb, params) + err = store.PutLiquidityParams( + ctxb, swap.DefaultBtcAssetID, insertParams, + ) require.NoError(t, err, "failed to put params") // Now fetch the db again should return the above saved bytes. paramsRead, err := store.FetchLiquidityParams(ctxb) require.NoError(t, err, "failed to fetch params") - require.Equal(t, params, paramsRead, "unexpected return value") + require.Equal(t, insertParams, paramsRead[0].Params, "unexpected return value") } diff --git a/loopdb/test_postgres.go b/loopdb/test_postgres.go index fafc9c127..f4eb85e6d 100644 --- a/loopdb/test_postgres.go +++ b/loopdb/test_postgres.go @@ -1,5 +1,5 @@ -//go:build test_db_postgres -// +build test_db_postgres +//go:build !test_db_postgres +// +build !test_db_postgres package loopdb diff --git a/loopdb/test_sqlite.go b/loopdb/test_sqlite.go index e60547c7a..cc9c52087 100644 --- a/loopdb/test_sqlite.go +++ b/loopdb/test_sqlite.go @@ -1,5 +1,5 @@ -//go:build !test_db_postgres -// +build !test_db_postgres +//go:build test_db_postgres +// +build test_db_postgres package loopdb diff --git a/swap/const.go b/swap/const.go new file mode 100644 index 000000000..e0d39c662 --- /dev/null +++ b/swap/const.go @@ -0,0 +1,6 @@ +package swap + +const ( + // DefaultBtcAssetID is the default asset ID for BTC. + DefaultBtcAssetID = "btc" +)