Skip to content
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

[7/?] StaticAddr: Loop-In #786

Open
wants to merge 49 commits into
base: static-addr-staging
Choose a base branch
from

Conversation

hieblmi
Copy link
Collaborator

@hieblmi hieblmi commented Jun 28, 2024

This PR introduces loop-ins of static address deposits.
The client/server interaction is depicted below:

image

Open tasks that need resolution until this PR can leave draft mode:

  • Refactorings, unify code with reservations/instantout
  • DB storage & fsm recovery
  • Manual quote acceptance
  • FSM transition consistency checks
  • unit + integration tests
  • signing multiple fee-version htlcs, potential anchor output

Previously merged PRs:

#642
#650
#677
#719
#721
#750

master...static-addr-staging

@hieblmi hieblmi self-assigned this Jun 28, 2024
@hieblmi hieblmi marked this pull request as draft June 28, 2024 12:59
@hieblmi hieblmi force-pushed the static-addr-staging branch 2 times, most recently from d807a95 to e635d63 Compare July 1, 2024 10:51
@hieblmi hieblmi force-pushed the static-addr-7 branch 2 times, most recently from d813b20 to 447d70d Compare July 9, 2024 10:13
@hieblmi hieblmi force-pushed the static-addr-7 branch 3 times, most recently from 7ee61f6 to 3eb5bd2 Compare July 17, 2024 07:11
@hieblmi hieblmi force-pushed the static-addr-7 branch 4 times, most recently from a151ffd to d69e9d5 Compare July 18, 2024 08:19
@hieblmi hieblmi force-pushed the static-addr-7 branch 6 times, most recently from 127d76c to a9d9e6f Compare July 30, 2024 14:38
@hieblmi hieblmi marked this pull request as ready for review July 30, 2024 14:38
@hieblmi hieblmi requested review from bhandras and starius July 30, 2024 14:38
Copy link
Collaborator

@starius starius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed only the first commit with protobuf types "looprpc: static address loop-ins".

looprpc/client.proto Show resolved Hide resolved

/*
EXPIRED indicates that the deposit has expired and the sweep transaction
has been sufficiently confirmed.
*/
EXPIRED = 6;
EXPIRED = 10;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename this state to EXPIRY_SWEEP_CONFIRMED?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These states were introduced in a different PR, so I'd add create a separate refactor PR to fix these up.

looprpc/client.proto Show resolved Hide resolved
looprpc/client.proto Show resolved Hide resolved
swapserverrpc/server.proto Outdated Show resolved Hide resolved
swapserverrpc/server.proto Show resolved Hide resolved
// Examples:
// loopd/v0.10.0-beta/commit=3b635821
// litd/v0.2.0-alpha/commit=326d754
string user_agent = 7;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is StaticAddressLoopInRequest.initiator appended to this field? Can you provide an example of such a user agent in the description, denoting where is the initiator part, please?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again thanks for poking, I was using the initator as the user agent, but there's actually a function that appends the right info so that it matches the examples. Have a look at https://github.com/lightninglabs/loop/blob/master/version.go#L57. Will update the PR

swapserverrpc/server.proto Outdated Show resolved Hide resolved
Comment on lines 795 to 846
// The address that the server wants to sweep the static address deposits
// to.
string sweepless_sweep_addr = 3;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we replace an address with an unsigned tx to provide more flexibility?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With flexibility you mean that if the sweepless sweep tx has different parameters in the future we wouldn't have to modify these rpc messages, but the client would just blindly sign any tx?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is the idea. Then we can implement sweep batching without asking clients to update.

Copy link
Collaborator

@starius starius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed another 3 commits:

  • sqlc: loop-in tables and queries
  • log: static address loop-in logging
  • staticaddr: deposit changes to be squashed

loopdb/sqlc/queries/static_address_loopin.sql Outdated Show resolved Hide resolved
loopdb/sqlc/queries/static_address_loopin.sql Outdated Show resolved Hide resolved
staticaddr/deposit/fsm.go Outdated Show resolved Hide resolved
staticaddr/deposit/fsm.go Show resolved Hide resolved
staticaddr/deposit/fsm.go Outdated Show resolved Hide resolved
staticaddr/deposit/fsm.go Outdated Show resolved Hide resolved
Deposit schema extension with a withdrawal
sweep address. If the user selects a deposit
for withdrawal the destination address of the
sweep is stored here.
A new rpc for deposit withdrawals is added.
A withdrawal cooperatively spends the 2/2
musig deposit outpoint to a client-specified
address.
A server endpoint to obtain a partial sig
to cooperatively spend a 2/2 musig deposit
outpoint.
This commit adds static address deposit outpoints to the
QuoteRequest message. It allows to quote for loop in swaps
with the total value of specified deposits.
This commit adds the number of deposits to the
ServerLoopInQuoteRequest that the client wants
to quote for.
These deposit changes will be squashed into
the original commits once merged into staging.
Copy link
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super clean PR, I think this is very close to ready now!

looprpc/client.proto Show resolved Hide resolved

-- quoted_swap_fee is the swap fee in sats that the server returned in
-- the swap quote.
quoted_swap_fee BIGINT NOT NULL,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just linking to this comment since it's in the auto generated code: 9ef2c6f#r1759145732

I generally agree, we could add the unit to the name here and for the fee rate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

WHERE
swaps.swap_hash = $1;

-- name: GetStaticAddressLoopInSwaps :many
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I assume this is to restart pending swaps. Perhaps we could filter on the state to not return everything.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed GetStaticAddressLoopInSwap and added GetStaticAddressLoopInSwapsByStates which we now use in the recoverLoopIns method.

defer d.Unlock()

return d.state == Expired || d.state == Withdrawn || d.state == Failed
return d.state == Expired || d.state == Withdrawn ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove locking (here and below)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I've removed the locks while working on the recover() in the withdrawal manager. There in GetActiveDepositsInState we lock the states of several deposits in lockDeposits(deposits), but then try to lock again in check if !d.IsInState(stateFilter).

I've restored the locks here, and also provided a method d.IsInStateNoLock(stateFilter) that I call in GetActiveDepositsInState in recover of the withdrawal manager, since all deposits are already locked.

@@ -34,7 +34,7 @@ const (

// DefaultTransitionTimeout is the default timeout for transitions in
// the deposit state machine.
DefaultTransitionTimeout = 1 * time.Minute
DefaultTransitionTimeout = 5 * time.Second
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume some transitions may be blocking, in which case 5 seconds might not be enough?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This timeout is only used in TransitionDeposits of the deposit manager, which has the following caveat:

// TransitionDeposits allows a caller to transition a set of deposits to a new
// state.
// Caveat: The action triggered by the state transitions should not compute
// heavy things or call external endpoints that can block for a long time.
// Deposits will be released if a transition takes longer than
// DefaultTransitionTimeout which is set to 5 seconds.

So we really only call this function to transition to 'light' states.


// Run runs the static address loop-in manager.
func (m *Manager) Run(ctx context.Context, currentHeight uint32) error {
m.runCtx = ctx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea for hygiene, although not strictly required given the current logic.

log.Infof("Recovering static address loop-ins...")

// Recover loop-ins.
loopIns, err := m.cfg.Store.AllLoopIns(m.runCtx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to just select pending ones.


// Create a state machine for a given loop-in.
recovery := true
fsm, err := NewFSM(m.runCtx, loopIn, m.cfg, recovery)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also store the constructed FSM in a member container, e.g. a map to avoid accidental GC.

func (m *Manager) startLoopInFsm(loopIn *StaticAddressLoopIn) error {
// Create a state machine for a given deposit.
recovery := false
loopInFsm, err := NewFSM(m.runCtx, loopIn, m.cfg, recovery)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I think we should store active FSM's in order to avoid accidental GC.

@@ -0,0 +1,336 @@
package loopin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This could be a separate commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants