feat: lwk wallet implementation#451
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThese changes introduce a Liquid wallet implementation with Go bindings, add a new lwk Rust submodule, and update build and CI scripts to support building and integrating the lwk library. New configuration and test utilities for the Liquid wallet are provided, and comprehensive integration tests are added. Changes
Sequence Diagram(s)sequenceDiagram
participant TestSuite
participant LiquidWallet
participant LWKLibrary
participant Esplora
participant LiquidNode
TestSuite->>LiquidWallet: Init(cfg)
LiquidWallet->>LWKLibrary: Initialize wallet (from mnemonic/descriptor)
LiquidWallet->>Esplora: Sync blockchain state (FullScan)
loop Periodic Sync
LiquidWallet->>Esplora: Scan for UTXOs/transactions
LiquidWallet->>LiquidWallet: Update wallet state
alt UTXO count > threshold
LiquidWallet->>LWKLibrary: Consolidate UTXOs
end
end
TestSuite->>LiquidWallet: NewAddress()
LiquidWallet->>LWKLibrary: Generate address
TestSuite->>LiquidWallet: SendToAddress(args)
LiquidWallet->>LWKLibrary: Create & sign transaction
LiquidWallet->>Esplora: Broadcast transaction
Esplora->>LiquidNode: Propagate transaction
Poem
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
c3af376 to
504292a
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (10)
internal/test/test.go (2)
19-19: Consider using a more descriptive import alias.The
liquid_walletalias is functional but could be more concise. Consider usingliquidwalletorlwalletfor better readability.- liquid_wallet "github.com/BoltzExchange/boltz-client/v2/internal/onchain/liquid-wallet" + liquidwallet "github.com/BoltzExchange/boltz-client/v2/internal/onchain/liquid-wallet"
77-108: Improve error handling and timing in wallet initialization.The wallet initialization logic is solid, but there are a few areas for improvement:
- The fixed 3-second sleep after mining may not be reliable across different environments
- Consider adding cleanup for the wallet if funding fails
- time.Sleep(3 * time.Second) + // Wait for wallet to sync with better timeout handling + for retries := 0; retries < 10; retries++ { + time.Sleep(500 * time.Millisecond) + balance, err := wallet.GetBalance() + if err == nil && balance.Confirmed > 0 { + break + } + }Makefile (1)
64-70: Improve the regtest setup condition.The change from checking
regtest/start.shtoregtest/docker-compose.override.ymlis reasonable, but the condition could be more robust.Consider checking for multiple critical files to ensure complete regtest setup:
-ifeq ("$(wildcard regtest/docker-compose.override.yml)","") +ifeq ("$(wildcard regtest/docker-compose.override.yml regtest/start.sh)","")internal/onchain/liquid-wallet/wallet_test.go (2)
73-77: Address the TODO comment and improve transaction verification.The commented-out output verification should be addressed for complete test coverage.
The TODO indicates an issue with output verification. This is likely related to the transaction output structure. Would you like me to help implement the correct output verification logic?
- // TODO: fix this - //require.True(t, slices.ContainsFunc(tx.Outputs, func(o onchain.TransactionOutput) bool { - //return o.Address == address - //})) + // Verify transaction contains the expected output + found := false + for _, output := range tx.Outputs { + if output.Address == address && output.Amount == uint64(amount) { + found = true + break + } + } + require.True(t, found, "Expected output not found in transaction")
101-136: Well-designed auto-consolidation test with minor timing concerns.The test correctly verifies the auto-consolidation feature by creating multiple UTXOs and checking for the consolidation transaction. However, the timing assumptions could be more robust.
Consider making the timing more flexible:
- }, 30*syncInterval, syncInterval) + }, 60*syncInterval, syncInterval/2)This provides more time for async operations while checking more frequently.
internal/onchain/liquid-wallet/wallet.go (5)
1-1: Consider renaming the package to follow Go conventions.Go package names should be lowercase without underscores. Consider renaming to
liquidwallet.-package liquid_wallet +package liquidwallet
146-148: Consider making initial sync failure non-fatal.If the initial
FullScanfails, the entire wallet creation fails. Consider allowing wallet creation to succeed and retrying the sync in the background loop.- if err := result.FullScan(); err != nil { - return nil, err - } + if err := result.FullScan(); err != nil { + logger.Errorf("Initial full scan failed: %v. Will retry in background.", err) + }
157-170: Consider adding exponential backoff for repeated sync failures.While the jitter helps distribute load, repeated failures should use exponential backoff to avoid overwhelming the Esplora server.
Would you like me to implement an exponential backoff mechanism for the sync loop?
242-243: Track and implement the unconfirmed balance TODO.The comment indicates unconfirmed balance should be tracked separately from confirmed balance.
Would you like me to open an issue to track the implementation of unconfirmed balance handling?
264-265: Track the pagination TODO for transaction listing.The comment indicates pagination needs to be implemented in the lwk library.
Would you like me to check if the lwk library has pagination support or open an issue to track this feature?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.github/workflows/test.yml(3 hunks).gitmodules(1 hunks).golangci.yml(1 hunks)Makefile(3 hunks)internal/onchain/liquid-wallet/lwk/dynamic.go(1 hunks)internal/onchain/liquid-wallet/lwk/static.go(1 hunks)internal/onchain/liquid-wallet/wallet.go(1 hunks)internal/onchain/liquid-wallet/wallet_test.go(1 hunks)internal/test/test.go(2 hunks)lwk(1 hunks)rust-toolchain.toml(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
internal/test/test.go (3)
internal/onchain/liquid-wallet/wallet.go (5)
Config(30-36)EsploraConfig(25-28)Wallet(16-23)Init(48-80)NewWallet(101-155)internal/onchain/wallet.go (2)
Wallet(47-57)WalletCredentials(67-74)pkg/boltz/currency.go (1)
CurrencyLiquid(12-12)
internal/onchain/liquid-wallet/wallet.go (4)
internal/onchain/liquid-wallet/lwk/lwk.go (21)
Wollet(6660-6662)Signer(4970-4972)Network(3792-3794)EsploraClient(3098-3100)EsploraClientNewWaterfalls(3116-3126)NewEsploraClient(3103-3113)NetworkRegtestDefault(3808-3812)NetworkTestnet(3814-3818)NetworkMainnet(3796-3800)WolletDescriptor(6906-6908)Mnemonic(3679-3681)NewMnemonic(3684-3694)NewSigner(4975-4985)NewWolletDescriptor(6910-6920)NewWollet(6665-6675)NewAddress(2284-2294)Address(2279-2281)Txid(5928-5930)Transaction(5251-5253)NewTxBuilder(5411-5415)SignerRandom(4988-4998)internal/onchain/wallet.go (2)
WalletInfo(32-38)WalletSendArgs(40-45)pkg/boltz/network.go (2)
TestNet(27-35)MainNet(17-25)internal/logger/logger.go (3)
Errorf(97-99)Debugf(121-123)Infof(113-115)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: CI (ubuntu-latest, 1.24.x)
🔇 Additional comments (11)
.golangci.yml (1)
1-5: Configuration to exclude generated CGO bindings is correct.Excluding
internal/onchain/liquid-wallet/lwk/prevents lint errors on the CGO binding files (dynamic.goandstatic.go).rust-toolchain.toml (1)
2-2: Clarifying comment added for toolchain version pinning.The comment explains why Rust is locked to version
1.81.0, aligning with thelwksubmodule’s caching requirements and improving maintainability.internal/onchain/liquid-wallet/lwk/dynamic.go (1)
1-9: Dynamic CGO binding boilerplate looks correct.The build tags (
dynamic || !static), cgo link flags, and runtime search path settings align with the static variant. Linting is intentionally disabled for this directory..github/workflows/test.yml (2)
23-24: Recursive submodule checkout added.Enabling
submodules: recursiveensures the newly addedlwksubmodule is fetched during the CI checkout step.
45-47: VerifyMakefiletarget name and adjust directory permissions.The workflow runs:
chmod -R 777 regtest && make start-regtest
- The PR summary mentions
setup-regtest, but this invokesstart-regtest. Please confirm the correct Makefile target name.chmod -R 777is overly permissive; preferchmod -R u+rwX,go+rX regtestto limit access.internal/onchain/liquid-wallet/lwk/static.go (1)
1-8: LGTM! Clean cgo static linking implementation.The build constraints and linker flags are appropriate for conditional static linking of the lwk library. The use of
${SRCDIR}ensures the library path is relative to the source directory, and the-Wl,--no-as-needed -ldlflags properly handle dynamic linking dependencies.internal/test/test.go (1)
66-75: LGTM! Well-structured configuration function.The configuration function provides sensible defaults for testing with regtest network and local Esplora endpoint.
Makefile (2)
88-93: LGTM! Well-structured conditional build with proper artifact copying.The build-lwk target correctly uses a conditional check to avoid unnecessary rebuilds and properly copies both static and shared library artifacts to the expected location.
95-95: Verify build dependency order is correct.The build and static targets now depend on build-lwk, which ensures the Rust library is built before the Go binaries. This dependency chain looks correct.
Also applies to: 100-100
internal/onchain/liquid-wallet/wallet_test.go (1)
35-44: LGTM! Good address generation test.The test properly verifies address generation and uniqueness. Well-structured with appropriate assertions.
internal/onchain/liquid-wallet/wallet.go (1)
48-80: Init function implementation looks good.The function properly sets defaults, validates configuration, and creates the necessary Esplora client. Good error handling throughout.
c4e0fb0 to
2646766
Compare
2646766 to
195dcb5
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
internal/onchain/liquid-wallet/wallet_test.go (5)
18-22: Consider adding documentation for test constants.The constants lack documentation explaining their purpose and why these specific values were chosen.
+// Global backend instance shared across tests var backend *liquid_wallet.BlockchainBackend +// syncInterval defines how frequently the wallet syncs with the blockchain during tests const syncInterval = 1 * time.Second +// consolidationThreshold is the number of UTXOs that triggers auto-consolidation const consolidationThreshold = 3
35-92: Good test structure with room for improvement.The test function properly creates isolated wallet instances and uses subtests effectively. However, there are some issues to address.
- Address the TODO comment (lines 66-69): The commented output validation should be implemented or removed.
- Consider extracting magic numbers: The amount
10000and fee rate1could be constants.- Improve assertion clarity (line 71): The fee calculation logic could be more explicit.
+const ( + testSendAmount = int64(10000) + testFeeRate = uint64(1) +) func TestWallet_Funded(t *testing.T) { fundedWallet, err := test.InitTestWalletLiquid(backend) require.NoError(t, err) // ... existing GetBalance test ... t.Run("SendToAddress", func(t *testing.T) { address := test.GetNewAddress(test.LiquidCli) - amount := int64(10000) + amount := testSendAmount txId, err := fundedWallet.SendToAddress(onchain.WalletSendArgs{ Address: address, Amount: uint64(amount), - SatPerVbyte: 1, + SatPerVbyte: testFeeRate, SendAll: false, })
66-72: Address the TODO comment or remove it.The commented validation code should either be implemented or removed if it's no longer needed.
Can you clarify whether the output validation is still needed? If so, I can help implement the fix for the transaction output validation.
119-145: Improve auto-consolidation test reliability.The test logic is sound but could be more robust and clearer.
func TestWallet_AutoConsolidate(t *testing.T) { wallet := newWallet(t) numTxns := consolidationThreshold amount := uint64(500) + + // Send multiple small transactions to trigger consolidation for i := 0; i < numTxns; i++ { address, err := wallet.NewAddress() require.NoError(t, err) require.NotEmpty(t, address) test.SendToAddress(test.LiquidCli, address, amount) - time.Sleep(100 * time.Millisecond) + time.Sleep(100 * time.Millisecond) // Prevent transaction conflicts } test.MineBlock() require.Eventually(t, func() bool { txes, err := wallet.GetTransactions(0, 0) require.NoError(t, err) + + // Expect numTxns incoming transactions + 1 consolidation transaction if len(txes) == numTxns+1 { balance, err := wallet.GetBalance() require.NoError(t, err) total := uint64(numTxns) * amount - change := uint64(txes[0].BalanceChange) - require.Equal(t, balance.Confirmed, total+change) + + // The consolidation transaction should have a negative balance change (fee) + consolidationTx := txes[0] // Assuming newest transaction is first + require.Negative(t, consolidationTx.BalanceChange, "Consolidation should have negative balance change due to fees") + + // Total balance should be original amount minus consolidation fees + expectedBalance := total + uint64(consolidationTx.BalanceChange) + require.Equal(t, expectedBalance, balance.Confirmed) return true } return false }, 30*syncInterval, syncInterval) }
128-128: Document the purpose of the sleep duration.The 100ms sleep could benefit from a comment explaining why this specific duration is needed.
- time.Sleep(100 * time.Millisecond) + time.Sleep(100 * time.Millisecond) // Small delay to prevent mempool conflicts
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.github/workflows/test.yml(3 hunks).gitmodules(1 hunks).golangci.yml(1 hunks)Makefile(3 hunks)internal/onchain/liquid-wallet/lwk/dynamic.go(1 hunks)internal/onchain/liquid-wallet/lwk/static.go(1 hunks)internal/onchain/liquid-wallet/wallet.go(1 hunks)internal/onchain/liquid-wallet/wallet_test.go(1 hunks)internal/test/test.go(2 hunks)lwk(1 hunks)rust-toolchain.toml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
- .golangci.yml
- .gitmodules
- rust-toolchain.toml
- internal/onchain/liquid-wallet/lwk/dynamic.go
- .github/workflows/test.yml
- lwk
- internal/onchain/liquid-wallet/lwk/static.go
- internal/test/test.go
- Makefile
- internal/onchain/liquid-wallet/wallet.go
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: CI (ubuntu-latest, 1.24.x)
🔇 Additional comments (4)
internal/onchain/liquid-wallet/wallet_test.go (4)
1-3: LGTM! Proper build tag for integration tests.The
!unitbuild tag correctly excludes this integration test from unit test runs.
79-91: Verify fee calculation logic.The test assumes that
amount + feeequals the confirmed balance, but this might not always be true if there are previous transactions or change outputs.Consider adding more context to this assertion or using a more explicit balance check:
t.Run("SendFee", func(t *testing.T) { address := test.GetNewAddress(test.LiquidCli) + initialBalance, err := fundedWallet.GetBalance() + require.NoError(t, err) + amount, fee, err := fundedWallet.GetSendFee(onchain.WalletSendArgs{ Address: address, SatPerVbyte: 1, SendAll: true, }) require.NoError(t, err) - balance, err := fundedWallet.GetBalance() - require.NoError(t, err) - require.Equal(t, balance.Confirmed, amount+fee) + // When SendAll is true, amount + fee should equal the confirmed balance + require.Equal(t, initialBalance.Confirmed, amount+fee) })
94-105: LGTM! Well-structured helper function.The
newWalletfunction properly creates isolated wallet instances for testing.
107-117: LGTM! Good address uniqueness validation.The test properly verifies that the wallet generates unique addresses.
Docstrings generation was requested by @jackstar12. * #451 (comment) The following files were modified: * `internal/onchain/liquid-wallet/wallet.go` * `internal/test/test.go`
|
Note Generated docstrings for this pull request at #458 |
fd8d76a to
26e0516
Compare
26e0516 to
67a27a7
Compare
67a27a7 to
0460d76
Compare
Initial LWK wallet implementation.
All
Walletinterface methods have been implemented, aswell asFollow ups: #457, #456
Summary by CodeRabbit
New Features
Chores