-
Notifications
You must be signed in to change notification settings - Fork 122
[2/?] Instant loop out: Add reservations #632
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
228bf6a
reservation: add reservation fsm and actions
sputn1ck 1a75a53
reservation add actions tests
sputn1ck a29f7e4
loopdb: add reservation sqlc code
sputn1ck 60df5fe
reservations: add reservation sql store
sputn1ck 61a5f9d
reservation: add reservation manager
sputn1ck d527b0b
reservation: add test for manager
sputn1ck 73d5cf5
swapserverrpc add ReservationServer
sputn1ck 091c0a8
looprpc: add reservation rpcs
sputn1ck 4d558b1
loop: expose server grpc connection
sputn1ck 49c40d9
loopd: add reservation handling
sputn1ck 30acccb
loop: add reservation cli commands
sputn1ck f00329d
loopd: hide reservation manager behind flag.
sputn1ck 9b178dd
fsm: add reservation fsm compiling
sputn1ck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/lightninglabs/loop/looprpc" | ||
| "github.com/urfave/cli" | ||
| ) | ||
|
|
||
| var reservationsCommands = cli.Command{ | ||
|
|
||
| Name: "reservations", | ||
| ShortName: "r", | ||
| Usage: "manage reservations", | ||
sputn1ck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Description: ` | ||
| With loopd running, you can use this command to manage your | ||
| reservations. Reservations are 2-of-2 multisig utxos that | ||
| the loop server can open to clients. The reservations are used | ||
| to enable instant swaps. | ||
| `, | ||
| Subcommands: []cli.Command{ | ||
| listReservationsCommand, | ||
| }, | ||
| } | ||
|
|
||
| var ( | ||
| listReservationsCommand = cli.Command{ | ||
| Name: "list", | ||
sputn1ck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ShortName: "l", | ||
| Usage: "list all reservations", | ||
| ArgsUsage: "", | ||
| Description: ` | ||
| List all reservations. | ||
| `, | ||
| Action: listReservations, | ||
| } | ||
| ) | ||
|
|
||
| func listReservations(ctx *cli.Context) error { | ||
| client, cleanup, err := getClient(ctx) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer cleanup() | ||
|
|
||
| resp, err := client.ListReservations( | ||
| context.Background(), &looprpc.ListReservationsRequest{}, | ||
| ) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| printRespJSON(resp) | ||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| package reservation | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/btcsuite/btcd/btcec/v2" | ||
| "github.com/btcsuite/btcd/btcutil" | ||
| "github.com/lightninglabs/loop/fsm" | ||
| looprpc "github.com/lightninglabs/loop/swapserverrpc" | ||
| ) | ||
|
|
||
| // InitReservationContext contains the request parameters for a reservation. | ||
| type InitReservationContext struct { | ||
| reservationID ID | ||
| serverPubkey *btcec.PublicKey | ||
| value btcutil.Amount | ||
| expiry uint32 | ||
| heightHint uint32 | ||
| } | ||
|
|
||
| // InitAction is the action that is executed when the reservation state machine | ||
| // is initialized. It creates the reservation in the database and dispatches the | ||
| // payment to the server. | ||
| func (r *FSM) InitAction(eventCtx fsm.EventContext) fsm.EventType { | ||
| // Check if the context is of the correct type. | ||
| reservationRequest, ok := eventCtx.(*InitReservationContext) | ||
| if !ok { | ||
| return r.HandleError(fsm.ErrInvalidContextType) | ||
| } | ||
|
|
||
| keyRes, err := r.cfg.Wallet.DeriveNextKey( | ||
| r.ctx, KeyFamily, | ||
| ) | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| // Send the client reservation details to the server. | ||
| log.Debugf("Dispatching reservation to server: %x", | ||
| reservationRequest.reservationID) | ||
|
|
||
| request := &looprpc.ServerOpenReservationRequest{ | ||
| ReservationId: reservationRequest.reservationID[:], | ||
| ClientKey: keyRes.PubKey.SerializeCompressed(), | ||
| } | ||
|
|
||
| _, err = r.cfg.ReservationClient.OpenReservation(r.ctx, request) | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| reservation, err := NewReservation( | ||
| reservationRequest.reservationID, | ||
| reservationRequest.serverPubkey, | ||
| keyRes.PubKey, | ||
| reservationRequest.value, | ||
| reservationRequest.expiry, | ||
| reservationRequest.heightHint, | ||
| keyRes.KeyLocator, | ||
| ) | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| r.reservation = reservation | ||
|
|
||
| // Create the reservation in the database. | ||
| err = r.cfg.Store.CreateReservation(r.ctx, reservation) | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| return OnBroadcast | ||
| } | ||
|
|
||
| // SubscribeToConfirmationAction is the action that is executed when the | ||
| // reservation is waiting for confirmation. It subscribes to the confirmation | ||
| // of the reservation transaction. | ||
| func (r *FSM) SubscribeToConfirmationAction(_ fsm.EventContext) fsm.EventType { | ||
| pkscript, err := r.reservation.GetPkScript() | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| callCtx, cancel := context.WithCancel(r.ctx) | ||
| defer cancel() | ||
|
|
||
| // Subscribe to the confirmation of the reservation transaction. | ||
| log.Debugf("Subscribing to conf for reservation: %x pkscript: %x, "+ | ||
| "initiation height: %v", r.reservation.ID, pkscript, | ||
| r.reservation.InitiationHeight) | ||
|
|
||
| confChan, errConfChan, err := r.cfg.ChainNotifier.RegisterConfirmationsNtfn( | ||
| callCtx, nil, pkscript, DefaultConfTarget, | ||
| r.reservation.InitiationHeight, | ||
| ) | ||
| if err != nil { | ||
| r.Errorf("unable to subscribe to conf notification: %v", err) | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| blockChan, errBlockChan, err := r.cfg.ChainNotifier.RegisterBlockEpochNtfn( | ||
| callCtx, | ||
| ) | ||
| if err != nil { | ||
| r.Errorf("unable to subscribe to block notifications: %v", err) | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| // We'll now wait for the confirmation of the reservation transaction. | ||
| for { | ||
| select { | ||
| case err := <-errConfChan: | ||
| r.Errorf("conf subscription error: %v", err) | ||
| return r.HandleError(err) | ||
|
|
||
| case err := <-errBlockChan: | ||
| r.Errorf("block subscription error: %v", err) | ||
| return r.HandleError(err) | ||
|
|
||
| case confInfo := <-confChan: | ||
| r.Debugf("reservation confirmed: %v", confInfo) | ||
| outpoint, err := r.reservation.findReservationOutput( | ||
| confInfo.Tx, | ||
| ) | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| r.reservation.ConfirmationHeight = confInfo.BlockHeight | ||
| r.reservation.Outpoint = outpoint | ||
|
|
||
| return OnConfirmed | ||
|
|
||
| case block := <-blockChan: | ||
| r.Debugf("block received: %v expiry: %v", block, | ||
| r.reservation.Expiry) | ||
sputn1ck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if uint32(block) >= r.reservation.Expiry { | ||
| return OnTimedOut | ||
| } | ||
|
|
||
| case <-r.ctx.Done(): | ||
| return fsm.NoOp | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // ReservationConfirmedAction waits for the reservation to be either expired or | ||
| // waits for other actions to happen. | ||
| func (r *FSM) ReservationConfirmedAction(_ fsm.EventContext) fsm.EventType { | ||
| blockHeightChan, errEpochChan, err := r.cfg.ChainNotifier. | ||
| RegisterBlockEpochNtfn(r.ctx) | ||
| if err != nil { | ||
| return r.HandleError(err) | ||
| } | ||
|
|
||
| for { | ||
| select { | ||
| case err := <-errEpochChan: | ||
| return r.HandleError(err) | ||
|
|
||
| case blockHeight := <-blockHeightChan: | ||
| expired := blockHeight >= int32(r.reservation.Expiry) | ||
| if expired { | ||
| r.Debugf("Reservation %v expired", | ||
| r.reservation.ID) | ||
|
|
||
| return OnTimedOut | ||
| } | ||
|
|
||
| case <-r.ctx.Done(): | ||
| return fsm.NoOp | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.