Builder's Guide
  • Welcome to the Builder's Guide to the LND Galaxy!
  • The Lightning Network
    • Overview
    • Payment Channels
      • Lifecycle of a Payment Channel
      • Watchtowers
      • Understanding Sweeping
      • Etymology
    • The Gossip Network
      • Identifying Good Peers on the Lightning Network
    • Pathfinding
      • Finding routes in the Lightning Network
      • Channel Fees
      • Multipath Payments (MPP)
    • Lightning Network Invoices
      • Understanding Lightning Invoices
    • Making Payments
      • The Payment Cycle
      • Timelocks
      • ⭐Hashed Timelock Contract (HTLC)
      • Payment Etymology
      • ⭐What Makes a Good Routing Node
      • Understanding Submarine Swaps
      • Instant Submarine Swaps
    • Liquidity
      • ⭐Understanding Liquidity
      • Managing Liquidity on the Lightning Network
      • Liquidity Management for Lightning Merchants
      • How to Get Inbound Capacity on the Lightning Network
      • Lightning Service Provider
    • L402: Lightning HTTP 402 Protocol
      • Macaroons
      • L402
      • 📋Protocol Specification
      • Implementations and Links
    • Taproot Assets
      • Taproot Assets Protocol
      • Taproot Assets on Lightning
      • Edge Nodes
      • Taproot Assets Trustless Swap
      • FAQ
      • Glossary
  • Lightning Network Tools
    • LND
      • 🛠️Get Started
      • lnd.conf
      • First Steps With LND
      • Wallet Management
      • Sending Payments
      • Atomic Multi-path Payments (AMP)
      • Receiving Payments
      • Unconfirmed Bitcoin Transactions
      • Channel Fees
      • Inbound Channel Fees
      • Macaroons
      • Configuring Watchtowers
      • Pathfinding
      • Blinded Paths
      • Key Import
      • Secure Your Lightning Network Node
      • Configuration of a Routing Node
      • Quick Tor Setup
      • Configuring Tor
      • Enable ‘Neutrino mode’ in Bitcoin Core
      • Send Messages With Keysend
      • Partially Signed Bitcoin Transactions
      • Bulk onchain actions with PSBTs
      • Sweeper
      • Debugging LND
      • Fuzzing LND
      • LND API documentation
      • Channel Acceptor
      • RPC Middleware Interceptor
      • HTLC Interceptor
      • NAT Traversal
      • Recovery: Planning for Failure
      • Migrating LND
      • Disaster recovery
      • Contribute to LND
    • Lightning Terminal
      • What is Lightning Terminal?
      • 🛠️Get litd
      • Run litd
      • Integrating litd
      • Demo: Litd Speed Run
      • Connect to Terminal
      • Recommended Channels
      • Rankings
      • Health Checks
      • Liquidity Report
      • Opening Lightning Network Channels
      • Managing Channel Liquidity
      • Autofees
      • AutoOpen
      • LND Accounts
      • Loop and Lightning Terminal
      • Loop Fees
      • Pool and Lightning Terminal
      • Command Line Interface
      • Troubleshooting
      • Lightning Node Connect: Under the hood
      • LNC Node Package
      • LITD API Documentation
      • Privacy and Security
      • Privacy Policy
      • Terms of Use
    • Loop
      • 🛠️Get Started
      • The Loop CLI
      • Autoloop
      • Static Loop In Addresses
      • Instant Loop Outs
      • Peer with Loop
      • Loop API Documentation
    • Pool
      • Overview
      • Quickstart
      • 🛠️Installation
      • First Steps
      • Accounts
      • Orders and Asks
      • Sidecar Channels
      • Zero-confirmation Channels
      • Channel Leases
      • Batch Execution
      • Account Recovery
      • Pool API Documentation
      • FAQs
    • Taproot Assets
      • Get Started
      • First Steps
      • Taproot Assets Channels
      • Asset Decimal Display
      • Become an Edge Node
      • RFQ
      • Collectibles
      • Universes
      • Asset Loop
      • Debugging Tapd
      • Multisignature
      • Minting Assets With an External Signer
      • Lightning Polar
      • Operational Safety Guidelines
      • Taproot Assets API Documentation
    • Aperture
      • ⚒️Get Aperture
      • LNC Backend
      • LNC Mailbox
      • Pricing
    • Faraday
      • 🛠️Get Started
      • The Faraday CLI
      • Faraday API Documentation
  • LAPPs
    • Guides
      • Use Polar to Build Your First LAPP
        • Setup: Local Cluster with Polar
        • Setup: Run the Completed App
        • Setup: Run the App Without LND
      • Add Features
        • Feature 1: Connect to LND
        • Feature 2: Display Node Alias and Balance
        • Feature 3: Sign and Verify Posts
        • Feature 4: Modify Upvote Action
      • Make Your own LNC-powered Application
    • Next Steps
  • Community Resources
    • Resource List
    • Lightning Bulb 💡
    • Glossary
    • FAQ
Powered by GitBook
On this page
  • Code examples:
  • Pool:
  • lndclient:

Was this helpful?

  1. Lightning Network Tools
  2. LND

Channel Acceptor

The channel acceptor API allows you to enforce custom logic on whether an incoming channel should be accepted or not.

PreviousFuzzing LNDNextRPC Middleware Interceptor

Last updated 24 days ago

Was this helpful?

LND’s channel acceptor is a mechanism which you can use to define custom logic with regard to whether an incoming channel should be accepted or not.

This may be useful when restricting channel opens from nodes that meet certain criteria. For example, some nodes may want to restrict channel opens to a desired list of nodes or a specifically defined size. It can also be used to accept channels with a remote channel reserve of zero or to accept zero-confirmation channels.

The channel acceptor is used in Pool to ensure that channels opened through the marketplace have the desired attributes.

In principle, the channel acceptor is relatively simple and does not need to be specifically enabled. When the API endpoints are called (either RPC or REST), a bi-directional channel between LND and the client is established, through which all incoming channel requests are sent.

The client can then respond with either TRUE or FALSE regarding whether the channel should be accepted or not. They can also send a 500 character custom error message to the initiator to inform them about why the channel was denied.

When no channel acceptor is set, all incoming zero-confirmation channels are denied by default.

When using the channel acceptor to accept zero-confirmation channels, please note that both the initiator and the respondent must have the following set in their lnd.conf:

protocol.option-scid-alias=true protocol.zero-conf=true

It is possible to have multiple channel acceptors. If any channel acceptor denies a channel request, LND will deny the channel request as well.

Code examples:

Pool:

// acceptChannel is the callback that is invoked each time a new incoming
// channel message is received in lnd. We inspect it here and if it corresponds
// to a pending channel ID that we have an expectation for, we check whether the
// self chan balance (=push amount) is correct.
func (s *ChannelAcceptor) acceptChannel(_ context.Context,
	req *lndclient.AcceptorRequest) (*lndclient.AcceptorResponse, error) {

	s.expectedChansMtx.Lock()
	defer s.expectedChansMtx.Unlock()

	expectedChanBid, ok := s.expectedChans[req.PendingChanID]

	// It's not a channel we've registered within the funding manager so we
	// just accept it to not interfere with the normal node operation.
	if !ok {
		return &lndclient.AcceptorResponse{Accept: true}, nil
	}

	// The push amount in the acceptor request is in milli sats, we need to
	// convert it first.
	pushAmtSat := lnwire.MilliSatoshi(req.PushAmt).ToSatoshis()

	// Push amount must be exactly what we expect. Otherwise the asker could
	// be trying to cheat.
	if expectedChanBid.SelfChanBalance != pushAmtSat {
		return &lndclient.AcceptorResponse{
			Accept: false,
			Error: fmt.Sprintf("invalid push amount %v",
				req.PushAmt),
		}, nil
	}

	switch expectedChanBid.ChannelType {
	// The bid doesn't have specific requirements for the channel type.
	case order.ChannelTypePeerDependent:
		break

	// The bid expects a channel type that enforces the channel lease
	// maturity in its output scripts.
	case order.ChannelTypeScriptEnforced:
		if req.CommitmentType == nil {
			return &lndclient.AcceptorResponse{
				Accept: false,
				Error:  "expected explicit channel negotiation",
			}, nil
		}

		switch *req.CommitmentType {
		case lnwallet.CommitmentTypeScriptEnforcedLease:
		default:
			return &lndclient.AcceptorResponse{
				Accept: false,
				Error: "expected script enforced channel " +
					"lease commitment type",
			}, nil
		}

	default:
		log.Warnf("Unhandled channel type %v for bid %v",
			expectedChanBid.ChannelType, expectedChanBid.Nonce())
		return &lndclient.AcceptorResponse{
			Accept: false,
			Error:  "internal error",
		}, nil
	}

	fundingFlags := lnwire.FundingFlag(req.ChannelFlags)
	isPrivateChan := fundingFlags&lnwire.FFAnnounceChannel == 0

	// Check that the new channel is announced/unannounced as expected.
	if isPrivateChan != expectedChanBid.UnannouncedChannel {
		var errMsg string
		errTemplate := "expected an %s channel but received an %s one"

		if expectedChanBid.UnannouncedChannel {
			errMsg = fmt.Sprintf(errTemplate, "unannounced",
				"announced")
		} else {
			errMsg = fmt.Sprintf(errTemplate, "announced",
				"unannounced")
		}

		return &lndclient.AcceptorResponse{
			Accept: false,
			Error:  errMsg,
		}, nil
	}

	// Check that the channel is a zero conf channel if we were expecting
	// one.
	if expectedChanBid.ZeroConfChannel {
		if !req.WantsZeroConf {
			return &lndclient.AcceptorResponse{
				Accept: false,
				Error:  "expected zero conf channel",
			}, nil
		}
		return &lndclient.AcceptorResponse{
			Accept:         true,
			MinAcceptDepth: 0,
			ZeroConf:       true,
		}, nil
	}

	return &lndclient.AcceptorResponse{
		Accept: true,
	}, nil
}

lndclient:

	// ChannelAcceptor create a channel acceptor using the accept function
	// passed in. The timeout provided will be used to timeout the passed
	// accept closure when it exceeds the amount of time we allow. Note that
	// this amount should be strictly less than lnd's chanacceptor timeout
	// parameter.
	ChannelAcceptor(ctx context.Context, timeout time.Duration,
		accept AcceptorFunction) (chan error, error)

	// FundingStateStep is a funding related call that allows the execution
	// of some preparatory steps for a funding workflow or manual
	// progression of a funding workflow.
	FundingStateStep(ctx context.Context, req *lnrpc.FundingTransitionMsg) (
		*lnrpc.FundingStateStepResp, error)

	// QueryRoutes can query LND to return a route (with fees) between two
	// vertices.
	QueryRoutes(ctx context.Context, req QueryRoutesRequest) (
		*QueryRoutesResponse, error)

	// CheckMacaroonPermissions allows a client to check the validity of a
	// macaroon.
	CheckMacaroonPermissions(ctx context.Context, macaroon []byte,
		permissions []MacaroonPermission, fullMethod string) (bool,
		error)

	// RegisterRPCMiddleware adds a new gRPC middleware to the interceptor
	// chain. A gRPC middleware is software component external to lnd that
	// aims to add additional business logic to lnd by observing/
	// intercepting/validating incoming gRPC client requests and (if needed)
	// replacing/overwriting outgoing messages before they're sent to the
	// client.
	RegisterRPCMiddleware(ctx context.Context, middlewareName,
		customCaveatName string, readOnly bool, timeout time.Duration,
		intercept InterceptFunction) (chan error, error)

	// SendCustomMessage sends a custom message to a peer.
	SendCustomMessage(ctx context.Context, msg CustomMessage) error

	// SubscribeCustomMessages creates a subscription to custom messages
	// received from our peers.
	SubscribeCustomMessages(ctx context.Context) (<-chan CustomMessage,
		<-chan error, error)
}
API documentation: Channel acceptor
pool/channel_acceptor.go at master · lightninglabs/poolGitHub
How the channel acceptor is used in Pool
lndclient/lightning_client.go at master · lightninglabs/lndclientGitHub
How the channel acceptor is used in lndclient
Logo
Logo