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).
This commit is contained in:
Olaoluwa Osuntokun 2019-10-30 19:24:49 -07:00
parent fcf81ed8ff
commit a73ee28e46
No known key found for this signature in database
GPG Key ID: BC13F65E2DC84465
14 changed files with 42 additions and 39 deletions

@ -1865,7 +1865,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa
IdentityPub: aliceKeyPub, IdentityPub: aliceKeyPub,
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ShortChannelID: shortChanID, ShortChannelID: shortChanID,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: true, IsInitiator: true,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: bobCommitPoint, RemoteCurrentRevocation: bobCommitPoint,
@ -1883,7 +1883,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa
IdentityPub: bobKeyPub, IdentityPub: bobKeyPub,
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ShortChannelID: shortChanID, ShortChannelID: shortChanID,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: false, IsInitiator: false,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: aliceCommitPoint, RemoteCurrentRevocation: aliceCommitPoint,

@ -124,9 +124,9 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) {
isInitiator = true isInitiator = true
} }
chanType := channeldb.SingleFunder chanType := channeldb.SingleFunderBit
if rand.Int63()%2 == 0 { if rand.Int63()%2 == 0 {
chanType = channeldb.SingleFunderTweakless chanType = channeldb.SingleFunderTweaklessBit
} }
return &channeldb.OpenChannel{ return &channeldb.OpenChannel{

@ -125,39 +125,45 @@ var (
// ChannelType is an enum-like type that describes one of several possible // 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 types. Each open channel is associated with a particular type as the
// channel type may determine how higher level operations are conducted such as // channel type may determine how higher level operations are conducted such as
// fee negotiation, channel closing, the format of HTLCs, etc. // fee negotiation, channel closing, the format of HTLCs, etc. Structure-wise,
// TODO(roasbeef): split up per-chain? // a ChannelType is a bit field, with each bit denoting a modification from the
// base channel type of single funder.
type ChannelType uint8 type ChannelType uint8
const ( const (
// NOTE: iota isn't used here for this enum needs to be stable // NOTE: iota isn't used here for this enum needs to be stable
// long-term as it will be persisted to the database. // long-term as it will be persisted to the database.
// SingleFunder represents a channel wherein one party solely funds the // SingleFunderBit represents a channel wherein one party solely funds
// entire capacity of the channel. // the entire capacity of the channel.
SingleFunder ChannelType = 0 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 // funds towards the total capacity of the channel. The channel may be
// funded symmetrically or asymmetrically. // funded symmetrically or asymmetrically.
DualFunder ChannelType = 1 DualFunderBit ChannelType = 1 << 0
// SingleFunderTweakless is similar to the basic SingleFunder channel // SingleFunderTweakless is similar to the basic SingleFunder channel
// type, but it omits the tweak for one's key in the commitment // type, but it omits the tweak for one's key in the commitment
// transaction of the remote party. // 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 // IsSingleFunder returns true if the channel type if one of the known single
// funder variants. // funder variants.
func (c ChannelType) IsSingleFunder() bool { 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 // IsTweakless returns true if the target channel uses a commitment that
// doesn't tweak the key for the remote party. // doesn't tweak the key for the remote party.
func (c ChannelType) IsTweakless() bool { func (c ChannelType) IsTweakless() bool {
return c == SingleFunderTweakless return c&SingleFunderTweaklessBit == SingleFunderTweaklessBit
} }
// ChannelConstraints represents a set of constraints meant to allow a node to // ChannelConstraints represents a set of constraints meant to allow a node to

@ -187,7 +187,7 @@ func createTestChannelState(cdb *DB) (*OpenChannel, error) {
chanID := lnwire.NewShortChanIDFromInt(uint64(rand.Int63())) chanID := lnwire.NewShortChanIDFromInt(uint64(rand.Int63()))
return &OpenChannel{ return &OpenChannel{
ChanType: SingleFunder, ChanType: SingleFunderBit,
ChainHash: key, ChainHash: key,
FundingOutpoint: wire.OutPoint{Hash: key, Index: rand.Uint32()}, FundingOutpoint: wire.OutPoint{Hash: key, Index: rand.Uint32()},
ShortChannelID: chanID, ShortChannelID: chanID,

@ -87,10 +87,10 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) (
switch backup.Version { switch backup.Version {
case chanbackup.DefaultSingleVersion: case chanbackup.DefaultSingleVersion:
chanType = channeldb.SingleFunder chanType = channeldb.SingleFunderBit
case chanbackup.TweaklessCommitVersion: case chanbackup.TweaklessCommitVersion:
chanType = channeldb.SingleFunderTweakless chanType = channeldb.SingleFunderTweaklessBit
default: default:
return nil, fmt.Errorf("unknown Single version: %v", err) return nil, fmt.Errorf("unknown Single version: %v", err)

@ -521,7 +521,7 @@ func (f *fundingManager) start() error {
// Rebroadcast the funding transaction for any pending // Rebroadcast the funding transaction for any pending
// channel that we initiated. No error will be returned // channel that we initiated. No error will be returned
// if the transaction already has been broadcasted. // if the transaction already has been broadcasted.
if channel.ChanType == channeldb.SingleFunder && if channel.ChanType.IsSingleFunder() &&
channel.IsInitiator { channel.IsInitiator {
err := f.cfg.PublishTransaction( err := f.cfg.PublishTransaction(

@ -1860,11 +1860,9 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
} }
chanType := l.channel.State().ChanType chanType := l.channel.State().ChanType
isTweakless := chanType == channeldb.SingleFunderTweakless
chanID := l.ChanID() chanID := l.ChanID()
err = l.cfg.TowerClient.BackupState( err = l.cfg.TowerClient.BackupState(
&chanID, breachInfo, isTweakless, &chanID, breachInfo, chanType.IsTweakless(),
) )
if err != nil { if err != nil {
l.fail(LinkFailureError{code: ErrInternalError}, l.fail(LinkFailureError{code: ErrInternalError},

@ -328,7 +328,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
RemoteChanCfg: bobCfg, RemoteChanCfg: bobCfg,
IdentityPub: aliceKeyPub, IdentityPub: aliceKeyPub,
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: true, IsInitiator: true,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: bobCommitPoint, RemoteCurrentRevocation: bobCommitPoint,
@ -347,7 +347,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
RemoteChanCfg: aliceCfg, RemoteChanCfg: aliceCfg,
IdentityPub: bobKeyPub, IdentityPub: bobKeyPub,
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: false, IsInitiator: false,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: aliceCommitPoint, RemoteCurrentRevocation: aliceCommitPoint,

@ -868,8 +868,7 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
// If this commit is tweakless, then it'll affect the way we derive our // If this commit is tweakless, then it'll affect the way we derive our
// keys, which will affect the commitment transaction reconstruction. // keys, which will affect the commitment transaction reconstruction.
// So we'll determine this first, before we do anything else. // So we'll determine this first, before we do anything else.
tweaklessCommit := (lc.channelState.ChanType == tweaklessCommit := lc.channelState.ChanType.IsTweakless()
channeldb.SingleFunderTweakless)
// First, we'll need to re-derive the commitment key ring for each // 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 // party used within this particular state. If this is a pending commit

@ -511,7 +511,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness,
if !bytes.Equal(aliceChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) { if !bytes.Equal(aliceChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
t.Fatalf("channel state not properly saved") 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") t.Fatalf("channel not detected as dual funder")
} }
bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub) bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub)
@ -521,7 +521,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness,
if !bytes.Equal(bobChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) { if !bytes.Equal(bobChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
t.Fatalf("channel state not properly saved") 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") t.Fatalf("channel not detected as dual funder")
} }
@ -971,7 +971,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
} }
if !aliceChannels[0].ChanType.IsSingleFunder() { if !aliceChannels[0].ChanType.IsSingleFunder() {
t.Fatalf("channel type is incorrect, expected %v instead got %v", 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) bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub)
@ -991,7 +991,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
} }
if !bobChannels[0].ChanType.IsSingleFunder() { if !bobChannels[0].ChanType.IsSingleFunder() {
t.Fatalf("channel type is incorrect, expected %v instead got %v", 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. // Let Alice publish the funding transaction.

@ -215,15 +215,15 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
// a single-funder channel. // a single-funder channel.
if ourBalance == 0 || theirBalance == 0 || pushMSat != 0 { if ourBalance == 0 || theirBalance == 0 || pushMSat != 0 {
if tweaklessCommit { if tweaklessCommit {
chanType = channeldb.SingleFunderTweakless chanType |= channeldb.SingleFunderTweaklessBit
} else { } else {
chanType = channeldb.SingleFunder chanType |= channeldb.SingleFunderBit
} }
} else { } else {
// Otherwise, this is a dual funder channel, and no side is // Otherwise, this is a dual funder channel, and no side is
// technically the "initiator" // technically the "initiator"
initiator = false initiator = false
chanType = channeldb.DualFunder chanType |= channeldb.DualFunderBit
} }
return &ChannelReservation{ return &ChannelReservation{

@ -274,7 +274,7 @@ func CreateTestChannels(tweaklessCommits bool) (
IdentityPub: aliceKeys[0].PubKey(), IdentityPub: aliceKeys[0].PubKey(),
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ShortChannelID: shortChanID, ShortChannelID: shortChanID,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: true, IsInitiator: true,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: bobCommitPoint, RemoteCurrentRevocation: bobCommitPoint,
@ -292,7 +292,7 @@ func CreateTestChannels(tweaklessCommits bool) (
IdentityPub: bobKeys[0].PubKey(), IdentityPub: bobKeys[0].PubKey(),
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ShortChannelID: shortChanID, ShortChannelID: shortChanID,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: false, IsInitiator: false,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: aliceCommitPoint, RemoteCurrentRevocation: aliceCommitPoint,
@ -305,8 +305,8 @@ func CreateTestChannels(tweaklessCommits bool) (
} }
if !tweaklessCommits { if !tweaklessCommits {
aliceChannelState.ChanType = channeldb.SingleFunder aliceChannelState.ChanType = channeldb.SingleFunderBit
bobChannelState.ChanType = channeldb.SingleFunder bobChannelState.ChanType = channeldb.SingleFunderBit
} }
aliceSigner := &input.MockSigner{Privkeys: aliceKeys} aliceSigner := &input.MockSigner{Privkeys: aliceKeys}

@ -370,7 +370,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
// Manually construct a new LightningChannel. // Manually construct a new LightningChannel.
channelState := channeldb.OpenChannel{ channelState := channeldb.OpenChannel{
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
ChainHash: *tc.netParams.GenesisHash, ChainHash: *tc.netParams.GenesisHash,
FundingOutpoint: tc.fundingOutpoint, FundingOutpoint: tc.fundingOutpoint,
ShortChannelID: tc.shortChanID, ShortChannelID: tc.shortChanID,

@ -255,7 +255,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
IdentityPub: aliceKeyPub, IdentityPub: aliceKeyPub,
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ShortChannelID: shortChanID, ShortChannelID: shortChanID,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: true, IsInitiator: true,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: bobCommitPoint, RemoteCurrentRevocation: bobCommitPoint,
@ -272,7 +272,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
RemoteChanCfg: aliceCfg, RemoteChanCfg: aliceCfg,
IdentityPub: bobKeyPub, IdentityPub: bobKeyPub,
FundingOutpoint: *prevOut, FundingOutpoint: *prevOut,
ChanType: channeldb.SingleFunderTweakless, ChanType: channeldb.SingleFunderTweaklessBit,
IsInitiator: false, IsInitiator: false,
Capacity: channelCapacity, Capacity: channelCapacity,
RemoteCurrentRevocation: aliceCommitPoint, RemoteCurrentRevocation: aliceCommitPoint,