multi: add backward compatibility test

This commit is contained in:
Oliver Gugger 2025-05-15 11:17:08 +02:00
parent c99f2dc07c
commit 03c80cfeab
No known key found for this signature in database
GPG key ID: 8E4256593F177720
11 changed files with 270 additions and 46 deletions

View file

@ -207,20 +207,20 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap,
erinAssetBalance := assetSendAmount - erinFundingAmount
// Assert that we see the funding outputs in the wallet.
itest.AssertBalances(
assertBalance(
t.t, charlieTap, charlieFundingAmount,
itest.WithAssetID(assetID),
itest.WithScriptKeyType(asset.ScriptKeyScriptPathChannel),
itest.WithNumUtxos(1),
itest.WithScriptKey(fundingScriptKeyBytes),
)
itest.AssertBalances(
assertBalance(
t.t, daveTap, daveFundingAmount, itest.WithAssetID(assetID),
itest.WithScriptKeyType(asset.ScriptKeyScriptPathChannel),
itest.WithNumUtxos(1),
itest.WithScriptKey(fundingScriptKeyBytes),
)
itest.AssertBalances(
assertBalance(
t.t, erinTap, erinFundingAmount, itest.WithAssetID(assetID),
itest.WithScriptKeyType(asset.ScriptKeyScriptPathChannel),
itest.WithNumUtxos(1),
@ -229,14 +229,13 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap,
// After opening the channels, the asset balance of the funding nodes
// should have been decreased with the funding amount.
itest.AssertBalances(
t.t, charlieTap, charlieAssetBalance,
itest.WithAssetID(assetID),
assertBalance(
t.t, charlieTap, charlieAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, daveTap, daveAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, erinTap, erinAssetBalance, itest.WithAssetID(assetID),
)
@ -527,6 +526,18 @@ func createTestAssetNetworkGroupKey(ctx context.Context, t *harnessTest,
return chanPointCD, chanPointEF
}
// assertBalance is a thin wrapper around itest.AssertBalances that skips the
// balance check for old versions during the backward compatibility test.
func assertBalance(t *testing.T, client *tapClient, balance uint64,
opts ...itest.BalanceOption) {
if client.node.Cfg.SkipBalanceChecks {
return
}
itest.AssertBalances(t, client, balance, opts...)
}
// sendAssetsAndAssert sends the given amount of assets to the recipient and
// asserts that the transfer was successful. It also checks that the asset
// balance of the sender and recipient is as expected.
@ -718,6 +729,12 @@ func assertPendingChannels(t *testing.T, node *HarnessNode,
require.NoError(t, err)
require.Len(t, pendingChannelsResp.PendingOpenChannels, numChannels)
// For older versions (during the backward compatibility test), if the
// channel custom data is in the old format, we can't do further checks.
if node.Cfg.OldChannelFormat {
return
}
pendingChan := pendingChannelsResp.PendingOpenChannels[0]
var pendingJSON rfqmsg.JsonAssetChannel
err = json.Unmarshal(
@ -768,6 +785,12 @@ func haveFundingAsset(assetChannel *rfqmsg.JsonAssetChannel,
func assertAssetChan(t *testing.T, src, dst *HarnessNode, fundingAmount uint64,
channelAssets []*taprpc.Asset) {
if src.Cfg.OldChannelFormat {
t.Logf("Skipping asset channel check for %s->%s, old format",
src.Cfg.Name, dst.Cfg.Name)
return
}
err := wait.NoError(func() error {
a, err := getChannelCustomData(src, dst)
if err != nil {
@ -1822,8 +1845,12 @@ func closeAssetChannelAndAssert(t *harnessTest, net *NetworkHarness,
)
require.NoError(t.t, err)
assertWaitingCloseChannelAssetData(t.t, local, chanPoint)
assertWaitingCloseChannelAssetData(t.t, remote, chanPoint)
if !local.Cfg.OldChannelFormat {
assertWaitingCloseChannelAssetData(t.t, local, chanPoint)
}
if !remote.Cfg.OldChannelFormat {
assertWaitingCloseChannelAssetData(t.t, remote, chanPoint)
}
mineBlocks(t, net, 1, 1)
@ -1846,8 +1873,12 @@ func closeAssetChannelAndAssert(t *harnessTest, net *NetworkHarness,
universeTap,
)
assertClosedChannelAssetData(t.t, local, chanPoint)
assertClosedChannelAssetData(t.t, remote, chanPoint)
if !local.Cfg.OldChannelFormat {
assertClosedChannelAssetData(t.t, local, chanPoint)
}
if !remote.Cfg.OldChannelFormat {
assertClosedChannelAssetData(t.t, remote, chanPoint)
}
}
// assertDefaultCoOpCloseBalance returns a default implementation of the co-op

View file

@ -639,20 +639,20 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness,
erinAssetBalance += 3
fabiaAssetBalance -= 3
yaraAssetBalance -= 1
itest.AssertBalances(
assertBalance(
t.t, charlieTap, charlieAssetBalance,
itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, daveTap, daveAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, erinTap, erinAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, fabiaTap, fabiaAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, yaraTap, yaraAssetBalance, itest.WithAssetID(assetID),
)
@ -698,7 +698,7 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness,
)
// Charlie should still have four asset pieces, two with the same size.
itest.AssertBalances(
assertBalance(
t.t, charlieTap, charlieAssetBalance,
itest.WithAssetID(assetID), itest.WithNumUtxos(2),
itest.WithScriptKeyType(asset.ScriptKeyBip86),
@ -706,7 +706,7 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness,
// Dave should have two outputs, one from the initial channel with Yara
// and one from the remaining amount of the channel with Charlie.
itest.AssertBalances(
assertBalance(
t.t, daveTap, daveAssetBalance, itest.WithAssetID(assetID),
itest.WithNumUtxos(2),
itest.WithScriptKeyType(asset.ScriptKeyBip86),
@ -714,12 +714,12 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness,
// Fabia and Yara should all have a single output each, just what was
// left over from the initial channel.
itest.AssertBalances(
assertBalance(
t.t, fabiaTap, fabiaAssetBalance, itest.WithAssetID(assetID),
itest.WithNumUtxos(1),
itest.WithScriptKeyType(asset.ScriptKeyBip86),
)
itest.AssertBalances(
assertBalance(
t.t, yaraTap, yaraAssetBalance, itest.WithAssetID(assetID),
itest.WithNumUtxos(1),
itest.WithScriptKeyType(asset.ScriptKeyBip86),
@ -728,24 +728,24 @@ func testCustomChannels(ctx context.Context, net *NetworkHarness,
// Erin didn't use all of his assets when opening the channel, so he
// should have two outputs, the change from the channel opening and the
// remaining amount after closing the channel.
itest.AssertBalances(
assertBalance(
t.t, erinTap, erinAssetBalance, itest.WithAssetID(assetID),
itest.WithNumUtxos(2),
itest.WithScriptKeyType(asset.ScriptKeyBip86),
)
// The asset balances should still remain unchanged.
itest.AssertBalances(
assertBalance(
t.t, charlieTap, charlieAssetBalance,
itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, daveTap, daveAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, erinTap, erinAssetBalance, itest.WithAssetID(assetID),
)
itest.AssertBalances(
assertBalance(
t.t, fabiaTap, fabiaAssetBalance, itest.WithAssetID(assetID),
)
}

View file

@ -68,6 +68,26 @@ var (
"litdbbackend", terminal.DatabaseBackendBbolt, "Set the "+
"database backend to use when starting a LiT daemon.",
)
// backwardCompatFlagOverride is a map of LiT versions to a map of
// config file flags that need to be overwritten or added for the target
// version to work. If a flag in the map is empty, it means it will be
// removed from the config file of that version.
backwardCompatFlagOverride = map[string]map[string]string{
"v0.14.1-alpha": {
"databasebackend": "",
"lnd.logging.no-commit-hash": "",
},
}
// backwardCompatConfigOverride is a map of LiT versions to a map of
// config file overriding functions.
backwardCompatConfigOverride = map[string]func(*LitNodeConfig){
"v0.14.1-alpha": func(cfg *LitNodeConfig) {
cfg.OldChannelFormat = true
cfg.SkipBalanceChecks = true
},
}
)
// Option is a function for updating a node's configuration.
@ -103,6 +123,14 @@ type LitNodeConfig struct {
LitPort int
LitRESTPort int
// OldChannelFormat is a flag for turning off certain checks for old
// versions of litd during the backward compatibility test.
OldChannelFormat bool
// SkipBalanceChecks is a flag for turning off certain checks for old
// versions of litd during the backward compatibility test.
SkipBalanceChecks bool
// backupDBDir is the path where a database backup is stored, if any.
backupDBDir string
}
@ -616,17 +644,60 @@ func renameFile(fromFileName, toFileName string) {
}
}
// overrideFlagsAndBinary is a helper function that checks if the passed node
// name needs a version downgrade and if so, it will return the new binary
// name and the new arguments.
func (hn *HarnessNode) overrideFlagsAndBinary(backwardCompat map[string]string,
binary string, args []LitArgOption) (string, []LitArgOption) {
if backwardCompat == nil {
return binary, args
}
downgradeVersion, ok := backwardCompat[hn.Cfg.Name]
if !ok {
return binary, args
}
newBinary := fmt.Sprintf("%s-%s", binary, downgradeVersion)
flagOverride, ok := backwardCompatFlagOverride[downgradeVersion]
if !ok {
return newBinary, args
}
for k, v := range flagOverride {
if v == "" {
args = append(args, WithoutLitArg(k))
} else {
args = append(args, WithLitArg(k, v))
}
}
cfgOverride, ok := backwardCompatConfigOverride[downgradeVersion]
if ok && cfgOverride != nil {
cfgOverride(hn.Cfg)
}
return newBinary, args
}
// Start launches a new process running lnd. Additionally, the PID of the
// launched process is saved in order to possibly kill the process forcibly
// later.
//
// This may not clean up properly if an error is returned, so the caller should
// call shutdown() regardless of the return value.
func (hn *HarnessNode) Start(litdBinary string, litdError chan<- error,
func (hn *HarnessNode) Start(litdBinary string,
backwardCompat map[string]string, litdError chan<- error,
waitForStart bool, litArgOpts ...LitArgOption) error {
hn.quit = make(chan struct{})
litdBinary, litArgOpts = hn.overrideFlagsAndBinary(
backwardCompat, litdBinary, litArgOpts,
)
args := hn.Cfg.GenArgs(litArgOpts...)
hn.cmd = exec.Command(litdBinary, args...)

View file

@ -71,6 +71,7 @@ func TestLightningTerminal(t *testing.T) {
lndSubTest := lndHarness.Subtest(t1)
litdHarness, err := NewNetworkHarness(
lndSubTest, chainBackend, binary, feeService,
testCase.backwardCompat,
)
require.NoError(t1, err)

View file

@ -29,6 +29,15 @@ var allTestCases = []*testCase{
test: testCustomChannels,
noAliceBob: true,
},
{
name: "custom channels backward compatibility",
test: testCustomChannels,
noAliceBob: true,
backwardCompat: map[string]string{
"Dave": "v0.14.1-alpha",
"Fabia": "v0.14.1-alpha",
},
},
{
name: "custom channels large",
test: testCustomChannelsLarge,

View file

@ -69,6 +69,11 @@ type NetworkHarness struct {
Alice *HarnessNode
Bob *HarnessNode
// backwardCompat is a map of node names to the version of litd that
// should be used for them. If the map is empty, then the latest/current
// version will be used for all nodes.
backwardCompat map[string]string
// Channel for transmitting stderr output from failed lightning node
// to main process.
lndErrorChan chan error
@ -78,19 +83,20 @@ type NetworkHarness struct {
// NewNetworkHarness creates a new network test harness.
func NewNetworkHarness(lndHarness *lntest.HarnessTest, b node.BackendConfig,
litdBinary string, feeService lntest.WebFeeService) (*NetworkHarness,
error) {
litdBinary string, feeService lntest.WebFeeService,
backwardCompat map[string]string) (*NetworkHarness, error) {
n := NetworkHarness{
activeNodes: make(map[int]*HarnessNode),
nodesByPub: make(map[string]*HarnessNode),
lndErrorChan: make(chan error),
netParams: lndHarness.Miner().ActiveNet,
Miner: lndHarness.Miner(),
LNDHarness: lndHarness,
BackendCfg: b,
litdBinary: litdBinary,
feeService: feeService,
activeNodes: make(map[int]*HarnessNode),
nodesByPub: make(map[string]*HarnessNode),
lndErrorChan: make(chan error),
netParams: lndHarness.Miner().ActiveNet,
Miner: lndHarness.Miner(),
LNDHarness: lndHarness,
BackendCfg: b,
litdBinary: litdBinary,
feeService: feeService,
backwardCompat: backwardCompat,
}
return &n, nil
}
@ -373,7 +379,7 @@ func (n *NetworkHarness) newNode(t *testing.T, name string, extraArgs,
n.activeNodes[node.NodeID] = node
n.mtx.Unlock()
err = node.Start(n.litdBinary, n.lndErrorChan, wait)
err = node.Start(n.litdBinary, n.backwardCompat, n.lndErrorChan, wait)
if err != nil {
return nil, err
}
@ -767,7 +773,10 @@ func (n *NetworkHarness) RestartNodeNoUnlock(node *HarnessNode,
}
}
return node.Start(n.litdBinary, n.lndErrorChan, wait, litArgOpts...)
return node.Start(
n.litdBinary, n.backwardCompat, n.lndErrorChan, wait,
litArgOpts...,
)
}
// SuspendNode stops the given node and returns a callback that can be used to
@ -778,7 +787,9 @@ func (n *NetworkHarness) SuspendNode(node *HarnessNode) (func() error, error) {
}
restart := func() error {
return node.Start(n.litdBinary, n.lndErrorChan, true)
return node.Start(
n.litdBinary, n.backwardCompat, n.lndErrorChan, true,
)
}
return restart, nil

View file

@ -129,6 +129,12 @@ type testCase struct {
test func(ctx context.Context, net *NetworkHarness,
t *harnessTest)
noAliceBob bool
// backwardCompat is a map of node names to the version they are going
// to be downgraded to during the specific test. Make sure to update the
// LITD_COMPAT_VERSIONS variable in the Makefile to include all versions
// used for any backward compatibility tests.
backwardCompat map[string]string
}
// waitForNTxsInMempool polls until finding the desired number of transactions