diff --git a/test/lwk_cln_test.go b/test/lwk_cln_test.go index 69f67abb..1e5dddde 100644 --- a/test/lwk_cln_test.go +++ b/test/lwk_cln_test.go @@ -994,3 +994,489 @@ func Test_ClnLnd_LWK_SwapOut(t *testing.T) { csvClaimTest(t, params) }) } + +func Test_ClnCln_LWKElements_SwapIn(t *testing.T) { + IsIntegrationTest(t) + t.Parallel() + t.Run("claim_normal", func(t *testing.T) { + t.Parallel() + require := require.New(t) + + bitcoind, liquidd, lightningds, scid, electrs, lwk := clnclnLWKLiquidSetup(t, uint64(math.Pow10(9))) + defer func() { + if t.Failed() { + filter := os.Getenv("PEERSWAP_TEST_FILTER") + pprintFail( + tailableProcess{ + p: bitcoind.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: liquidd.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[0].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[1].DaemonProcess, + // filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: electrs.Process, + lines: defaultLines, + }, + tailableProcess{ + p: lwk.Process, + lines: defaultLines, + }, + ) + } + }() + + var channelBalances []uint64 + var walletBalances []uint64 + for _, lightningd := range lightningds { + b, err := lightningd.GetBtcBalanceSat() + require.NoError(err) + walletBalances = append(walletBalances, b) + + b, err = lightningd.GetChannelBalanceSat(scid) + require.NoError(err) + channelBalances = append(channelBalances, b) + } + + params := &testParams{ + swapAmt: channelBalances[0] / 2, + scid: scid, + origTakerWallet: walletBalances[0], + origMakerWallet: walletBalances[1], + origTakerBalance: channelBalances[0], + origMakerBalance: channelBalances[1], + takerNode: lightningds[0], + makerNode: lightningds[1], + takerPeerswap: lightningds[0].DaemonProcess, + makerPeerswap: lightningds[1].DaemonProcess, + chainRpc: liquidd.RpcProxy, + chaind: liquidd, + confirms: LiquidConfirms, + csv: LiquidCsv, + swapType: swap.SWAPTYPE_IN, + } + asset := "lbtc" + + // Do swap. + go func() { + var response map[string]interface{} + err := lightningds[1].Rpc.Request(&clightning.SwapIn{SatAmt: params.swapAmt, ShortChannelId: params.scid, Asset: asset}, &response) + require.NoError(err) + + }() + preimageClaimTest(t, params) + }) + t.Run("claim_coop", func(t *testing.T) { + t.Parallel() + require := require.New(t) + + bitcoind, liquidd, lightningds, scid, electrs, lwk := clnclnLWKLiquidSetup(t, uint64(math.Pow10(9))) + defer func() { + if t.Failed() { + filter := os.Getenv("PEERSWAP_TEST_FILTER") + pprintFail( + tailableProcess{ + p: bitcoind.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: liquidd.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[0].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[1].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: electrs.Process, + lines: defaultLines, + }, + tailableProcess{ + p: lwk.Process, + lines: defaultLines, + }, + ) + } + }() + + var channelBalances []uint64 + var walletBalances []uint64 + for _, lightningd := range lightningds { + b, err := lightningd.GetBtcBalanceSat() + require.NoError(err) + walletBalances = append(walletBalances, b) + + b, err = lightningd.GetChannelBalanceSat(scid) + require.NoError(err) + channelBalances = append(channelBalances, b) + } + + params := &testParams{ + swapAmt: channelBalances[0] / 2, + scid: scid, + origTakerWallet: walletBalances[0], + origMakerWallet: walletBalances[1], + origTakerBalance: channelBalances[0], + origMakerBalance: channelBalances[1], + takerNode: lightningds[0], + makerNode: lightningds[1], + takerPeerswap: lightningds[0].DaemonProcess, + makerPeerswap: lightningds[1].DaemonProcess, + chainRpc: liquidd.RpcProxy, + chaind: liquidd, + confirms: LiquidConfirms, + csv: LiquidCsv, + swapType: swap.SWAPTYPE_IN, + } + asset := "lbtc" + + // Do swap. + go func() { + var response map[string]interface{} + err := lightningds[1].Rpc.Request(&clightning.SwapIn{SatAmt: params.swapAmt, ShortChannelId: params.scid, Asset: asset}, &response) + require.NoError(err) + + }() + coopClaimTest(t, params) + }) + + t.Run("claim_csv", func(t *testing.T) { + t.Parallel() + require := require.New(t) + + bitcoind, liquidd, lightningds, scid, electrs, lwk := clnclnLWKLiquidSetup(t, uint64(math.Pow10(9))) + defer func() { + if t.Failed() { + filter := os.Getenv("PEERSWAP_TEST_FILTER") + pprintFail( + tailableProcess{ + p: bitcoind.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: liquidd.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[0].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[1].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: electrs.Process, + lines: defaultLines, + }, + tailableProcess{ + p: lwk.Process, + lines: defaultLines, + }, + ) + } + }() + + var channelBalances []uint64 + var walletBalances []uint64 + for _, lightningd := range lightningds { + b, err := lightningd.GetBtcBalanceSat() + require.NoError(err) + walletBalances = append(walletBalances, b) + + b, err = lightningd.GetChannelBalanceSat(scid) + require.NoError(err) + channelBalances = append(channelBalances, b) + } + + params := &testParams{ + swapAmt: channelBalances[0] / 2, + scid: scid, + origTakerWallet: walletBalances[0], + origMakerWallet: walletBalances[1], + origTakerBalance: channelBalances[0], + origMakerBalance: channelBalances[1], + takerNode: lightningds[0], + makerNode: lightningds[1], + takerPeerswap: lightningds[0].DaemonProcess, + makerPeerswap: lightningds[1].DaemonProcess, + chainRpc: liquidd.RpcProxy, + chaind: liquidd, + confirms: LiquidConfirms, + csv: LiquidCsv, + swapType: swap.SWAPTYPE_IN, + } + asset := "lbtc" + + // Do swap. + go func() { + var response map[string]interface{} + err := lightningds[1].Rpc.Request(&clightning.SwapIn{SatAmt: params.swapAmt, ShortChannelId: params.scid, Asset: asset}, &response) + require.NoError(err) + + }() + csvClaimTest(t, params) + }) +} + +func Test_ClnCln_LWKLiquid_SwapOut(t *testing.T) { + IsIntegrationTest(t) + t.Parallel() + t.Run("claim_normal", func(t *testing.T) { + t.Parallel() + require := require.New(t) + + bitcoind, liquidd, lightningds, scid, electrs, lwk := clnclnLWKLiquidSetup(t, uint64(math.Pow10(9))) + defer func() { + if t.Failed() { + filter := os.Getenv("PEERSWAP_TEST_FILTER") + pprintFail( + tailableProcess{ + p: bitcoind.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: liquidd.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[0].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[1].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: electrs.Process, + lines: defaultLines, + }, + tailableProcess{ + p: lwk.Process, + lines: defaultLines, + }, + ) + } + }() + + var channelBalances []uint64 + var walletBalances []uint64 + for _, lightningd := range lightningds { + b, err := lightningd.GetBtcBalanceSat() + require.NoError(err) + walletBalances = append(walletBalances, b) + + b, err = lightningd.GetChannelBalanceSat(scid) + require.NoError(err) + channelBalances = append(channelBalances, b) + } + + params := &testParams{ + swapAmt: channelBalances[0] / 2, + scid: scid, + origTakerWallet: walletBalances[0], + origMakerWallet: walletBalances[1], + origTakerBalance: channelBalances[0], + origMakerBalance: channelBalances[1], + takerNode: lightningds[0], + makerNode: lightningds[1], + takerPeerswap: lightningds[0].DaemonProcess, + makerPeerswap: lightningds[1].DaemonProcess, + chainRpc: liquidd.RpcProxy, + chaind: liquidd, + confirms: LiquidConfirms, + csv: LiquidCsv, + swapType: swap.SWAPTYPE_OUT, + } + asset := "lbtc" + + // Do swap. + go func() { + var response map[string]interface{} + err := lightningds[0].Rpc.Request(&clightning.SwapOut{SatAmt: params.swapAmt, ShortChannelId: params.scid, Asset: asset}, &response) + require.NoError(err) + + }() + preimageClaimTest(t, params) + }) + t.Run("claim_coop", func(t *testing.T) { + t.Parallel() + require := require.New(t) + + bitcoind, liquidd, lightningds, scid, electrs, lwk := clnclnLWKSetup(t, uint64(math.Pow10(9))) + defer func() { + if t.Failed() { + filter := os.Getenv("PEERSWAP_TEST_FILTER") + pprintFail( + tailableProcess{ + p: bitcoind.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: liquidd.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[0].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[1].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: electrs.Process, + lines: defaultLines, + }, + tailableProcess{ + p: lwk.Process, + lines: defaultLines, + }, + ) + } + }() + + var channelBalances []uint64 + var walletBalances []uint64 + for _, lightningd := range lightningds { + b, err := lightningd.GetBtcBalanceSat() + require.NoError(err) + walletBalances = append(walletBalances, b) + + b, err = lightningd.GetChannelBalanceSat(scid) + require.NoError(err) + channelBalances = append(channelBalances, b) + } + + params := &testParams{ + swapAmt: channelBalances[0] / 2, + scid: scid, + origTakerWallet: walletBalances[0], + origMakerWallet: walletBalances[1], + origTakerBalance: channelBalances[0], + origMakerBalance: channelBalances[1], + takerNode: lightningds[0], + makerNode: lightningds[1], + takerPeerswap: lightningds[0].DaemonProcess, + makerPeerswap: lightningds[1].DaemonProcess, + chainRpc: liquidd.RpcProxy, + chaind: liquidd, + confirms: LiquidConfirms, + csv: LiquidCsv, + swapType: swap.SWAPTYPE_OUT, + } + asset := "lbtc" + + // Do swap. + go func() { + var response map[string]interface{} + err := lightningds[0].Rpc.Request(&clightning.SwapOut{SatAmt: params.swapAmt, ShortChannelId: params.scid, Asset: asset}, &response) + require.NoError(err) + + }() + coopClaimTest(t, params) + }) + + t.Run("claim_csv", func(t *testing.T) { + t.Parallel() + require := require.New(t) + + bitcoind, liquidd, lightningds, scid, electrs, lwk := clnclnLWKSetup(t, uint64(math.Pow10(9))) + defer func() { + if t.Failed() { + filter := os.Getenv("PEERSWAP_TEST_FILTER") + pprintFail( + tailableProcess{ + p: bitcoind.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: liquidd.DaemonProcess, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[0].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: lightningds[1].DaemonProcess, + filter: filter, + lines: defaultLines, + }, + tailableProcess{ + p: electrs.Process, + lines: defaultLines, + }, + tailableProcess{ + p: lwk.Process, + lines: defaultLines, + }, + ) + } + }() + + var channelBalances []uint64 + var walletBalances []uint64 + for _, lightningd := range lightningds { + b, err := lightningd.GetBtcBalanceSat() + require.NoError(err) + walletBalances = append(walletBalances, b) + + b, err = lightningd.GetChannelBalanceSat(scid) + require.NoError(err) + channelBalances = append(channelBalances, b) + } + + params := &testParams{ + swapAmt: channelBalances[0] / 2, + scid: scid, + origTakerWallet: walletBalances[0], + origMakerWallet: walletBalances[1], + origTakerBalance: channelBalances[0], + origMakerBalance: channelBalances[1], + takerNode: lightningds[0], + makerNode: lightningds[1], + takerPeerswap: lightningds[0].DaemonProcess, + makerPeerswap: lightningds[1].DaemonProcess, + chainRpc: liquidd.RpcProxy, + chaind: liquidd, + confirms: LiquidConfirms, + csv: LiquidCsv, + swapType: swap.SWAPTYPE_OUT, + } + asset := "lbtc" + + // Do swap. + go func() { + var response map[string]interface{} + err := lightningds[0].Rpc.Request(&clightning.SwapOut{SatAmt: params.swapAmt, ShortChannelId: params.scid, Asset: asset}, &response) + require.NoError(err) + + }() + csvClaimTest(t, params) + }) +} diff --git a/test/setup.go b/test/setup.go index 155ac042..903f23c5 100644 --- a/test/setup.go +++ b/test/setup.go @@ -1336,3 +1336,244 @@ func mixedLWKSetup(t *testing.T, fundAmt uint64, funder fundingNode) (*testframe syncPoll(&clnPollableNode{cln}, &peerswapPollableNode{peerswapd, lnd.Id()}) return bitcoind, liquidd, lightningds, peerswapd, scid, electrsd, lwk } + +func clnclnLWKLiquidSetup(t *testing.T, fundAmt uint64) (*testframework.BitcoinNode, + *testframework.LiquidNode, []*CLightningNodeWithLiquid, string, + *testframework.Electrs, *testframework.LWK) { + /// Get PeerSwap plugin path and test dir + _, filename, _, _ := runtime.Caller(0) + pathToPlugin := filepath.Join(filename, "..", "..", "out", "test-builds", "peerswap") + testDir := t.TempDir() + + // Setup nodes (1 bitcoind, 1 liquidd, 2 lightningd) + bitcoind, err := testframework.NewBitcoinNode(testDir, 1) + if err != nil { + t.Fatalf("could not create bitcoind %v", err) + } + t.Cleanup(bitcoind.Kill) + + liquidd, err := testframework.NewLiquidNode(testDir, bitcoind, 1) + if err != nil { + t.Fatal("error creating liquidd node", err) + } + t.Cleanup(liquidd.Kill) + + electrsd, err := testframework.NewElectrs(testDir, 1, liquidd) + if err != nil { + t.Fatal("error creating electrsd node", err) + } + t.Cleanup(electrsd.Process.Kill) + + lwk, err := testframework.NewLWK(testDir, 1, electrsd) + if err != nil { + t.Fatal("error creating electrsd node", err) + } + t.Cleanup(lwk.Process.Kill) + + var lightningds []*testframework.CLightningNode + + lightningd, err := testframework.NewCLightningNode(testDir, bitcoind, 1) + if err != nil { + t.Fatalf("could not create liquidd %v", err) + } + t.Cleanup(lightningd.Kill) + defer printFailedFiltered(t, lightningd.DaemonProcess) + + // Create policy file and accept all peers + err = os.MkdirAll(filepath.Join(lightningd.GetDataDir(), "peerswap"), os.ModePerm) + if err != nil { + t.Fatal("could not create dir", err) + } + err = os.WriteFile(filepath.Join(lightningd.GetDataDir(), "peerswap", "policy.conf"), []byte("accept_all_peers=1\n"), os.ModePerm) + if err != nil { + t.Fatal("could not create policy file", err) + } + + walletName := "swapElements" + + // Create config file + fileConf := struct { + Liquid struct { + RpcUser string + RpcPassword string + RpcHost string + RpcPort uint + RpcWallet string + } + }{ + Liquid: struct { + RpcUser string + RpcPassword string + RpcHost string + RpcPort uint + RpcWallet string + }{ + RpcUser: liquidd.RpcUser, + RpcPassword: liquidd.RpcPassword, + RpcHost: "http://127.0.0.1", + RpcPort: uint(liquidd.RpcPort), + RpcWallet: walletName, + }, + } + + data, err := toml.Marshal(fileConf) + require.NoError(t, err) + + configPath := filepath.Join(lightningd.GetDataDir(), "peerswap", "peerswap.conf") + os.WriteFile( + configPath, + data, + os.ModePerm, + ) + + // Use lightningd with --developer turned on + lightningd.WithCmd("lightningd") + + // Add plugin to cmd line options + lightningd.AppendCmdLine([]string{ + "--dev-bitcoind-poll=1", + "--dev-fast-gossip", + "--large-channels", + fmt.Sprint("--plugin=", pathToPlugin), + }) + + lightningds = append(lightningds, lightningd) + + lightningd, err = testframework.NewCLightningNode(testDir, bitcoind, 2) + if err != nil { + t.Fatalf("could not create liquidd %v", err) + } + t.Cleanup(lightningd.Kill) + defer printFailedFiltered(t, lightningd.DaemonProcess) + + // Create policy file and accept all peers + err = os.MkdirAll(filepath.Join(lightningd.GetDataDir(), "peerswap"), os.ModePerm) + if err != nil { + t.Fatal("could not create dir", err) + } + err = os.WriteFile(filepath.Join(lightningd.GetDataDir(), "peerswap", "policy.conf"), []byte("accept_all_peers=1\n"), os.ModePerm) + if err != nil { + t.Fatal("could not create policy file", err) + } + + // Set wallet name + walletName2 := "swapLWK" + + // Create config file + fileConf2 := struct { + LWK struct { + SignerName string + WalletName string + LWKEndpoint string + ElectrumEndpoint string + Network string + LiquidSwaps bool + } + }{ + LWK: struct { + SignerName string + WalletName string + LWKEndpoint string + ElectrumEndpoint string + Network string + LiquidSwaps bool + }{ + WalletName: walletName2, + SignerName: walletName2 + "-" + "signer", + LiquidSwaps: true, + LWKEndpoint: lwk.RPCURL.String(), + ElectrumEndpoint: electrsd.RPCURL.String(), + Network: "liquid-regtest", + }, + } + data, err = toml.Marshal(fileConf2) + require.NoError(t, err) + + configPath = filepath.Join(lightningd.GetDataDir(), "peerswap", "peerswap.conf") + os.WriteFile( + configPath, + data, + os.ModePerm, + ) + + // Use lightningd with --developer turned on + lightningd.WithCmd("lightningd") + + // Add plugin to cmd line options + lightningd.AppendCmdLine([]string{ + "--dev-bitcoind-poll=1", + "--dev-fast-gossip", + "--large-channels", + fmt.Sprint("--plugin=", pathToPlugin), + }) + + lightningds = append(lightningds, lightningd) + + // Start nodes + err = bitcoind.Run(true) + if err != nil { + t.Fatalf("bitcoind.Run() got err %v", err) + } + + err = liquidd.Run(true) + if err != nil { + t.Fatalf("Run() got err %v", err) + } + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, testframework.TIMEOUT) + defer cancel() + require.NoError(t, electrsd.Run(ctx)) + lwk.Process.Run() + + for _, lightningd := range lightningds { + err = lightningd.Run(true, true) + if err != nil { + t.Fatalf("lightningd.Run() got err %v", err) + } + err = lightningd.WaitForLog("peerswap initialized", testframework.TIMEOUT) + if err != nil { + t.Fatalf("lightningd.WaitForLog() got err %v", err) + } + } + + // Give liquid funds to nodes to have something to swap. + for _, lightningd := range lightningds { + var result clightning.GetAddressResponse + require.NoError(t, lightningd.Rpc.Request(&clightning.LiquidGetAddress{}, &result)) + _, err = liquidd.Rpc.Call("sendtoaddress", result.LiquidAddress, 10., "", "", false, false, 1, "UNSET") + require.NoError(t, err) + _ = liquidd.GenerateBlocks(20) + require.NoError(t, + testframework.WaitFor(func() bool { + var balance clightning.GetBalanceResponse + require.NoError(t, lightningd.Rpc.Request(&clightning.LiquidGetBalance{}, &balance)) + return balance.LiquidBalance >= 1000000000 + }, testframework.TIMEOUT)) + } + + // Lock txs. + _, err = liquidd.Rpc.Call("generatetoaddress", 1, testframework.LBTC_BURN) + require.NoError(t, err) + require.NoError(t, liquidd.GenerateBlocks(20)) + + // Setup channel ([0] fundAmt(10^7) ---- 0 [1]). + scid, err := lightningds[0].OpenChannel(lightningds[1], fundAmt, 0, true, true, true) + if err != nil { + t.Fatalf("lightingds[0].OpenChannel() %v", err) + } + + // Sync peer polling + var result interface{} + err = lightningds[0].Rpc.Request(&clightning.ReloadPolicyFile{}, &result) + if err != nil { + t.Fatalf("ListPeers %v", err) + } + err = lightningds[1].Rpc.Request(&clightning.ReloadPolicyFile{}, &result) + if err != nil { + t.Fatalf("ListPeers %v", err) + } + + syncPoll(&clnPollableNode{lightningds[0]}, &clnPollableNode{lightningds[1]}) + + return bitcoind, liquidd, []*CLightningNodeWithLiquid{{lightningds[0]}, {lightningds[1]}}, scid, electrsd, lwk +}