From a73ee28e466f6cba29bb98f61492eea6a8880c91 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 30 Oct 2019 19:24:49 -0700 Subject: [PATCH] multi: convert the existing channeldb.ChannelType uint8 into a bit field In this commit, we convert the existing `channeldb.ChannelType` type into a _bit field_. This doesn't require us to change the current serialization or interpretation or the type as it is, since all the current defined values us a distinct bit. This PR lays the ground work for any future changes that may introduce new channel types (like anchor outputs), and also any changes that may modify the existing invariants around channels (if we're the initiator, we always have the funding transaction). --- breacharbiter_test.go | 4 ++-- chanbackup/single_test.go | 4 ++-- channeldb/channel.go | 26 ++++++++++++++++---------- channeldb/channel_test.go | 2 +- chanrestore.go | 4 ++-- fundingmanager.go | 2 +- htlcswitch/link.go | 4 +--- htlcswitch/test_utils.go | 4 ++-- lnwallet/channel.go | 3 +-- lnwallet/interface_test.go | 8 ++++---- lnwallet/reservation.go | 6 +++--- lnwallet/test_utils.go | 8 ++++---- lnwallet/transactions_test.go | 2 +- test_utils.go | 4 ++-- 14 files changed, 42 insertions(+), 39 deletions(-) diff --git a/breacharbiter_test.go b/breacharbiter_test.go index 7f471ea2..724643ae 100644 --- a/breacharbiter_test.go +++ b/breacharbiter_test.go @@ -1865,7 +1865,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: true, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, @@ -1883,7 +1883,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: false, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint, diff --git a/chanbackup/single_test.go b/chanbackup/single_test.go index ba56ece7..776ce0bc 100644 --- a/chanbackup/single_test.go +++ b/chanbackup/single_test.go @@ -124,9 +124,9 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { isInitiator = true } - chanType := channeldb.SingleFunder + chanType := channeldb.SingleFunderBit if rand.Int63()%2 == 0 { - chanType = channeldb.SingleFunderTweakless + chanType = channeldb.SingleFunderTweaklessBit } return &channeldb.OpenChannel{ diff --git a/channeldb/channel.go b/channeldb/channel.go index 7bc9e480..1fdd97e9 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -125,39 +125,45 @@ var ( // ChannelType is an enum-like type that describes one of several possible // channel types. Each open channel is associated with a particular type as the // channel type may determine how higher level operations are conducted such as -// fee negotiation, channel closing, the format of HTLCs, etc. -// TODO(roasbeef): split up per-chain? +// fee negotiation, channel closing, the format of HTLCs, etc. Structure-wise, +// a ChannelType is a bit field, with each bit denoting a modification from the +// base channel type of single funder. type ChannelType uint8 const ( // NOTE: iota isn't used here for this enum needs to be stable // long-term as it will be persisted to the database. - // SingleFunder represents a channel wherein one party solely funds the - // entire capacity of the channel. - SingleFunder ChannelType = 0 + // SingleFunderBit represents a channel wherein one party solely funds + // the entire capacity of the channel. + SingleFunderBit ChannelType = 0 - // DualFunder represents a channel wherein both parties contribute + // DualFunderBit represents a channel wherein both parties contribute // funds towards the total capacity of the channel. The channel may be // funded symmetrically or asymmetrically. - DualFunder ChannelType = 1 + DualFunderBit ChannelType = 1 << 0 // SingleFunderTweakless is similar to the basic SingleFunder channel // type, but it omits the tweak for one's key in the commitment // transaction of the remote party. - SingleFunderTweakless ChannelType = 2 + SingleFunderTweaklessBit ChannelType = 1 << 1 ) // IsSingleFunder returns true if the channel type if one of the known single // funder variants. func (c ChannelType) IsSingleFunder() bool { - return c == SingleFunder || c == SingleFunderTweakless + return c&DualFunderBit == 0 +} + +// IsDualFunder returns true if the ChannelType has the DualFunderBit set. +func (c ChannelType) IsDualFunder() bool { + return c&DualFunderBit == DualFunderBit } // IsTweakless returns true if the target channel uses a commitment that // doesn't tweak the key for the remote party. func (c ChannelType) IsTweakless() bool { - return c == SingleFunderTweakless + return c&SingleFunderTweaklessBit == SingleFunderTweaklessBit } // ChannelConstraints represents a set of constraints meant to allow a node to diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index 21bb738c..6d34c2f9 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -187,7 +187,7 @@ func createTestChannelState(cdb *DB) (*OpenChannel, error) { chanID := lnwire.NewShortChanIDFromInt(uint64(rand.Int63())) return &OpenChannel{ - ChanType: SingleFunder, + ChanType: SingleFunderBit, ChainHash: key, FundingOutpoint: wire.OutPoint{Hash: key, Index: rand.Uint32()}, ShortChannelID: chanID, diff --git a/chanrestore.go b/chanrestore.go index 6196aed5..5586ab92 100644 --- a/chanrestore.go +++ b/chanrestore.go @@ -87,10 +87,10 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) ( switch backup.Version { case chanbackup.DefaultSingleVersion: - chanType = channeldb.SingleFunder + chanType = channeldb.SingleFunderBit case chanbackup.TweaklessCommitVersion: - chanType = channeldb.SingleFunderTweakless + chanType = channeldb.SingleFunderTweaklessBit default: return nil, fmt.Errorf("unknown Single version: %v", err) diff --git a/fundingmanager.go b/fundingmanager.go index c18df5ab..4275338c 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -521,7 +521,7 @@ func (f *fundingManager) start() error { // Rebroadcast the funding transaction for any pending // channel that we initiated. No error will be returned // if the transaction already has been broadcasted. - if channel.ChanType == channeldb.SingleFunder && + if channel.ChanType.IsSingleFunder() && channel.IsInitiator { err := f.cfg.PublishTransaction( diff --git a/htlcswitch/link.go b/htlcswitch/link.go index c0b62633..b2ffe87c 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -1860,11 +1860,9 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { } chanType := l.channel.State().ChanType - isTweakless := chanType == channeldb.SingleFunderTweakless - chanID := l.ChanID() err = l.cfg.TowerClient.BackupState( - &chanID, breachInfo, isTweakless, + &chanID, breachInfo, chanType.IsTweakless(), ) if err != nil { l.fail(LinkFailureError{code: ErrInternalError}, diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 3c11c3fd..5ff59566 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -328,7 +328,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, RemoteChanCfg: bobCfg, IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: true, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, @@ -347,7 +347,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, RemoteChanCfg: aliceCfg, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: false, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint, diff --git a/lnwallet/channel.go b/lnwallet/channel.go index f9d07787..b199efe5 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -868,8 +868,7 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool, // If this commit is tweakless, then it'll affect the way we derive our // keys, which will affect the commitment transaction reconstruction. // So we'll determine this first, before we do anything else. - tweaklessCommit := (lc.channelState.ChanType == - channeldb.SingleFunderTweakless) + tweaklessCommit := lc.channelState.ChanType.IsTweakless() // First, we'll need to re-derive the commitment key ring for each // party used within this particular state. If this is a pending commit diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go index 04af443f..d998c0a0 100644 --- a/lnwallet/interface_test.go +++ b/lnwallet/interface_test.go @@ -511,7 +511,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, if !bytes.Equal(aliceChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) { t.Fatalf("channel state not properly saved") } - if aliceChannels[0].ChanType != channeldb.DualFunder { + if !aliceChannels[0].ChanType.IsDualFunder() { t.Fatalf("channel not detected as dual funder") } bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub) @@ -521,7 +521,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, if !bytes.Equal(bobChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) { t.Fatalf("channel state not properly saved") } - if bobChannels[0].ChanType != channeldb.DualFunder { + if !bobChannels[0].ChanType.IsDualFunder() { t.Fatalf("channel not detected as dual funder") } @@ -971,7 +971,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, } if !aliceChannels[0].ChanType.IsSingleFunder() { t.Fatalf("channel type is incorrect, expected %v instead got %v", - channeldb.SingleFunder, aliceChannels[0].ChanType) + channeldb.SingleFunderBit, aliceChannels[0].ChanType) } bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub) @@ -991,7 +991,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, } if !bobChannels[0].ChanType.IsSingleFunder() { t.Fatalf("channel type is incorrect, expected %v instead got %v", - channeldb.SingleFunder, bobChannels[0].ChanType) + channeldb.SingleFunderBit, bobChannels[0].ChanType) } // Let Alice publish the funding transaction. diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index b96651ff..465a9b41 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -215,15 +215,15 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // a single-funder channel. if ourBalance == 0 || theirBalance == 0 || pushMSat != 0 { if tweaklessCommit { - chanType = channeldb.SingleFunderTweakless + chanType |= channeldb.SingleFunderTweaklessBit } else { - chanType = channeldb.SingleFunder + chanType |= channeldb.SingleFunderBit } } else { // Otherwise, this is a dual funder channel, and no side is // technically the "initiator" initiator = false - chanType = channeldb.DualFunder + chanType |= channeldb.DualFunderBit } return &ChannelReservation{ diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index efb30ac1..324064ff 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -274,7 +274,7 @@ func CreateTestChannels(tweaklessCommits bool) ( IdentityPub: aliceKeys[0].PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: true, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, @@ -292,7 +292,7 @@ func CreateTestChannels(tweaklessCommits bool) ( IdentityPub: bobKeys[0].PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: false, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint, @@ -305,8 +305,8 @@ func CreateTestChannels(tweaklessCommits bool) ( } if !tweaklessCommits { - aliceChannelState.ChanType = channeldb.SingleFunder - bobChannelState.ChanType = channeldb.SingleFunder + aliceChannelState.ChanType = channeldb.SingleFunderBit + bobChannelState.ChanType = channeldb.SingleFunderBit } aliceSigner := &input.MockSigner{Privkeys: aliceKeys} diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index ed4c533d..9fdacc07 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -370,7 +370,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) { // Manually construct a new LightningChannel. channelState := channeldb.OpenChannel{ - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, ChainHash: *tc.netParams.GenesisHash, FundingOutpoint: tc.fundingOutpoint, ShortChannelID: tc.shortChanID, diff --git a/test_utils.go b/test_utils.go index 671bc0f4..06f3767d 100644 --- a/test_utils.go +++ b/test_utils.go @@ -255,7 +255,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: true, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, @@ -272,7 +272,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, RemoteChanCfg: aliceCfg, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, - ChanType: channeldb.SingleFunderTweakless, + ChanType: channeldb.SingleFunderTweaklessBit, IsInitiator: false, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint,