Skip to content

Commit

Permalink
Merge 998fc9f into 2e2da11
Browse files Browse the repository at this point in the history
  • Loading branch information
cjamthagen committed Apr 8, 2017
2 parents 2e2da11 + 998fc9f commit 645655d
Show file tree
Hide file tree
Showing 4 changed files with 425 additions and 34 deletions.
116 changes: 102 additions & 14 deletions channeldb/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,19 @@ var (
// sequential prefix scans, and second to eliminate write amplification
// caused by serializing/deserializing the *entire* struct with each
// update.
chanCapacityPrefix = []byte("ccp")
selfBalancePrefix = []byte("sbp")
theirBalancePrefix = []byte("tbp")
minFeePerKbPrefix = []byte("mfp")
theirDustLimitPrefix = []byte("tdlp")
ourDustLimitPrefix = []byte("odlp")
updatePrefix = []byte("uup")
satSentPrefix = []byte("ssp")
satReceivedPrefix = []byte("srp")
netFeesPrefix = []byte("ntp")
isPendingPrefix = []byte("pdg")
chanCapacityPrefix = []byte("ccp")
selfBalancePrefix = []byte("sbp")
theirBalancePrefix = []byte("tbp")
minFeePerKbPrefix = []byte("mfp")
theirDustLimitPrefix = []byte("tdlp")
ourDustLimitPrefix = []byte("odlp")
theirChanReservePrefix = []byte("tcrp")
ourChanReservePrefix = []byte("ocrp")
updatePrefix = []byte("uup")
satSentPrefix = []byte("ssp")
satReceivedPrefix = []byte("srp")
netFeesPrefix = []byte("ntp")
isPendingPrefix = []byte("pdg")

// chanIDKey stores the node, and channelID for an active channel.
chanIDKey = []byte("cik")
Expand Down Expand Up @@ -151,6 +153,14 @@ type OpenChannel struct {
// this amount are not enforceable onchain from out point of view.
OurDustLimit btcutil.Amount

// TheirChannelReserve is the threshold which our counterparts channel
// balance is not allowed to fall below.
TheirChannelReserve btcutil.Amount

// OurChannelReserve is the threshold which our channel balance is not
// allowed to fall below.
OurChannelReserve btcutil.Amount

// OurCommitKey is the key to be used within our commitment transaction
// to generate the scripts for outputs paying to ourself, and
// revocation clauses.
Expand Down Expand Up @@ -728,9 +738,10 @@ type ChannelSnapshot struct {

ChannelPoint *wire.OutPoint

Capacity btcutil.Amount
LocalBalance btcutil.Amount
RemoteBalance btcutil.Amount
Capacity btcutil.Amount
LocalBalance btcutil.Amount
RemoteBalance btcutil.Amount
ChannelReserve btcutil.Amount

NumUpdates uint64

Expand All @@ -753,6 +764,7 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot {
Capacity: c.Capacity,
LocalBalance: c.OurBalance,
RemoteBalance: c.TheirBalance,
ChannelReserve: c.OurChannelReserve,
NumUpdates: c.NumUpdates,
TotalSatoshisSent: c.TotalSatoshisSent,
TotalSatoshisReceived: c.TotalSatoshisReceived,
Expand Down Expand Up @@ -802,6 +814,12 @@ func putOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
if err := putChanOurDustLimit(openChanBucket, channel); err != nil {
return err
}
if err := putChanTheirChannelReserve(openChanBucket, channel); err != nil {
return err
}
if err := putChanOurChannelReserve(openChanBucket, channel); err != nil {
return err
}
if err := putChanNumUpdates(openChanBucket, channel); err != nil {
return err
}
Expand Down Expand Up @@ -889,6 +907,12 @@ func fetchOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
if err = fetchChanOurDustLimit(openChanBucket, channel); err != nil {
return nil, fmt.Errorf("unable to read their dust limit: %v", err)
}
if err = fetchChanTheirChannelReserve(openChanBucket, channel); err != nil {
return nil, err
}
if err = fetchChanOurChannelReserve(openChanBucket, channel); err != nil {
return nil, err
}
if err = fetchChanNumUpdates(openChanBucket, channel); err != nil {
return nil, fmt.Errorf("unable to read num updates: %v", err)
}
Expand Down Expand Up @@ -1078,6 +1102,38 @@ func putChanOurDustLimit(openChanBucket *bolt.Bucket, channel *OpenChannel) erro
return openChanBucket.Put(keyPrefix, scratch)
}

func putChanTheirChannelReserve(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
scratch := make([]byte, 8)
byteOrder.PutUint64(scratch, uint64(channel.TheirChannelReserve))

var b bytes.Buffer
if err := writeOutpoint(&b, channel.ChanID); err != nil {
return err
}

keyPrefix := make([]byte, 4+b.Len())
copy(keyPrefix, theirChanReservePrefix)
copy(keyPrefix[4:], b.Bytes())

return openChanBucket.Put(keyPrefix, scratch)
}

func putChanOurChannelReserve(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
scratch := make([]byte, 8)
byteOrder.PutUint64(scratch, uint64(channel.OurChannelReserve))

var b bytes.Buffer
if err := writeOutpoint(&b, channel.ChanID); err != nil {
return err
}

keyPrefix := make([]byte, 4+b.Len())
copy(keyPrefix, ourChanReservePrefix)
copy(keyPrefix[4:], b.Bytes())

return openChanBucket.Put(keyPrefix, scratch)
}

func deleteChanMinFeePerKb(openChanBucket *bolt.Bucket, chanID []byte) error {
keyPrefix := make([]byte, 3+len(chanID))
copy(keyPrefix, minFeePerKbPrefix)
Expand Down Expand Up @@ -1149,6 +1205,38 @@ func deleteChanOurDustLimit(openChanBucket *bolt.Bucket, chanID []byte) error {
return openChanBucket.Delete(ourDustKey)
}

func fetchChanTheirChannelReserve(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
var b bytes.Buffer
if err := writeOutpoint(&b, channel.ChanID); err != nil {
return err
}

keyPrefix := make([]byte, 4+b.Len())
copy(keyPrefix, theirChanReservePrefix)
copy(keyPrefix[4:], b.Bytes())

chanReserveBytes := openChanBucket.Get(keyPrefix)
channel.TheirChannelReserve = btcutil.Amount(byteOrder.Uint64(chanReserveBytes))

return nil
}

func fetchChanOurChannelReserve(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
var b bytes.Buffer
if err := writeOutpoint(&b, channel.ChanID); err != nil {
return err
}

keyPrefix := make([]byte, 4+b.Len())
copy(keyPrefix, ourChanReservePrefix)
copy(keyPrefix[4:], b.Bytes())

chanReserveBytes := openChanBucket.Get(keyPrefix)
channel.OurChannelReserve = btcutil.Amount(byteOrder.Uint64(chanReserveBytes))

return nil
}

func putChanNumUpdates(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
scratch := make([]byte, 8)
byteOrder.PutUint64(scratch, channel.NumUpdates)
Expand Down
2 changes: 1 addition & 1 deletion htlcswitch.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ func (h *htlcSwitch) handleRegisterLink(req *registerLinkMsg) {
chanPoint := req.linkInfo.ChannelPoint
newLink := &link{
capacity: req.linkInfo.Capacity,
availableBandwidth: int64(req.linkInfo.LocalBalance),
availableBandwidth: int64(req.linkInfo.LocalBalance - req.linkInfo.ChannelReserve),
peer: req.peer,
chanPoint: chanPoint,
}
Expand Down
37 changes: 30 additions & 7 deletions lnwallet/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ var (
// maximum number of allowed HTLC's if committed in a state transition
ErrMaxHTLCNumber = fmt.Errorf("commitment transaction exceed max " +
"htlc number")

// ErrChanReserveBreach is returned when the remote peer tries to
// add a HTLC that will put them under their channel reserve limit.
ErrChanReserveBreach = fmt.Errorf("channel reserve threshold breached")
)

const (
Expand Down Expand Up @@ -1514,7 +1518,7 @@ func (lc *LightningChannel) SignNextCommitment() ([]byte, error) {
// party set up when we initially set up the channel. If we are, then
// we'll abort this state transition.
err := lc.validateCommitmentSanity(lc.remoteUpdateLog.ackedIndex,
lc.localUpdateLog.logIndex, false)
lc.localUpdateLog.logIndex, false, 0)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1581,36 +1585,55 @@ func (lc *LightningChannel) SignNextCommitment() ([]byte, error) {
// validateCommitmentSanity is used to validate that on current state the commitment
// transaction is valid in terms of propagating it over Bitcoin network, and
// also that all outputs are meet Bitcoin spec requirements and they are
// spendable.
// spendable. Channel policies are also checked here, such as ensuring that
// the channel reserve limit is enforced.
func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
ourLogCounter uint64, prediction bool) error {
ourLogCounter uint64, prediction bool, amt btcutil.Amount) error {

htlcCount := 0
sum := amt

if prediction {
htlcCount++
}

// Run through all the HTLCs that will be covered by this transaction
// in order to calculate theirs count.
// in order to calculate their count and total value.
htlcView := lc.fetchHTLCView(theirLogCounter, ourLogCounter)

for _, entry := range htlcView.ourUpdates {
if entry.EntryType == Add {
htlcCount++
} else {
if entry.EntryType == Fail &&
entry.removeCommitHeightLocal == 0 {
sum -= entry.Amount
}
htlcCount--
}
}

for _, entry := range htlcView.theirUpdates {
if entry.EntryType == Add {
htlcCount++
if entry.addCommitHeightRemote == 0 {
sum += entry.Amount
}
} else {
if entry.EntryType == Settle &&
entry.addCommitHeightLocal == 0 {
sum -= entry.Amount
}
htlcCount--
}
}

// We only have to check the reserve limit when we receive an HTLC.
if amt != 0 && lc.channelState.TheirBalance-sum <
lc.channelState.TheirChannelReserve {
return ErrChanReserveBreach
}

if htlcCount > MaxHTLCNumber {
return ErrMaxHTLCNumber
}
Expand All @@ -1634,7 +1657,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(rawSig []byte) error {
// the constraints we specified during initial channel setup. If not,
// then we'll abort the channel as they've violated our constraints.
err := lc.validateCommitmentSanity(lc.remoteUpdateLog.logIndex,
lc.localUpdateLog.ackedIndex, false)
lc.localUpdateLog.ackedIndex, false, 0)
if err != nil {
return err
}
Expand Down Expand Up @@ -1988,7 +2011,7 @@ func (lc *LightningChannel) AddHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, error)
defer lc.Unlock()

if err := lc.validateCommitmentSanity(lc.remoteUpdateLog.logIndex,
lc.localUpdateLog.logIndex, true); err != nil {
lc.localUpdateLog.logIndex, true, 0); err != nil {
return 0, err
}

Expand All @@ -2015,7 +2038,7 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, err
defer lc.Unlock()

if err := lc.validateCommitmentSanity(lc.remoteUpdateLog.logIndex,
lc.localUpdateLog.logIndex, true); err != nil {
lc.localUpdateLog.logIndex, true, htlc.Amount); err != nil {
return 0, err
}

Expand Down

0 comments on commit 645655d

Please sign in to comment.