Merge pull request #6831 from bottlepay/interceptor-watchdog
htlcswitch: interceptor watchdog
This commit is contained in:
13 files changed
+918
-374
No files matched your search
@@ -28,7 +28,14 @@
|
|||||||
Similar to TrackPaymentV2, but for any inflight payment.
|
Similar to TrackPaymentV2, but for any inflight payment.
|
||||||
|
|
||||||
* [Catch and throw an error](https://github.com/lightningnetwork/lnd/pull/6945)
|
* [Catch and throw an error](https://github.com/lightningnetwork/lnd/pull/6945)
|
||||||
during `openchannel` if the local funding amount given is zero.
|
during `openchannel` if the local funding amount given is zero.
|
||||||
|
|
||||||
|
* [Extend](https://github.com/lightningnetwork/lnd/pull/6831) the HTLC
|
||||||
|
interceptor server implementation with watchdog functionality to cancel back
|
||||||
|
HTLCs for which an interceptor client does not provide a resolution in time.
|
||||||
|
If an HTLC expires, the counterparty will claim it back on-chain and the
|
||||||
|
receiver will lose it. Therefore the receiver can just as well fail off-chain
|
||||||
|
a few blocks before so that the channel is saved.
|
||||||
|
|
||||||
* [Make remote channel reserve amount configurable for
|
* [Make remote channel reserve amount configurable for
|
||||||
`openchannel`](https://github.com/lightningnetwork/lnd/pull/6956)
|
`openchannel`](https://github.com/lightningnetwork/lnd/pull/6956)
|
||||||
@@ -167,6 +174,7 @@ details.
|
|||||||
* Graham Krizek
|
* Graham Krizek
|
||||||
* hieblmi
|
* hieblmi
|
||||||
* Jesse de Wit
|
* Jesse de Wit
|
||||||
|
* Joost Jager
|
||||||
* Jordi Montes
|
* Jordi Montes
|
||||||
* Matt Morehouse
|
* Matt Morehouse
|
||||||
* Michael Street
|
* Michael Street
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package htlcswitch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// heldHtlcSet keeps track of outstanding intercepted forwards. It exposes
|
||||||
|
// several methods to manipulate the underlying map structure in a consistent
|
||||||
|
// way.
|
||||||
|
type heldHtlcSet struct {
|
||||||
|
set map[channeldb.CircuitKey]InterceptedForward
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHeldHtlcSet() *heldHtlcSet {
|
||||||
|
return &heldHtlcSet{
|
||||||
|
set: make(map[channeldb.CircuitKey]InterceptedForward),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// forEach iterates over all held forwards and calls the given callback for each
|
||||||
|
// of them.
|
||||||
|
func (h *heldHtlcSet) forEach(cb func(InterceptedForward)) {
|
||||||
|
for _, fwd := range h.set {
|
||||||
|
cb(fwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// popAll calls the callback for each forward and removes them from the set.
|
||||||
|
func (h *heldHtlcSet) popAll(cb func(InterceptedForward)) {
|
||||||
|
for _, fwd := range h.set {
|
||||||
|
cb(fwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.set = make(map[channeldb.CircuitKey]InterceptedForward)
|
||||||
|
}
|
||||||
|
|
||||||
|
// popAutoFails calls the callback for each forward that has an auto-fail height
|
||||||
|
// equal or less then the specified pop height and removes them from the set.
|
||||||
|
func (h *heldHtlcSet) popAutoFails(height uint32, cb func(InterceptedForward)) {
|
||||||
|
for key, fwd := range h.set {
|
||||||
|
if uint32(fwd.Packet().AutoFailHeight) > height {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(fwd)
|
||||||
|
|
||||||
|
delete(h.set, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop returns the specified forward and removes it from the set.
|
||||||
|
func (h *heldHtlcSet) pop(key channeldb.CircuitKey) (InterceptedForward, error) {
|
||||||
|
intercepted, ok := h.set[key]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("fwd %v not found", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(h.set, key)
|
||||||
|
|
||||||
|
return intercepted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// exists tests whether the specified forward is part of the set.
|
||||||
|
func (h *heldHtlcSet) exists(key channeldb.CircuitKey) bool {
|
||||||
|
_, ok := h.set[key]
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// push adds the specified forward to the set. An error is returned if the
|
||||||
|
// forward exists already.
|
||||||
|
func (h *heldHtlcSet) push(key channeldb.CircuitKey,
|
||||||
|
fwd InterceptedForward) error {
|
||||||
|
|
||||||
|
if fwd == nil {
|
||||||
|
return errors.New("nil fwd pushed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.exists(key) {
|
||||||
|
return errors.New("htlc already exists in set")
|
||||||
|
}
|
||||||
|
|
||||||
|
h.set[key] = fwd
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package htlcswitch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHeldHtlcSetEmpty(t *testing.T) {
|
||||||
|
set := newHeldHtlcSet()
|
||||||
|
|
||||||
|
// Test operations on an empty set.
|
||||||
|
require.False(t, set.exists(channeldb.CircuitKey{}))
|
||||||
|
|
||||||
|
_, err := set.pop(channeldb.CircuitKey{})
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
set.popAll(
|
||||||
|
func(_ InterceptedForward) {
|
||||||
|
require.Fail(t, "unexpected fwd")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeldHtlcSet(t *testing.T) {
|
||||||
|
set := newHeldHtlcSet()
|
||||||
|
|
||||||
|
key := channeldb.CircuitKey{
|
||||||
|
ChanID: lnwire.NewShortChanIDFromInt(1),
|
||||||
|
HtlcID: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test pushing a nil forward.
|
||||||
|
require.Error(t, set.push(key, nil))
|
||||||
|
|
||||||
|
// Test pushing a forward.
|
||||||
|
fwd := &interceptedForward{
|
||||||
|
htlc: &lnwire.UpdateAddHTLC{},
|
||||||
|
}
|
||||||
|
require.NoError(t, set.push(key, fwd))
|
||||||
|
|
||||||
|
// Re-pushing should fail.
|
||||||
|
require.Error(t, set.push(key, fwd))
|
||||||
|
|
||||||
|
// Test popping the fwd.
|
||||||
|
poppedFwd, err := set.pop(key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, fwd, poppedFwd)
|
||||||
|
|
||||||
|
_, err = set.pop(key)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
// Pushing the forward again.
|
||||||
|
require.NoError(t, set.push(key, fwd))
|
||||||
|
|
||||||
|
// Test for each.
|
||||||
|
var cbCalled bool
|
||||||
|
set.forEach(func(_ InterceptedForward) {
|
||||||
|
cbCalled = true
|
||||||
|
|
||||||
|
require.Equal(t, fwd, poppedFwd)
|
||||||
|
})
|
||||||
|
require.True(t, cbCalled)
|
||||||
|
|
||||||
|
// Test popping all forwards.
|
||||||
|
cbCalled = false
|
||||||
|
set.popAll(
|
||||||
|
func(_ InterceptedForward) {
|
||||||
|
cbCalled = true
|
||||||
|
|
||||||
|
require.Equal(t, fwd, poppedFwd)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.True(t, cbCalled)
|
||||||
|
|
||||||
|
_, err = set.pop(key)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeldHtlcSetAutoFails(t *testing.T) {
|
||||||
|
set := newHeldHtlcSet()
|
||||||
|
|
||||||
|
key := channeldb.CircuitKey{
|
||||||
|
ChanID: lnwire.NewShortChanIDFromInt(1),
|
||||||
|
HtlcID: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
const autoFailHeight = 100
|
||||||
|
fwd := &interceptedForward{
|
||||||
|
packet: &htlcPacket{},
|
||||||
|
htlc: &lnwire.UpdateAddHTLC{},
|
||||||
|
autoFailHeight: autoFailHeight,
|
||||||
|
}
|
||||||
|
require.NoError(t, set.push(key, fwd))
|
||||||
|
|
||||||
|
// Test popping auto fails up to one block before the auto-fail height
|
||||||
|
// of our forward.
|
||||||
|
set.popAutoFails(
|
||||||
|
autoFailHeight-1,
|
||||||
|
func(_ InterceptedForward) {
|
||||||
|
require.Fail(t, "unexpected fwd")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Popping succeeds at the auto-fail height.
|
||||||
|
cbCalled := false
|
||||||
|
set.popAutoFails(
|
||||||
|
autoFailHeight,
|
||||||
|
func(poppedFwd InterceptedForward) {
|
||||||
|
cbCalled = true
|
||||||
|
|
||||||
|
require.Equal(t, fwd, poppedFwd)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.True(t, cbCalled)
|
||||||
|
|
||||||
|
// After this, there should be nothing more to pop.
|
||||||
|
set.popAutoFails(
|
||||||
|
autoFailHeight,
|
||||||
|
func(_ InterceptedForward) {
|
||||||
|
require.Fail(t, "unexpected fwd")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
@@ -20,6 +21,8 @@ var (
|
|||||||
// ErrUnsupportedFailureCode when processing of an unsupported failure
|
// ErrUnsupportedFailureCode when processing of an unsupported failure
|
||||||
// code is attempted.
|
// code is attempted.
|
||||||
ErrUnsupportedFailureCode = errors.New("unsupported failure code")
|
ErrUnsupportedFailureCode = errors.New("unsupported failure code")
|
||||||
|
|
||||||
|
errBlockStreamStopped = errors.New("block epoch stream stopped")
|
||||||
)
|
)
|
||||||
|
|
||||||
// InterceptableSwitch is an implementation of ForwardingSwitch interface.
|
// InterceptableSwitch is an implementation of ForwardingSwitch interface.
|
||||||
@@ -54,13 +57,32 @@ type InterceptableSwitch struct {
|
|||||||
// interceptor is the handler for intercepted packets.
|
// interceptor is the handler for intercepted packets.
|
||||||
interceptor ForwardInterceptor
|
interceptor ForwardInterceptor
|
||||||
|
|
||||||
// holdForwards keeps track of outstanding intercepted forwards.
|
// heldHtlcSet keeps track of outstanding intercepted forwards.
|
||||||
holdForwards map[channeldb.CircuitKey]InterceptedForward
|
heldHtlcSet *heldHtlcSet
|
||||||
|
|
||||||
// cltvRejectDelta defines the number of blocks before the expiry of the
|
// cltvRejectDelta defines the number of blocks before the expiry of the
|
||||||
// htlc where we no longer intercept it and instead cancel it back.
|
// htlc where we no longer intercept it and instead cancel it back.
|
||||||
cltvRejectDelta uint32
|
cltvRejectDelta uint32
|
||||||
|
|
||||||
|
// cltvInterceptDelta defines the number of blocks before the expiry of
|
||||||
|
// the htlc where we don't intercept anymore. This value must be greater
|
||||||
|
// than CltvRejectDelta, because we don't want to offer htlcs to the
|
||||||
|
// interceptor client for which there is no time left to resolve them
|
||||||
|
// anymore.
|
||||||
|
cltvInterceptDelta uint32
|
||||||
|
|
||||||
|
// notifier is an instance of a chain notifier that we'll use to signal
|
||||||
|
// the switch when a new block has arrived.
|
||||||
|
notifier chainntnfs.ChainNotifier
|
||||||
|
|
||||||
|
// blockEpochStream is an active block epoch event stream backed by an
|
||||||
|
// active ChainNotifier instance. This will be used to retrieve the
|
||||||
|
// latest height of the chain.
|
||||||
|
blockEpochStream *chainntnfs.BlockEpochEvent
|
||||||
|
|
||||||
|
// currentHeight is the currently best known height.
|
||||||
|
currentHeight int32
|
||||||
|
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
}
|
}
|
||||||
@@ -111,22 +133,57 @@ type fwdResolution struct {
|
|||||||
errChan chan error
|
errChan chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InterceptableSwitchConfig contains the configuration of InterceptableSwitch.
|
||||||
|
type InterceptableSwitchConfig struct {
|
||||||
|
// Switch is a reference to the actual switch implementation that
|
||||||
|
// packets get sent to on resume.
|
||||||
|
Switch *Switch
|
||||||
|
|
||||||
|
// Notifier is an instance of a chain notifier that we'll use to signal
|
||||||
|
// the switch when a new block has arrived.
|
||||||
|
Notifier chainntnfs.ChainNotifier
|
||||||
|
|
||||||
|
// CltvRejectDelta defines the number of blocks before the expiry of the
|
||||||
|
// htlc where we auto-fail an intercepted htlc to prevent channel
|
||||||
|
// force-closure.
|
||||||
|
CltvRejectDelta uint32
|
||||||
|
|
||||||
|
// CltvInterceptDelta defines the number of blocks before the expiry of
|
||||||
|
// the htlc where we don't intercept anymore. This value must be greater
|
||||||
|
// than CltvRejectDelta, because we don't want to offer htlcs to the
|
||||||
|
// interceptor client for which there is no time left to resolve them
|
||||||
|
// anymore.
|
||||||
|
CltvInterceptDelta uint32
|
||||||
|
|
||||||
|
// RequireInterceptor indicates whether processing should block if no
|
||||||
|
// interceptor is connected.
|
||||||
|
RequireInterceptor bool
|
||||||
|
}
|
||||||
|
|
||||||
// NewInterceptableSwitch returns an instance of InterceptableSwitch.
|
// NewInterceptableSwitch returns an instance of InterceptableSwitch.
|
||||||
func NewInterceptableSwitch(s *Switch, cltvRejectDelta uint32,
|
func NewInterceptableSwitch(cfg *InterceptableSwitchConfig) (
|
||||||
requireInterceptor bool) *InterceptableSwitch {
|
*InterceptableSwitch, error) {
|
||||||
|
|
||||||
|
if cfg.CltvInterceptDelta <= cfg.CltvRejectDelta {
|
||||||
|
return nil, fmt.Errorf("cltv intercept delta %v not greater "+
|
||||||
|
"than cltv reject delta %v",
|
||||||
|
cfg.CltvInterceptDelta, cfg.CltvRejectDelta)
|
||||||
|
}
|
||||||
|
|
||||||
return &InterceptableSwitch{
|
return &InterceptableSwitch{
|
||||||
htlcSwitch: s,
|
htlcSwitch: cfg.Switch,
|
||||||
intercepted: make(chan *interceptedPackets),
|
intercepted: make(chan *interceptedPackets),
|
||||||
onchainIntercepted: make(chan InterceptedForward),
|
onchainIntercepted: make(chan InterceptedForward),
|
||||||
interceptorRegistration: make(chan ForwardInterceptor),
|
interceptorRegistration: make(chan ForwardInterceptor),
|
||||||
holdForwards: make(map[channeldb.CircuitKey]InterceptedForward),
|
heldHtlcSet: newHeldHtlcSet(),
|
||||||
resolutionChan: make(chan *fwdResolution),
|
resolutionChan: make(chan *fwdResolution),
|
||||||
requireInterceptor: requireInterceptor,
|
requireInterceptor: cfg.RequireInterceptor,
|
||||||
cltvRejectDelta: cltvRejectDelta,
|
cltvRejectDelta: cfg.CltvRejectDelta,
|
||||||
|
cltvInterceptDelta: cfg.CltvInterceptDelta,
|
||||||
|
notifier: cfg.Notifier,
|
||||||
|
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInterceptor sets the ForwardInterceptor to be used. A nil argument
|
// SetInterceptor sets the ForwardInterceptor to be used. A nil argument
|
||||||
@@ -144,11 +201,20 @@ func (s *InterceptableSwitch) SetInterceptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *InterceptableSwitch) Start() error {
|
func (s *InterceptableSwitch) Start() error {
|
||||||
|
blockEpochStream, err := s.notifier.RegisterBlockEpochNtfn(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.blockEpochStream = blockEpochStream
|
||||||
|
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
|
|
||||||
s.run()
|
err := s.run()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("InterceptableSwitch stopped: %v", err)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -158,10 +224,28 @@ func (s *InterceptableSwitch) Stop() error {
|
|||||||
close(s.quit)
|
close(s.quit)
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
|
|
||||||
|
s.blockEpochStream.Cancel()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InterceptableSwitch) run() {
|
func (s *InterceptableSwitch) run() error {
|
||||||
|
// The block epoch stream will immediately stream the current height.
|
||||||
|
// Read it out here.
|
||||||
|
select {
|
||||||
|
case currentBlock, ok := <-s.blockEpochStream.Epochs:
|
||||||
|
if !ok {
|
||||||
|
return errBlockStreamStopped
|
||||||
|
}
|
||||||
|
s.currentHeight = currentBlock.Height
|
||||||
|
|
||||||
|
case <-s.quit:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("InterceptableSwitch running: height=%v, "+
|
||||||
|
"requireInterceptor=%v", s.currentHeight, s.requireInterceptor)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// An interceptor registration or de-registration came in.
|
// An interceptor registration or de-registration came in.
|
||||||
@@ -171,7 +255,14 @@ func (s *InterceptableSwitch) run() {
|
|||||||
case packets := <-s.intercepted:
|
case packets := <-s.intercepted:
|
||||||
var notIntercepted []*htlcPacket
|
var notIntercepted []*htlcPacket
|
||||||
for _, p := range packets.packets {
|
for _, p := range packets.packets {
|
||||||
if !s.interceptForward(p, packets.isReplay) {
|
intercepted, err := s.interceptForward(
|
||||||
|
p, packets.isReplay,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !intercepted {
|
||||||
notIntercepted = append(
|
notIntercepted = append(
|
||||||
notIntercepted, p,
|
notIntercepted, p,
|
||||||
)
|
)
|
||||||
@@ -192,16 +283,44 @@ func (s *InterceptableSwitch) run() {
|
|||||||
// already intercepted in the off-chain flow. And even
|
// already intercepted in the off-chain flow. And even
|
||||||
// if not, it is safe to signal replay so that we won't
|
// if not, it is safe to signal replay so that we won't
|
||||||
// unexpectedly skip over this htlc.
|
// unexpectedly skip over this htlc.
|
||||||
s.forward(fwd, true)
|
if _, err := s.forward(fwd, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
case res := <-s.resolutionChan:
|
case res := <-s.resolutionChan:
|
||||||
res.errChan <- s.resolve(res.resolution)
|
res.errChan <- s.resolve(res.resolution)
|
||||||
|
|
||||||
|
case currentBlock, ok := <-s.blockEpochStream.Epochs:
|
||||||
|
if !ok {
|
||||||
|
return errBlockStreamStopped
|
||||||
|
}
|
||||||
|
|
||||||
|
s.currentHeight = currentBlock.Height
|
||||||
|
|
||||||
|
// A new block is appended. Fail any held htlcs that
|
||||||
|
// expire at this height to prevent channel force-close.
|
||||||
|
s.failExpiredHtlcs()
|
||||||
|
|
||||||
case <-s.quit:
|
case <-s.quit:
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *InterceptableSwitch) failExpiredHtlcs() {
|
||||||
|
s.heldHtlcSet.popAutoFails(
|
||||||
|
uint32(s.currentHeight),
|
||||||
|
func(fwd InterceptedForward) {
|
||||||
|
err := fwd.FailWithCode(
|
||||||
|
lnwire.CodeTemporaryChannelFailure,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Cannot fail packet: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *InterceptableSwitch) sendForward(fwd InterceptedForward) {
|
func (s *InterceptableSwitch) sendForward(fwd InterceptedForward) {
|
||||||
err := s.interceptor(fwd.Packet())
|
err := s.interceptor(fwd.Packet())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -220,9 +339,7 @@ func (s *InterceptableSwitch) setInterceptor(interceptor ForwardInterceptor) {
|
|||||||
if interceptor != nil {
|
if interceptor != nil {
|
||||||
log.Debugf("Interceptor connected")
|
log.Debugf("Interceptor connected")
|
||||||
|
|
||||||
for _, fwd := range s.holdForwards {
|
s.heldHtlcSet.forEach(s.sendForward)
|
||||||
s.sendForward(fwd)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -238,20 +355,19 @@ func (s *InterceptableSwitch) setInterceptor(interceptor ForwardInterceptor) {
|
|||||||
// Interceptor is not required. Release held forwards.
|
// Interceptor is not required. Release held forwards.
|
||||||
log.Infof("Interceptor disconnected, resolving held packets")
|
log.Infof("Interceptor disconnected, resolving held packets")
|
||||||
|
|
||||||
for _, fwd := range s.holdForwards {
|
s.heldHtlcSet.popAll(func(fwd InterceptedForward) {
|
||||||
if err := fwd.Resume(); err != nil {
|
err := fwd.Resume()
|
||||||
|
if err != nil {
|
||||||
log.Errorf("Failed to resume hold forward %v", err)
|
log.Errorf("Failed to resume hold forward %v", err)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
s.holdForwards = make(map[channeldb.CircuitKey]InterceptedForward)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InterceptableSwitch) resolve(res *FwdResolution) error {
|
func (s *InterceptableSwitch) resolve(res *FwdResolution) error {
|
||||||
intercepted, ok := s.holdForwards[res.Key]
|
intercepted, err := s.heldHtlcSet.pop(res.Key)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return fmt.Errorf("fwd %v not found", res.Key)
|
return err
|
||||||
}
|
}
|
||||||
delete(s.holdForwards, res.Key)
|
|
||||||
|
|
||||||
switch res.Action {
|
switch res.Action {
|
||||||
case FwdActionResume:
|
case FwdActionResume:
|
||||||
@@ -338,19 +454,21 @@ func (s *InterceptableSwitch) ForwardPacket(
|
|||||||
// interceptForward forwards the packet to the external interceptor after
|
// interceptForward forwards the packet to the external interceptor after
|
||||||
// checking the interception criteria.
|
// checking the interception criteria.
|
||||||
func (s *InterceptableSwitch) interceptForward(packet *htlcPacket,
|
func (s *InterceptableSwitch) interceptForward(packet *htlcPacket,
|
||||||
isReplay bool) bool {
|
isReplay bool) (bool, error) {
|
||||||
|
|
||||||
switch htlc := packet.htlc.(type) {
|
switch htlc := packet.htlc.(type) {
|
||||||
case *lnwire.UpdateAddHTLC:
|
case *lnwire.UpdateAddHTLC:
|
||||||
// We are not interested in intercepting initiated payments.
|
// We are not interested in intercepting initiated payments.
|
||||||
if packet.incomingChanID == hop.Source {
|
if packet.incomingChanID == hop.Source {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
intercepted := &interceptedForward{
|
intercepted := &interceptedForward{
|
||||||
htlc: htlc,
|
htlc: htlc,
|
||||||
packet: packet,
|
packet: packet,
|
||||||
htlcSwitch: s.htlcSwitch,
|
htlcSwitch: s.htlcSwitch,
|
||||||
|
autoFailHeight: int32(packet.incomingTimeout -
|
||||||
|
s.cltvRejectDelta),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle forwards that are too close to expiry.
|
// Handle forwards that are too close to expiry.
|
||||||
@@ -368,28 +486,28 @@ func (s *InterceptableSwitch) interceptForward(packet *htlcPacket,
|
|||||||
// will remain stuck and potentially force-close the
|
// will remain stuck and potentially force-close the
|
||||||
// channel. But in the end, we should never get here, so
|
// channel. But in the end, we should never get here, so
|
||||||
// the actual return value doesn't matter that much.
|
// the actual return value doesn't matter that much.
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
if handled {
|
if handled {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.forward(intercepted, isReplay)
|
return s.forward(intercepted, isReplay)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward records the intercepted htlc and forwards it to the interceptor.
|
// forward records the intercepted htlc and forwards it to the interceptor.
|
||||||
func (s *InterceptableSwitch) forward(
|
func (s *InterceptableSwitch) forward(
|
||||||
fwd InterceptedForward, isReplay bool) bool {
|
fwd InterceptedForward, isReplay bool) (bool, error) {
|
||||||
|
|
||||||
inKey := fwd.Packet().IncomingCircuit
|
inKey := fwd.Packet().IncomingCircuit
|
||||||
|
|
||||||
// Ignore already held htlcs.
|
// Ignore already held htlcs.
|
||||||
if _, ok := s.holdForwards[inKey]; ok {
|
if s.heldHtlcSet.exists(inKey) {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no interceptor currently registered, configuration and packet
|
// If there is no interceptor currently registered, configuration and packet
|
||||||
@@ -397,7 +515,7 @@ func (s *InterceptableSwitch) forward(
|
|||||||
if s.interceptor == nil {
|
if s.interceptor == nil {
|
||||||
// Process normally if an interceptor is not required.
|
// Process normally if an interceptor is not required.
|
||||||
if !s.requireInterceptor {
|
if !s.requireInterceptor {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are in interceptor-required mode. If this is a new packet, it is
|
// We are in interceptor-required mode. If this is a new packet, it is
|
||||||
@@ -411,23 +529,28 @@ func (s *InterceptableSwitch) forward(
|
|||||||
log.Errorf("Cannot fail packet: %v", err)
|
log.Errorf("Cannot fail packet: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This packet is a replay. It is not safe to fail back, because the
|
// This packet is a replay. It is not safe to fail back, because the
|
||||||
// interceptor may still signal otherwise upon reconnect. Keep the
|
// interceptor may still signal otherwise upon reconnect. Keep the
|
||||||
// packet in the queue until then.
|
// packet in the queue until then.
|
||||||
s.holdForwards[inKey] = fwd
|
if err := s.heldHtlcSet.push(inKey, fwd); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is an interceptor registered. We can forward the packet right now.
|
// There is an interceptor registered. We can forward the packet right now.
|
||||||
// Hold it in the queue too to track what is outstanding.
|
// Hold it in the queue too to track what is outstanding.
|
||||||
s.holdForwards[inKey] = fwd
|
if err := s.heldHtlcSet.push(inKey, fwd); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
s.sendForward(fwd)
|
s.sendForward(fwd)
|
||||||
|
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleExpired checks that the htlc isn't too close to the channel
|
// handleExpired checks that the htlc isn't too close to the channel
|
||||||
@@ -435,8 +558,8 @@ func (s *InterceptableSwitch) forward(
|
|||||||
func (s *InterceptableSwitch) handleExpired(fwd *interceptedForward) (
|
func (s *InterceptableSwitch) handleExpired(fwd *interceptedForward) (
|
||||||
bool, error) {
|
bool, error) {
|
||||||
|
|
||||||
height := s.htlcSwitch.BestHeight()
|
height := uint32(s.currentHeight)
|
||||||
if fwd.packet.incomingTimeout >= height+s.cltvRejectDelta {
|
if fwd.packet.incomingTimeout >= height+s.cltvInterceptDelta {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,9 +583,10 @@ func (s *InterceptableSwitch) handleExpired(fwd *interceptedForward) (
|
|||||||
// It is passed from the switch to external interceptors that are interested
|
// It is passed from the switch to external interceptors that are interested
|
||||||
// in holding forwards and resolve them manually.
|
// in holding forwards and resolve them manually.
|
||||||
type interceptedForward struct {
|
type interceptedForward struct {
|
||||||
htlc *lnwire.UpdateAddHTLC
|
htlc *lnwire.UpdateAddHTLC
|
||||||
packet *htlcPacket
|
packet *htlcPacket
|
||||||
htlcSwitch *Switch
|
htlcSwitch *Switch
|
||||||
|
autoFailHeight int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packet returns the intercepted htlc packet.
|
// Packet returns the intercepted htlc packet.
|
||||||
@@ -480,6 +604,7 @@ func (f *interceptedForward) Packet() InterceptedPacket {
|
|||||||
IncomingExpiry: f.packet.incomingTimeout,
|
IncomingExpiry: f.packet.incomingTimeout,
|
||||||
CustomRecords: f.packet.customRecords,
|
CustomRecords: f.packet.customRecords,
|
||||||
OnionBlob: f.htlc.OnionBlob,
|
OnionBlob: f.htlc.OnionBlob,
|
||||||
|
AutoFailHeight: f.autoFailHeight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -312,6 +312,10 @@ type InterceptedPacket struct {
|
|||||||
|
|
||||||
// OnionBlob is the onion packet for the next hop
|
// OnionBlob is the onion packet for the next hop
|
||||||
OnionBlob [lnwire.OnionPacketSize]byte
|
OnionBlob [lnwire.OnionPacketSize]byte
|
||||||
|
|
||||||
|
// AutoFailHeight is the block height at which this intercept will be
|
||||||
|
// failed back automatically.
|
||||||
|
AutoFailHeight int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterceptedForward is passed to the ForwardInterceptor for every forwarded
|
// InterceptedForward is passed to the ForwardInterceptor for every forwarded
|
||||||
|
|||||||
+268
-129
@@ -14,10 +14,12 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/contractcourt"
|
"github.com/lightningnetwork/lnd/contractcourt"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
|
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
|
"github.com/lightningnetwork/lnd/lntest/mock"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
@@ -3702,6 +3704,8 @@ func (m *mockForwardInterceptor) InterceptForwardHtlc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockForwardInterceptor) getIntercepted() InterceptedPacket {
|
func (m *mockForwardInterceptor) getIntercepted() InterceptedPacket {
|
||||||
|
m.t.Helper()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case p := <-m.interceptedChan:
|
case p := <-m.interceptedChan:
|
||||||
return p
|
return p
|
||||||
@@ -3750,6 +3754,8 @@ func assertOutgoingLinkReceive(t *testing.T, targetLink *mockChannelLink,
|
|||||||
func assertOutgoingLinkReceiveIntercepted(t *testing.T,
|
func assertOutgoingLinkReceiveIntercepted(t *testing.T,
|
||||||
targetLink *mockChannelLink) {
|
targetLink *mockChannelLink) {
|
||||||
|
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-targetLink.packets:
|
case <-targetLink.packets:
|
||||||
case <-time.After(time.Second):
|
case <-time.After(time.Second):
|
||||||
@@ -3757,8 +3763,24 @@ func assertOutgoingLinkReceiveIntercepted(t *testing.T,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSwitchHoldForward(t *testing.T) {
|
type interceptableSwitchTestContext struct {
|
||||||
t.Parallel()
|
t *testing.T
|
||||||
|
|
||||||
|
preimage [sha256.Size]byte
|
||||||
|
rhash [32]byte
|
||||||
|
onionBlob [1366]byte
|
||||||
|
incomingHtlcID uint64
|
||||||
|
cltvRejectDelta uint32
|
||||||
|
cltvInterceptDelta uint32
|
||||||
|
|
||||||
|
forwardInterceptor *mockForwardInterceptor
|
||||||
|
aliceChannelLink *mockChannelLink
|
||||||
|
bobChannelLink *mockChannelLink
|
||||||
|
s *Switch
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInterceptableSwitchTestContext(
|
||||||
|
t *testing.T) *interceptableSwitchTestContext {
|
||||||
|
|
||||||
chanID1, chanID2, aliceChanID, bobChanID := genIDs()
|
chanID1, chanID2, aliceChanID, bobChanID := genIDs()
|
||||||
|
|
||||||
@@ -3783,12 +3805,6 @@ func TestSwitchHoldForward(t *testing.T) {
|
|||||||
t.Fatalf("unable to start switch: %v", err)
|
t.Fatalf("unable to start switch: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := s.Stop(); err != nil {
|
|
||||||
t.Fatalf(err.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
s, chanID1, aliceChanID, emptyScid, alicePeer, true, false,
|
s, chanID1, aliceChanID, emptyScid, alicePeer, true, false,
|
||||||
false, false,
|
false, false,
|
||||||
@@ -3804,72 +3820,106 @@ func TestSwitchHoldForward(t *testing.T) {
|
|||||||
t.Fatalf("unable to add bob link: %v", err)
|
t.Fatalf("unable to add bob link: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create request which should be forwarded from Alice channel link to
|
|
||||||
// bob channel link.
|
|
||||||
preimage := [sha256.Size]byte{1}
|
preimage := [sha256.Size]byte{1}
|
||||||
rhash := sha256.Sum256(preimage[:])
|
|
||||||
onionBlob := [1366]byte{4, 5, 6}
|
|
||||||
incomingHtlcID := uint64(0)
|
|
||||||
|
|
||||||
const cltvRejectDelta = 13
|
ctx := &interceptableSwitchTestContext{
|
||||||
|
t: t,
|
||||||
createTestPacket := func() *htlcPacket {
|
preimage: preimage,
|
||||||
incomingHtlcID++
|
rhash: sha256.Sum256(preimage[:]),
|
||||||
|
onionBlob: [1366]byte{4, 5, 6},
|
||||||
return &htlcPacket{
|
incomingHtlcID: uint64(0),
|
||||||
incomingChanID: aliceChannelLink.ShortChanID(),
|
cltvRejectDelta: 10,
|
||||||
incomingHTLCID: incomingHtlcID,
|
cltvInterceptDelta: 13,
|
||||||
incomingTimeout: testStartingHeight + cltvRejectDelta + 1,
|
forwardInterceptor: &mockForwardInterceptor{
|
||||||
outgoingChanID: bobChannelLink.ShortChanID(),
|
t: t,
|
||||||
obfuscator: NewMockObfuscator(),
|
interceptedChan: make(chan InterceptedPacket),
|
||||||
htlc: &lnwire.UpdateAddHTLC{
|
},
|
||||||
PaymentHash: rhash,
|
aliceChannelLink: aliceChannelLink,
|
||||||
Amount: 1,
|
bobChannelLink: bobChannelLink,
|
||||||
OnionBlob: onionBlob,
|
s: s,
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createSettlePacket := func(outgoingHTLCID uint64) *htlcPacket {
|
return ctx
|
||||||
return &htlcPacket{
|
}
|
||||||
outgoingChanID: bobChannelLink.ShortChanID(),
|
|
||||||
outgoingHTLCID: outgoingHTLCID,
|
|
||||||
amount: 1,
|
|
||||||
htlc: &lnwire.UpdateFulfillHTLC{
|
|
||||||
PaymentPreimage: preimage,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
forwardInterceptor := &mockForwardInterceptor{
|
func (c *interceptableSwitchTestContext) createTestPacket() *htlcPacket {
|
||||||
t: t,
|
c.incomingHtlcID++
|
||||||
interceptedChan: make(chan InterceptedPacket),
|
|
||||||
|
return &htlcPacket{
|
||||||
|
incomingChanID: c.aliceChannelLink.ShortChanID(),
|
||||||
|
incomingHTLCID: c.incomingHtlcID,
|
||||||
|
incomingTimeout: testStartingHeight + c.cltvInterceptDelta + 1,
|
||||||
|
outgoingChanID: c.bobChannelLink.ShortChanID(),
|
||||||
|
obfuscator: NewMockObfuscator(),
|
||||||
|
htlc: &lnwire.UpdateAddHTLC{
|
||||||
|
PaymentHash: c.rhash,
|
||||||
|
Amount: 1,
|
||||||
|
OnionBlob: c.onionBlob,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
switchForwardInterceptor := NewInterceptableSwitch(
|
}
|
||||||
s, cltvRejectDelta, false,
|
|
||||||
|
func (c *interceptableSwitchTestContext) finish() {
|
||||||
|
if err := c.s.Stop(); err != nil {
|
||||||
|
c.t.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *interceptableSwitchTestContext) createSettlePacket(
|
||||||
|
outgoingHTLCID uint64) *htlcPacket {
|
||||||
|
|
||||||
|
return &htlcPacket{
|
||||||
|
outgoingChanID: c.bobChannelLink.ShortChanID(),
|
||||||
|
outgoingHTLCID: outgoingHTLCID,
|
||||||
|
amount: 1,
|
||||||
|
htlc: &lnwire.UpdateFulfillHTLC{
|
||||||
|
PaymentPreimage: c.preimage,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSwitchHoldForward(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
c := newInterceptableSwitchTestContext(t)
|
||||||
|
defer c.finish()
|
||||||
|
|
||||||
|
notifier := &mock.ChainNotifier{
|
||||||
|
EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
|
||||||
|
}
|
||||||
|
notifier.EpochChan <- &chainntnfs.BlockEpoch{Height: testStartingHeight}
|
||||||
|
|
||||||
|
switchForwardInterceptor, err := NewInterceptableSwitch(
|
||||||
|
&InterceptableSwitchConfig{
|
||||||
|
Switch: c.s,
|
||||||
|
CltvRejectDelta: c.cltvRejectDelta,
|
||||||
|
CltvInterceptDelta: c.cltvInterceptDelta,
|
||||||
|
Notifier: notifier,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
require.NoError(t, switchForwardInterceptor.Start())
|
require.NoError(t, switchForwardInterceptor.Start())
|
||||||
|
|
||||||
switchForwardInterceptor.SetInterceptor(forwardInterceptor.InterceptForwardHtlc)
|
switchForwardInterceptor.SetInterceptor(c.forwardInterceptor.InterceptForwardHtlc)
|
||||||
linkQuit := make(chan struct{})
|
linkQuit := make(chan struct{})
|
||||||
|
|
||||||
// Test a forward that expires too soon.
|
// Test a forward that expires too soon.
|
||||||
packet := createTestPacket()
|
packet := c.createTestPacket()
|
||||||
packet.incomingTimeout = testStartingHeight + cltvRejectDelta - 1
|
packet.incomingTimeout = testStartingHeight + c.cltvRejectDelta - 1
|
||||||
|
|
||||||
err = switchForwardInterceptor.ForwardPackets(linkQuit, false, packet)
|
err = switchForwardInterceptor.ForwardPackets(linkQuit, false, packet)
|
||||||
require.NoError(t, err, "can't forward htlc packet")
|
require.NoError(t, err, "can't forward htlc packet")
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
assertOutgoingLinkReceiveIntercepted(t, aliceChannelLink)
|
assertOutgoingLinkReceiveIntercepted(t, c.aliceChannelLink)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Test a forward that expires too soon and can't be failed.
|
// Test a forward that expires too soon and can't be failed.
|
||||||
packet = createTestPacket()
|
packet = c.createTestPacket()
|
||||||
packet.incomingTimeout = testStartingHeight + cltvRejectDelta - 1
|
packet.incomingTimeout = testStartingHeight + c.cltvRejectDelta - 1
|
||||||
|
|
||||||
// Simulate an error during the composition of the failure message.
|
// Simulate an error during the composition of the failure message.
|
||||||
currentCallback := s.cfg.FetchLastChannelUpdate
|
currentCallback := c.s.cfg.FetchLastChannelUpdate
|
||||||
s.cfg.FetchLastChannelUpdate = func(
|
c.s.cfg.FetchLastChannelUpdate = func(
|
||||||
lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
|
lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
|
||||||
|
|
||||||
return nil, errors.New("cannot fetch update")
|
return nil, errors.New("cannot fetch update")
|
||||||
@@ -3877,137 +3927,137 @@ func TestSwitchHoldForward(t *testing.T) {
|
|||||||
|
|
||||||
err = switchForwardInterceptor.ForwardPackets(linkQuit, false, packet)
|
err = switchForwardInterceptor.ForwardPackets(linkQuit, false, packet)
|
||||||
require.NoError(t, err, "can't forward htlc packet")
|
require.NoError(t, err, "can't forward htlc packet")
|
||||||
receivedPkt := assertOutgoingLinkReceive(t, bobChannelLink, true)
|
receivedPkt := assertOutgoingLinkReceive(t, c.bobChannelLink, true)
|
||||||
assertNumCircuits(t, s, 1, 1)
|
assertNumCircuits(t, c.s, 1, 1)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false,
|
linkQuit, false,
|
||||||
createSettlePacket(receivedPkt.outgoingHTLCID),
|
c.createSettlePacket(receivedPkt.outgoingHTLCID),
|
||||||
))
|
))
|
||||||
|
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
s.cfg.FetchLastChannelUpdate = currentCallback
|
c.s.cfg.FetchLastChannelUpdate = currentCallback
|
||||||
|
|
||||||
// Test resume a hold forward.
|
// Test resume a hold forward.
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
err = switchForwardInterceptor.ForwardPackets(
|
err = switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
Action: FwdActionResume,
|
Action: FwdActionResume,
|
||||||
Key: forwardInterceptor.getIntercepted().IncomingCircuit,
|
Key: c.forwardInterceptor.getIntercepted().IncomingCircuit,
|
||||||
}))
|
}))
|
||||||
receivedPkt = assertOutgoingLinkReceive(t, bobChannelLink, true)
|
receivedPkt = assertOutgoingLinkReceive(t, c.bobChannelLink, true)
|
||||||
assertNumCircuits(t, s, 1, 1)
|
assertNumCircuits(t, c.s, 1, 1)
|
||||||
|
|
||||||
// settling the htlc to close the circuit.
|
// settling the htlc to close the circuit.
|
||||||
err = switchForwardInterceptor.ForwardPackets(
|
err = switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false,
|
linkQuit, false,
|
||||||
createSettlePacket(receivedPkt.outgoingHTLCID),
|
c.createSettlePacket(receivedPkt.outgoingHTLCID),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Test resume a hold forward after disconnection.
|
// Test resume a hold forward after disconnection.
|
||||||
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
))
|
))
|
||||||
|
|
||||||
// Wait until the packet is offered to the interceptor.
|
// Wait until the packet is offered to the interceptor.
|
||||||
_ = forwardInterceptor.getIntercepted()
|
_ = c.forwardInterceptor.getIntercepted()
|
||||||
|
|
||||||
// No forward expected yet.
|
// No forward expected yet.
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
|
|
||||||
// Disconnect should resume the forwarding.
|
// Disconnect should resume the forwarding.
|
||||||
switchForwardInterceptor.SetInterceptor(nil)
|
switchForwardInterceptor.SetInterceptor(nil)
|
||||||
|
|
||||||
receivedPkt = assertOutgoingLinkReceive(t, bobChannelLink, true)
|
receivedPkt = assertOutgoingLinkReceive(t, c.bobChannelLink, true)
|
||||||
assertNumCircuits(t, s, 1, 1)
|
assertNumCircuits(t, c.s, 1, 1)
|
||||||
|
|
||||||
// Settle the htlc to close the circuit.
|
// Settle the htlc to close the circuit.
|
||||||
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false,
|
linkQuit, false,
|
||||||
createSettlePacket(receivedPkt.outgoingHTLCID),
|
c.createSettlePacket(receivedPkt.outgoingHTLCID),
|
||||||
))
|
))
|
||||||
|
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Test failing a hold forward
|
// Test failing a hold forward
|
||||||
switchForwardInterceptor.SetInterceptor(
|
switchForwardInterceptor.SetInterceptor(
|
||||||
forwardInterceptor.InterceptForwardHtlc,
|
c.forwardInterceptor.InterceptForwardHtlc,
|
||||||
)
|
)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
))
|
))
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
Action: FwdActionFail,
|
Action: FwdActionFail,
|
||||||
Key: forwardInterceptor.getIntercepted().IncomingCircuit,
|
Key: c.forwardInterceptor.getIntercepted().IncomingCircuit,
|
||||||
FailureCode: lnwire.CodeTemporaryChannelFailure,
|
FailureCode: lnwire.CodeTemporaryChannelFailure,
|
||||||
}))
|
}))
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Test failing a hold forward with a failure message.
|
// Test failing a hold forward with a failure message.
|
||||||
require.NoError(t,
|
require.NoError(t,
|
||||||
switchForwardInterceptor.ForwardPackets(
|
switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
|
|
||||||
reason := lnwire.OpaqueReason([]byte{1, 2, 3})
|
reason := lnwire.OpaqueReason([]byte{1, 2, 3})
|
||||||
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
Action: FwdActionFail,
|
Action: FwdActionFail,
|
||||||
Key: forwardInterceptor.getIntercepted().IncomingCircuit,
|
Key: c.forwardInterceptor.getIntercepted().IncomingCircuit,
|
||||||
FailureMessage: reason,
|
FailureMessage: reason,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
packet = assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
packet = assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
|
|
||||||
require.Equal(t, reason, packet.htlc.(*lnwire.UpdateFailHTLC).Reason)
|
require.Equal(t, reason, packet.htlc.(*lnwire.UpdateFailHTLC).Reason)
|
||||||
|
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Test failing a hold forward with a malformed htlc failure.
|
// Test failing a hold forward with a malformed htlc failure.
|
||||||
err = switchForwardInterceptor.ForwardPackets(
|
err = switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
|
|
||||||
code := lnwire.CodeInvalidOnionKey
|
code := lnwire.CodeInvalidOnionKey
|
||||||
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
Action: FwdActionFail,
|
Action: FwdActionFail,
|
||||||
Key: forwardInterceptor.getIntercepted().IncomingCircuit,
|
Key: c.forwardInterceptor.getIntercepted().IncomingCircuit,
|
||||||
FailureCode: code,
|
FailureCode: code,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
packet = assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
packet = assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
failPacket := packet.htlc.(*lnwire.UpdateFailHTLC)
|
failPacket := packet.htlc.(*lnwire.UpdateFailHTLC)
|
||||||
|
|
||||||
shaOnionBlob := sha256.Sum256(onionBlob[:])
|
shaOnionBlob := sha256.Sum256(c.onionBlob[:])
|
||||||
expectedFailure := &lnwire.FailInvalidOnionKey{
|
expectedFailure := &lnwire.FailInvalidOnionKey{
|
||||||
OnionSHA256: shaOnionBlob,
|
OnionSHA256: shaOnionBlob,
|
||||||
}
|
}
|
||||||
@@ -4016,39 +4066,53 @@ func TestSwitchHoldForward(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, lnwire.OpaqueReason(b.Bytes()), failPacket.Reason)
|
assert.Equal(t, lnwire.OpaqueReason(b.Bytes()), failPacket.Reason)
|
||||||
|
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Test settling a hold forward
|
// Test settling a hold forward
|
||||||
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
))
|
))
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
Key: forwardInterceptor.getIntercepted().IncomingCircuit,
|
Key: c.forwardInterceptor.getIntercepted().IncomingCircuit,
|
||||||
Action: FwdActionSettle,
|
Action: FwdActionSettle,
|
||||||
Preimage: preimage,
|
Preimage: c.preimage,
|
||||||
}))
|
}))
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.Stop())
|
require.NoError(t, switchForwardInterceptor.Stop())
|
||||||
|
|
||||||
// Test always-on interception.
|
// Test always-on interception.
|
||||||
switchForwardInterceptor = NewInterceptableSwitch(s, cltvRejectDelta, true)
|
notifier = &mock.ChainNotifier{
|
||||||
|
EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
|
||||||
|
}
|
||||||
|
notifier.EpochChan <- &chainntnfs.BlockEpoch{Height: testStartingHeight}
|
||||||
|
|
||||||
|
switchForwardInterceptor, err = NewInterceptableSwitch(
|
||||||
|
&InterceptableSwitchConfig{
|
||||||
|
Switch: c.s,
|
||||||
|
CltvRejectDelta: c.cltvRejectDelta,
|
||||||
|
CltvInterceptDelta: c.cltvInterceptDelta,
|
||||||
|
RequireInterceptor: true,
|
||||||
|
Notifier: notifier,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
require.NoError(t, switchForwardInterceptor.Start())
|
require.NoError(t, switchForwardInterceptor.Start())
|
||||||
|
|
||||||
// Forward a fresh packet. It is expected to be failed immediately,
|
// Forward a fresh packet. It is expected to be failed immediately,
|
||||||
// because there is no interceptor registered.
|
// because there is no interceptor registered.
|
||||||
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
require.NoError(t, switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, false, createTestPacket(),
|
linkQuit, false, c.createTestPacket(),
|
||||||
))
|
))
|
||||||
|
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Forward a replayed packet. It is expected to be held until the
|
// Forward a replayed packet. It is expected to be held until the
|
||||||
// interceptor connects. To continue the test, it needs to be ran in a
|
// interceptor connects. To continue the test, it needs to be ran in a
|
||||||
@@ -4056,54 +4120,115 @@ func TestSwitchHoldForward(t *testing.T) {
|
|||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
errChan <- switchForwardInterceptor.ForwardPackets(
|
errChan <- switchForwardInterceptor.ForwardPackets(
|
||||||
linkQuit, true, createTestPacket(),
|
linkQuit, true, c.createTestPacket(),
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Assert that nothing is forward to the switch.
|
// Assert that nothing is forward to the switch.
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
// Register an interceptor.
|
// Register an interceptor.
|
||||||
switchForwardInterceptor.SetInterceptor(
|
switchForwardInterceptor.SetInterceptor(
|
||||||
forwardInterceptor.InterceptForwardHtlc,
|
c.forwardInterceptor.InterceptForwardHtlc,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Expect the ForwardPackets call to unblock.
|
// Expect the ForwardPackets call to unblock.
|
||||||
require.NoError(t, <-errChan)
|
require.NoError(t, <-errChan)
|
||||||
|
|
||||||
// Now expect the queued packet to come through.
|
// Now expect the queued packet to come through.
|
||||||
forwardInterceptor.getIntercepted()
|
c.forwardInterceptor.getIntercepted()
|
||||||
|
|
||||||
// Disconnect and reconnect interceptor.
|
// Disconnect and reconnect interceptor.
|
||||||
switchForwardInterceptor.SetInterceptor(nil)
|
switchForwardInterceptor.SetInterceptor(nil)
|
||||||
switchForwardInterceptor.SetInterceptor(
|
switchForwardInterceptor.SetInterceptor(
|
||||||
forwardInterceptor.InterceptForwardHtlc,
|
c.forwardInterceptor.InterceptForwardHtlc,
|
||||||
)
|
)
|
||||||
|
|
||||||
// A replay of the held packet is expected.
|
// A replay of the held packet is expected.
|
||||||
intercepted := forwardInterceptor.getIntercepted()
|
intercepted := c.forwardInterceptor.getIntercepted()
|
||||||
|
|
||||||
// Settle the packet.
|
// Settle the packet.
|
||||||
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
require.NoError(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
Key: intercepted.IncomingCircuit,
|
Key: intercepted.IncomingCircuit,
|
||||||
Action: FwdActionSettle,
|
Action: FwdActionSettle,
|
||||||
Preimage: preimage,
|
Preimage: c.preimage,
|
||||||
}))
|
}))
|
||||||
assertOutgoingLinkReceive(t, bobChannelLink, false)
|
assertOutgoingLinkReceive(t, c.bobChannelLink, false)
|
||||||
assertOutgoingLinkReceive(t, aliceChannelLink, true)
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
assertNumCircuits(t, s, 0, 0)
|
assertNumCircuits(t, c.s, 0, 0)
|
||||||
|
|
||||||
require.NoError(t, switchForwardInterceptor.Stop())
|
require.NoError(t, switchForwardInterceptor.Stop())
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-forwardInterceptor.interceptedChan:
|
case <-c.forwardInterceptor.interceptedChan:
|
||||||
require.Fail(t, "unexpected interception")
|
require.Fail(t, "unexpected interception")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInterceptableSwitchWatchDog(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
c := newInterceptableSwitchTestContext(t)
|
||||||
|
defer c.finish()
|
||||||
|
|
||||||
|
// Start interceptable switch.
|
||||||
|
notifier := &mock.ChainNotifier{
|
||||||
|
EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
|
||||||
|
}
|
||||||
|
notifier.EpochChan <- &chainntnfs.BlockEpoch{Height: testStartingHeight}
|
||||||
|
|
||||||
|
switchForwardInterceptor, err := NewInterceptableSwitch(
|
||||||
|
&InterceptableSwitchConfig{
|
||||||
|
Switch: c.s,
|
||||||
|
CltvRejectDelta: c.cltvRejectDelta,
|
||||||
|
CltvInterceptDelta: c.cltvInterceptDelta,
|
||||||
|
Notifier: notifier,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, switchForwardInterceptor.Start())
|
||||||
|
|
||||||
|
// Set interceptor.
|
||||||
|
switchForwardInterceptor.SetInterceptor(
|
||||||
|
c.forwardInterceptor.InterceptForwardHtlc,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Receive a packet.
|
||||||
|
linkQuit := make(chan struct{})
|
||||||
|
|
||||||
|
packet := c.createTestPacket()
|
||||||
|
|
||||||
|
err = switchForwardInterceptor.ForwardPackets(linkQuit, false, packet)
|
||||||
|
require.NoError(t, err, "can't forward htlc packet")
|
||||||
|
|
||||||
|
// Intercept the packet.
|
||||||
|
intercepted := c.forwardInterceptor.getIntercepted()
|
||||||
|
|
||||||
|
require.Equal(t,
|
||||||
|
int32(packet.incomingTimeout-c.cltvRejectDelta),
|
||||||
|
intercepted.AutoFailHeight,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Htlc expires before a resolution from the interceptor.
|
||||||
|
notifier.EpochChan <- &chainntnfs.BlockEpoch{
|
||||||
|
Height: int32(packet.incomingTimeout) -
|
||||||
|
int32(c.cltvRejectDelta),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect the htlc to be failed back.
|
||||||
|
assertOutgoingLinkReceive(t, c.aliceChannelLink, true)
|
||||||
|
|
||||||
|
// It is too late now to resolve. Expect an error.
|
||||||
|
require.Error(t, switchForwardInterceptor.Resolve(&FwdResolution{
|
||||||
|
Action: FwdActionSettle,
|
||||||
|
Key: intercepted.IncomingCircuit,
|
||||||
|
Preimage: c.preimage,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
// TestSwitchDustForwarding tests that the switch properly fails HTLC's which
|
// TestSwitchDustForwarding tests that the switch properly fails HTLC's which
|
||||||
// have incoming or outgoing links that breach their dust thresholds.
|
// have incoming or outgoing links that breach their dust thresholds.
|
||||||
func TestSwitchDustForwarding(t *testing.T) {
|
func TestSwitchDustForwarding(t *testing.T) {
|
||||||
@@ -5329,7 +5454,21 @@ func testSwitchAliasInterceptFail(t *testing.T, zeroConf bool) {
|
|||||||
t: t,
|
t: t,
|
||||||
interceptedChan: make(chan InterceptedPacket),
|
interceptedChan: make(chan InterceptedPacket),
|
||||||
}
|
}
|
||||||
interceptSwitch := NewInterceptableSwitch(s, 0, false)
|
|
||||||
|
notifier := &mock.ChainNotifier{
|
||||||
|
EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
|
||||||
|
}
|
||||||
|
notifier.EpochChan <- &chainntnfs.BlockEpoch{Height: testStartingHeight}
|
||||||
|
|
||||||
|
interceptSwitch, err := NewInterceptableSwitch(
|
||||||
|
&InterceptableSwitchConfig{
|
||||||
|
Switch: s,
|
||||||
|
Notifier: notifier,
|
||||||
|
CltvRejectDelta: 10,
|
||||||
|
CltvInterceptDelta: 13,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
require.NoError(t, interceptSwitch.Start())
|
require.NoError(t, interceptSwitch.Start())
|
||||||
interceptSwitch.SetInterceptor(forwardInterceptor.InterceptForwardHtlc)
|
interceptSwitch.SetInterceptor(forwardInterceptor.InterceptForwardHtlc)
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ const (
|
|||||||
// push us in the broadcast window.
|
// push us in the broadcast window.
|
||||||
DefaultFinalCltvRejectDelta = DefaultIncomingBroadcastDelta + 3
|
DefaultFinalCltvRejectDelta = DefaultIncomingBroadcastDelta + 3
|
||||||
|
|
||||||
|
// DefaultCltvInterceptDelta defines the number of blocks before the
|
||||||
|
// expiry of the htlc where we don't intercept anymore. This value must
|
||||||
|
// be greater than CltvRejectDelta, because we don't want to offer htlcs
|
||||||
|
// to the interceptor client for which there is no time left to resolve
|
||||||
|
// them anymore.
|
||||||
|
DefaultCltvInterceptDelta = DefaultFinalCltvRejectDelta + 3
|
||||||
|
|
||||||
// DefaultOutgoingBroadcastDelta defines the number of blocks before the
|
// DefaultOutgoingBroadcastDelta defines the number of blocks before the
|
||||||
// expiry of an outgoing htlc at which we force close the channel. We
|
// expiry of an outgoing htlc at which we force close the channel. We
|
||||||
// are not in a hurry to force close, because there is nothing to claim
|
// are not in a hurry to force close, because there is nothing to claim
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ func (r *forwardInterceptor) onIntercept(
|
|||||||
IncomingExpiry: htlc.IncomingExpiry,
|
IncomingExpiry: htlc.IncomingExpiry,
|
||||||
CustomRecords: htlc.CustomRecords,
|
CustomRecords: htlc.CustomRecords,
|
||||||
OnionBlob: htlc.OnionBlob[:],
|
OnionBlob: htlc.OnionBlob[:],
|
||||||
|
AutoFailHeight: htlc.AutoFailHeight,
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.stream.Send(interceptionRequest)
|
return r.stream.Send(interceptionRequest)
|
||||||
|
|||||||
+199
-187
@@ -2590,6 +2590,9 @@ type ForwardHtlcInterceptRequest struct {
|
|||||||
CustomRecords map[uint64][]byte `protobuf:"bytes,8,rep,name=custom_records,json=customRecords,proto3" json:"custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
CustomRecords map[uint64][]byte `protobuf:"bytes,8,rep,name=custom_records,json=customRecords,proto3" json:"custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
// The onion blob for the next hop
|
// The onion blob for the next hop
|
||||||
OnionBlob []byte `protobuf:"bytes,9,opt,name=onion_blob,json=onionBlob,proto3" json:"onion_blob,omitempty"`
|
OnionBlob []byte `protobuf:"bytes,9,opt,name=onion_blob,json=onionBlob,proto3" json:"onion_blob,omitempty"`
|
||||||
|
// The block height at which this htlc will be auto-failed to prevent the
|
||||||
|
// channel from force-closing.
|
||||||
|
AutoFailHeight int32 `protobuf:"varint,10,opt,name=auto_fail_height,json=autoFailHeight,proto3" json:"auto_fail_height,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ForwardHtlcInterceptRequest) Reset() {
|
func (x *ForwardHtlcInterceptRequest) Reset() {
|
||||||
@@ -2687,6 +2690,13 @@ func (x *ForwardHtlcInterceptRequest) GetOnionBlob() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ForwardHtlcInterceptRequest) GetAutoFailHeight() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.AutoFailHeight
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// *
|
// *
|
||||||
// ForwardHtlcInterceptResponse enables the caller to resolve a previously hold
|
// ForwardHtlcInterceptResponse enables the caller to resolve a previously hold
|
||||||
// forward. The caller can choose either to:
|
// forward. The caller can choose either to:
|
||||||
@@ -3178,7 +3188,7 @@ var file_routerrpc_router_proto_rawDesc = []byte{
|
|||||||
0x75, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69,
|
0x75, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69,
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12,
|
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12,
|
||||||
0x17, 0x0a, 0x07, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
|
0x17, 0x0a, 0x07, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
|
||||||
0x52, 0x06, 0x68, 0x74, 0x6c, 0x63, 0x49, 0x64, 0x22, 0xbf, 0x04, 0x0a, 0x1b, 0x46, 0x6f, 0x72,
|
0x52, 0x06, 0x68, 0x74, 0x6c, 0x63, 0x49, 0x64, 0x22, 0xe9, 0x04, 0x0a, 0x1b, 0x46, 0x6f, 0x72,
|
||||||
0x77, 0x61, 0x72, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
|
0x77, 0x61, 0x72, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
|
||||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x14, 0x69, 0x6e, 0x63, 0x6f,
|
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x14, 0x69, 0x6e, 0x63, 0x6f,
|
||||||
0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79,
|
0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79,
|
||||||
@@ -3210,194 +3220,196 @@ var file_routerrpc_router_proto_rawDesc = []byte{
|
|||||||
0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75, 0x73, 0x74,
|
0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75, 0x73, 0x74,
|
||||||
0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x6e, 0x69,
|
0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x6e, 0x69,
|
||||||
0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f,
|
0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f,
|
||||||
0x6e, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x62, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74,
|
0x6e, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x75, 0x74, 0x6f,
|
||||||
0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
|
0x5f, 0x66, 0x61, 0x69, 0x6c, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01,
|
||||||
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
0x28, 0x05, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x6f, 0x46, 0x61, 0x69, 0x6c, 0x48, 0x65, 0x69, 0x67,
|
||||||
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
0x68, 0x74, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f,
|
||||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa8, 0x02, 0x0a, 0x1c, 0x46,
|
0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||||
0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63,
|
0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
|
||||||
0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x14, 0x69,
|
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x5f,
|
0x3a, 0x02, 0x38, 0x01, 0x22, 0xa8, 0x02, 0x0a, 0x1c, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
|
||||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73,
|
||||||
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x4b, 0x65, 0x79,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x14, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e,
|
||||||
0x52, 0x12, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69,
|
0x67, 0x5f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
||||||
0x74, 0x4b, 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02,
|
0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e,
|
||||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63,
|
0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6f,
|
||||||
0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x48, 0x6f, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x77,
|
0x6d, 0x69, 0x6e, 0x67, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x3b,
|
||||||
0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23,
|
||||||
0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20,
|
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c,
|
||||||
0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a,
|
0x76, 0x65, 0x48, 0x6f, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74,
|
||||||
0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70,
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4d,
|
0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70,
|
||||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72,
|
0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x75,
|
||||||
0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c,
|
0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c,
|
||||||
0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x61, 0x69,
|
0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||||
0x6c, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72,
|
0x12, 0x3d, 0x0a, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65,
|
||||||
0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
|
0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46,
|
||||||
0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x43, 0x6f,
|
||||||
0x74, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18,
|
0x64, 0x65, 0x52, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68,
|
0x82, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74,
|
||||||
0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e,
|
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x0a, 0x63,
|
||||||
0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x33, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18,
|
0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70,
|
0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50,
|
||||||
0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x41, 0x63, 0x74, 0x69,
|
0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12,
|
||||||
0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1a, 0x0a, 0x18, 0x55, 0x70,
|
0x33, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||||
0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
|
0x1b, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x81, 0x04, 0x0a, 0x0d, 0x46, 0x61, 0x69, 0x6c, 0x75,
|
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63,
|
||||||
0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
|
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1a, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68,
|
||||||
0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x54, 0x41,
|
0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x49, 0x4c, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45,
|
0x2a, 0x81, 0x04, 0x0a, 0x0d, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61,
|
||||||
0x43, 0x4f, 0x44, 0x45, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x4e,
|
0x69, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,
|
||||||
0x4f, 0x54, 0x5f, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a,
|
0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x10, 0x01, 0x12, 0x10,
|
||||||
0x10, 0x4f, 0x4e, 0x5f, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55,
|
0x0a, 0x0c, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x02,
|
||||||
0x54, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x45, 0x58, 0x43, 0x45,
|
0x12, 0x15, 0x0a, 0x11, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x45, 0x4c, 0x49,
|
||||||
0x45, 0x44, 0x53, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x49, 0x4e, 0x53,
|
0x47, 0x49, 0x42, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x4e, 0x5f, 0x43, 0x48,
|
||||||
0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43,
|
0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x12, 0x14, 0x0a,
|
||||||
0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54,
|
0x10, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x45, 0x58, 0x43, 0x45, 0x45, 0x44, 0x53, 0x5f, 0x4d, 0x41,
|
||||||
0x45, 0x5f, 0x46, 0x4f, 0x52, 0x57, 0x41, 0x52, 0x44, 0x10, 0x07, 0x12, 0x13, 0x0a, 0x0f, 0x48,
|
0x58, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49,
|
||||||
0x54, 0x4c, 0x43, 0x5f, 0x41, 0x44, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x08,
|
0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a,
|
||||||
0x12, 0x15, 0x0a, 0x11, 0x46, 0x4f, 0x52, 0x57, 0x41, 0x52, 0x44, 0x53, 0x5f, 0x44, 0x49, 0x53,
|
0x12, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x57,
|
||||||
0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x09, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x4f, 0x49,
|
0x41, 0x52, 0x44, 0x10, 0x07, 0x12, 0x13, 0x0a, 0x0f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x44,
|
||||||
0x43, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x0a, 0x12, 0x15, 0x0a,
|
0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x08, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x4f,
|
||||||
0x11, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x44, 0x45, 0x52, 0x50, 0x41,
|
0x52, 0x57, 0x41, 0x52, 0x44, 0x53, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10,
|
||||||
0x49, 0x44, 0x10, 0x0b, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f,
|
0x09, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x43, 0x41, 0x4e,
|
||||||
0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x10,
|
0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x0a, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x56, 0x4f, 0x49,
|
||||||
0x0c, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4e, 0x4f, 0x54,
|
0x43, 0x45, 0x5f, 0x55, 0x4e, 0x44, 0x45, 0x52, 0x50, 0x41, 0x49, 0x44, 0x10, 0x0b, 0x12, 0x1b,
|
||||||
0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x50, 0x50, 0x5f, 0x49,
|
0x0a, 0x17, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59,
|
||||||
0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x0e,
|
0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x10, 0x0c, 0x12, 0x14, 0x0a, 0x10, 0x49,
|
||||||
0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x4d, 0x49, 0x53, 0x4d,
|
0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x10,
|
||||||
0x41, 0x54, 0x43, 0x48, 0x10, 0x0f, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x45, 0x54, 0x5f, 0x54, 0x4f,
|
0x0d, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x50, 0x50, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45,
|
||||||
0x54, 0x41, 0x4c, 0x5f, 0x4d, 0x49, 0x53, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x10, 0x12, 0x15,
|
0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44,
|
||||||
0x0a, 0x11, 0x53, 0x45, 0x54, 0x5f, 0x54, 0x4f, 0x54, 0x41, 0x4c, 0x5f, 0x54, 0x4f, 0x4f, 0x5f,
|
0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x4d, 0x49, 0x53, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x0f,
|
||||||
0x4c, 0x4f, 0x57, 0x10, 0x11, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x45, 0x54, 0x5f, 0x4f, 0x56, 0x45,
|
0x12, 0x16, 0x0a, 0x12, 0x53, 0x45, 0x54, 0x5f, 0x54, 0x4f, 0x54, 0x41, 0x4c, 0x5f, 0x4d, 0x49,
|
||||||
0x52, 0x50, 0x41, 0x49, 0x44, 0x10, 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
|
0x53, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x10, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x45, 0x54, 0x5f,
|
||||||
0x57, 0x4e, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x10, 0x13, 0x12, 0x13, 0x0a, 0x0f,
|
0x54, 0x4f, 0x54, 0x41, 0x4c, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x4c, 0x4f, 0x57, 0x10, 0x11, 0x12,
|
||||||
0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x45, 0x4e, 0x44, 0x10,
|
0x10, 0x0a, 0x0c, 0x53, 0x45, 0x54, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x50, 0x41, 0x49, 0x44, 0x10,
|
||||||
0x14, 0x12, 0x13, 0x0a, 0x0f, 0x4d, 0x50, 0x50, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47,
|
0x12, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x49, 0x4e, 0x56,
|
||||||
0x52, 0x45, 0x53, 0x53, 0x10, 0x15, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x52, 0x43, 0x55, 0x4c,
|
0x4f, 0x49, 0x43, 0x45, 0x10, 0x13, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49,
|
||||||
0x41, 0x52, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x16, 0x2a, 0xae, 0x01, 0x0a, 0x0c, 0x50,
|
0x44, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x45, 0x4e, 0x44, 0x10, 0x14, 0x12, 0x13, 0x0a, 0x0f, 0x4d,
|
||||||
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x49,
|
0x50, 0x50, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x15,
|
||||||
0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55,
|
0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x52, 0x43, 0x55, 0x4c, 0x41, 0x52, 0x5f, 0x52, 0x4f, 0x55,
|
||||||
0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x46, 0x41, 0x49,
|
0x54, 0x45, 0x10, 0x16, 0x2a, 0xae, 0x01, 0x0a, 0x0c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
0x4c, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x02, 0x12, 0x13, 0x0a,
|
0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47,
|
||||||
0x0f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45,
|
0x48, 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45,
|
||||||
0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x45, 0x52, 0x52,
|
0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x49,
|
||||||
0x4f, 0x52, 0x10, 0x04, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49,
|
0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x46, 0x41, 0x49, 0x4c, 0x45,
|
||||||
0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54,
|
0x44, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c,
|
||||||
0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x46, 0x41,
|
0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x12, 0x24,
|
||||||
0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e,
|
0x0a, 0x20, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45,
|
||||||
0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x06, 0x2a, 0x3c, 0x0a, 0x18, 0x52,
|
0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49,
|
||||||
0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x48, 0x6f, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72,
|
0x4c, 0x53, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49,
|
||||||
0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x54, 0x54, 0x4c,
|
0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41,
|
||||||
0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x01, 0x12, 0x0a, 0x0a,
|
0x4e, 0x43, 0x45, 0x10, 0x06, 0x2a, 0x3c, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65,
|
||||||
0x06, 0x52, 0x45, 0x53, 0x55, 0x4d, 0x45, 0x10, 0x02, 0x2a, 0x35, 0x0a, 0x10, 0x43, 0x68, 0x61,
|
0x48, 0x6f, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f,
|
||||||
0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a,
|
0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a,
|
||||||
0x06, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x49, 0x53,
|
0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x53, 0x55, 0x4d,
|
||||||
0x41, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x4f, 0x10, 0x02,
|
0x45, 0x10, 0x02, 0x2a, 0x35, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||||
0x32, 0xb5, 0x0c, 0x0a, 0x06, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x12, 0x40, 0x0a, 0x0d, 0x53,
|
0x73, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x4e, 0x41, 0x42, 0x4c,
|
||||||
0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x32, 0x12, 0x1d, 0x2e, 0x72,
|
0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x01,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79,
|
0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x4f, 0x10, 0x02, 0x32, 0xb5, 0x0c, 0x0a, 0x06, 0x52,
|
||||||
0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x12, 0x40, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79,
|
||||||
0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x42, 0x0a,
|
0x6d, 0x65, 0x6e, 0x74, 0x56, 0x32, 0x12, 0x1d, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72,
|
||||||
0x0e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x32, 0x12,
|
0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65,
|
||||||
0x1e, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x63,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61,
|
||||||
0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x63, 0x6b,
|
||||||
0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x30,
|
0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x32, 0x12, 0x1e, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x01, 0x12, 0x42, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
|
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65,
|
||||||
0x74, 0x73, 0x12, 0x1f, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54,
|
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70,
|
||||||
0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
|
0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0d, 0x54,
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d,
|
0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x72,
|
||||||
0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x10, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61,
|
||||||
0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x1a, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e,
|
||||||
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65,
|
0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70,
|
0x4b, 0x0a, 0x10, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x46, 0x65, 0x65, 0x12, 0x1a, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e,
|
||||||
0x73, 0x65, 0x12, 0x51, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x65, 0x12, 0x1d, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65,
|
0x1b, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74,
|
||||||
0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0b,
|
||||||
0x1a, 0x1e, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e,
|
0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x1d, 0x2e, 0x72, 0x6f,
|
||||||
0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f,
|
||||||
0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x42, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52,
|
0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x56, 0x32, 0x12, 0x1d, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72,
|
0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75,
|
||||||
0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65,
|
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54,
|
0x42, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x56, 0x32,
|
||||||
0x4c, 0x43, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x12, 0x64, 0x0a, 0x13, 0x52, 0x65, 0x73,
|
0x12, 0x1d, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e,
|
||||||
0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x12, 0x25, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73,
|
0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x4c, 0x43, 0x41, 0x74, 0x74, 0x65,
|
||||||
0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
0x6d, 0x70, 0x74, 0x12, 0x64, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73,
|
||||||
|
0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x25, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
|
0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73,
|
||||||
|
0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
|
0x74, 0x1a, 0x26, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65,
|
||||||
|
0x73, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||||
|
0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x13, 0x51, 0x75, 0x65,
|
||||||
|
0x72, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
|
0x12, 0x25, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65,
|
||||||
|
0x72, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x64, 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43,
|
0x6a, 0x0a, 0x15, 0x58, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f,
|
||||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x25, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72,
|
0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x27, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43,
|
0x72, 0x72, 0x70, 0x63, 0x2e, 0x58, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x69, 0x73, 0x73,
|
||||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e,
|
0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4d,
|
0x74, 0x1a, 0x28, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x58, 0x49,
|
||||||
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x73,
|
0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x15, 0x58, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74,
|
0x72, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x17, 0x47,
|
||||||
0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x27,
|
0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x58, 0x49, 0x6d, 0x70, 0x6f,
|
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72,
|
||||||
0x72, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x72, 0x70, 0x63, 0x2e, 0x58, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69,
|
0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65,
|
||||||
0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43,
|
||||||
0x65, 0x12, 0x70, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a,
|
||||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x72,
|
0x17, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72,
|
||||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73,
|
0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f,
|
0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e,
|
||||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x53, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f,
|
0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29,
|
0x5b, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c,
|
||||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69,
|
0x69, 0x74, 0x79, 0x12, 0x22, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e,
|
||||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66,
|
0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,
|
||||||
0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72,
|
||||||
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69,
|
||||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
|
0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72,
|
0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x72, 0x6f, 0x75,
|
||||||
0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x22, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x6f, 0x75, 0x74,
|
||||||
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x62, 0x61,
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||||
0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e,
|
0x72, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52,
|
||||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||||
0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x72, 0x69, 0x62, 0x65, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x25,
|
||||||
0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||||
0x12, 0x1c, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x69,
|
0x72, 0x69, 0x62, 0x65, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65,
|
||||||
0x6c, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70,
|
||||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64,
|
0x63, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x4d, 0x0a,
|
||||||
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a,
|
0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x72,
|
||||||
0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79,
|
||||||
0x65, 0x6e, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63,
|
0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x6f,
|
||||||
0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76,
|
0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53,
|
||||||
0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x6f,
|
0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x03, 0x88, 0x02, 0x01, 0x30, 0x01, 0x12, 0x4f, 0x0a, 0x0c,
|
||||||
0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e,
|
0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x72,
|
||||||
0x74, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61,
|
||||||
0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x53,
|
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72,
|
||||||
0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
0x74, 0x1a, 0x18, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61,
|
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x03, 0x88, 0x02, 0x01, 0x30, 0x01, 0x12, 0x66, 0x0a,
|
||||||
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x03, 0x88, 0x02, 0x01,
|
0x0f, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72,
|
||||||
0x30, 0x01, 0x12, 0x4f, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65,
|
0x12, 0x27, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72,
|
||||||
0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54,
|
0x77, 0x61, 0x72, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
|
||||||
0x72, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x26, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x50,
|
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x48, 0x74, 0x6c,
|
||||||
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x03, 0x88, 0x02,
|
0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x01, 0x30, 0x01, 0x12, 0x66, 0x0a, 0x0f, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72,
|
0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43,
|
||||||
0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x27, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72,
|
0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x22, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e,
|
0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e,
|
||||||
0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a,
|
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e,
|
||||||
0x26, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77,
|
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||||
0x61, 0x72, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74,
|
0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x10, 0x55,
|
0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
|
||||||
0x22, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61,
|
0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x6f, 0x75, 0x74,
|
||||||
0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75,
|
0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e,
|
|
||||||
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
|
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67,
|
|
||||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70,
|
|
||||||
0x63, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -792,6 +792,10 @@ message ForwardHtlcInterceptRequest {
|
|||||||
|
|
||||||
// The onion blob for the next hop
|
// The onion blob for the next hop
|
||||||
bytes onion_blob = 9;
|
bytes onion_blob = 9;
|
||||||
|
|
||||||
|
// The block height at which this htlc will be auto-failed to prevent the
|
||||||
|
// channel from force-closing.
|
||||||
|
int32 auto_fail_height = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1229,6 +1229,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "byte",
|
"format": "byte",
|
||||||
"title": "The onion blob for the next hop"
|
"title": "The onion blob for the next hop"
|
||||||
|
},
|
||||||
|
"auto_fail_height": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"description": "The block height at which this htlc will be auto-failed to prevent the\nchannel from force-closing."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+26
-10
@@ -359,6 +359,24 @@ func createTestPeer(t *testing.T, notifier chainntnfs.ChainNotifier,
|
|||||||
ChainNet: wire.SimNet,
|
ChainNet: wire.SimNet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interceptableSwitchNotifier := &mock.ChainNotifier{
|
||||||
|
EpochChan: make(chan *chainntnfs.BlockEpoch, 1),
|
||||||
|
}
|
||||||
|
interceptableSwitchNotifier.EpochChan <- &chainntnfs.BlockEpoch{
|
||||||
|
Height: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
interceptableSwitch, err := htlcswitch.NewInterceptableSwitch(
|
||||||
|
&htlcswitch.InterceptableSwitchConfig{
|
||||||
|
CltvRejectDelta: testCltvRejectDelta,
|
||||||
|
CltvInterceptDelta: testCltvRejectDelta + 3,
|
||||||
|
Notifier: interceptableSwitchNotifier,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
Addr: cfgAddr,
|
Addr: cfgAddr,
|
||||||
PubKeyBytes: pubKey,
|
PubKeyBytes: pubKey,
|
||||||
@@ -366,16 +384,14 @@ func createTestPeer(t *testing.T, notifier chainntnfs.ChainNotifier,
|
|||||||
ChainIO: chainIO,
|
ChainIO: chainIO,
|
||||||
Switch: mockSwitch,
|
Switch: mockSwitch,
|
||||||
ChanActiveTimeout: chanActiveTimeout,
|
ChanActiveTimeout: chanActiveTimeout,
|
||||||
InterceptSwitch: htlcswitch.NewInterceptableSwitch(
|
InterceptSwitch: interceptableSwitch,
|
||||||
nil, testCltvRejectDelta, false,
|
ChannelDB: dbAlice.ChannelStateDB(),
|
||||||
),
|
FeeEstimator: estimator,
|
||||||
ChannelDB: dbAlice.ChannelStateDB(),
|
Wallet: wallet,
|
||||||
FeeEstimator: estimator,
|
ChainNotifier: notifier,
|
||||||
Wallet: wallet,
|
ChanStatusMgr: chanStatusMgr,
|
||||||
ChainNotifier: notifier,
|
Features: lnwire.NewFeatureVector(nil, lnwire.Features),
|
||||||
ChanStatusMgr: chanStatusMgr,
|
DisconnectPeer: func(b *btcec.PublicKey) error { return nil },
|
||||||
Features: lnwire.NewFeatureVector(nil, lnwire.Features),
|
|
||||||
DisconnectPeer: func(b *btcec.PublicKey) error { return nil },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alicePeer := NewBrontide(*cfg)
|
alicePeer := NewBrontide(*cfg)
|
||||||
|
|||||||
@@ -666,10 +666,18 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.interceptableSwitch = htlcswitch.NewInterceptableSwitch(
|
s.interceptableSwitch, err = htlcswitch.NewInterceptableSwitch(
|
||||||
s.htlcSwitch, lncfg.DefaultFinalCltvRejectDelta,
|
&htlcswitch.InterceptableSwitchConfig{
|
||||||
s.cfg.RequireInterceptor,
|
Switch: s.htlcSwitch,
|
||||||
|
CltvRejectDelta: lncfg.DefaultFinalCltvRejectDelta,
|
||||||
|
CltvInterceptDelta: lncfg.DefaultCltvInterceptDelta,
|
||||||
|
RequireInterceptor: s.cfg.RequireInterceptor,
|
||||||
|
Notifier: s.cc.ChainNotifier,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
s.witnessBeacon = newPreimageBeacon(
|
s.witnessBeacon = newPreimageBeacon(
|
||||||
dbs.ChanStateDB.NewWitnessCache(),
|
dbs.ChanStateDB.NewWitnessCache(),
|
||||||
|
|||||||
Reference in new issue
Block a user