Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lnrpc+lnwire: append listchannels command with the chan_id and short_chan_id #9390

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions cmd/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/jessevdk/go-flags"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/signal"
Expand Down Expand Up @@ -50,6 +51,14 @@ var (
customDataPattern = regexp.MustCompile(
`"custom_channel_data":\s*"([0-9a-f]+)"`,
)

chanIDPattern = regexp.MustCompile(
`"chan_id":\s*"(\d+)"`,
)

channelPointPattern = regexp.MustCompile(
`"channel_point":\s*"([0-9a-fA-F]+:[0-9]+)"`,
)
)

// replaceCustomData replaces the custom channel data hex string with the
Expand Down Expand Up @@ -86,6 +95,96 @@ func replaceCustomData(jsonBytes []byte) []byte {
return buf.Bytes()
}

// appendShortChanIDStr appends the human readable string representation of
// short_chan_id.
func appendChanIDStr(jsonBytes []byte) []byte {
// If there's nothing to replace, return the original JSON.
if !chanIDPattern.Match(jsonBytes) {
return jsonBytes
}

replacedBytes := chanIDPattern.ReplaceAllFunc(
jsonBytes, func(match []byte) []byte {
// Extract the numeric string from the match
encoded := chanIDPattern.FindStringSubmatch(
string(match),
)[1]

shortChandIDInt, err := strconv.ParseUint(encoded, 10,
64)
if err != nil {
return match
}

// Format a new JSON field for the short_chan_id with
// both its numeric representation and its string
// representation (short_chan_id_str)
updatedField := fmt.Sprintf(`"chan_id": "%s",
"chan_id_str": "%s"`,
encoded,
lnwire.NewShortChanIDFromInt(shortChandIDInt).
String())

// Replace the entire match with the new structure.
return []byte(updatedField)
},
)

var buf bytes.Buffer
err := json.Indent(&buf, replacedBytes, "", " ")
if err != nil {
// If we can't indent the JSON, it likely means the replacement
// data wasn't correct, so we return the original JSON.
return jsonBytes
}

return buf.Bytes()
}

// appendFundingOutpointID appends the funding_outpoint_id which is computed
// using the outpoint of the funding transaction (the txid, and output index).
func appendFundingOutpointID(jsonBytes []byte) []byte {
// If there's nothing to replace, return the original JSON.
if !channelPointPattern.Match(jsonBytes) {
return jsonBytes
}

replacedBytes := channelPointPattern.ReplaceAllFunc(
jsonBytes, func(match []byte) []byte {
channelPoint := channelPointPattern.FindStringSubmatch(
string(match),
)[1]

channelOutPoint, err := wire.NewOutPointFromString(
channelPoint)
if err != nil {
return match
}

// Format a new JSON field computed from the
// channel_point (funding_outpoint_id).
updatedField := fmt.Sprintf(`"channel_point": "%s",
"funding_outpoint_id": "%s"`,
channelPoint,
lnwire.NewChanIDFromOutPoint(*channelOutPoint).
String())

// Replace the entire match with the new structure.
return []byte(updatedField)
},
)

var buf bytes.Buffer
err := json.Indent(&buf, replacedBytes, "", " ")
if err != nil {
// If we can't indent the JSON, it likely means the replacement
// data wasn't correct, so we return the original JSON.
return jsonBytes
}

return buf.Bytes()
}

func getContext() context.Context {
shutdownInterceptor, err := signal.Intercept()
if err != nil {
Expand Down Expand Up @@ -120,8 +219,15 @@ func printRespJSON(resp proto.Message) {
return
}

// Replace custom_channel_data.
jsonBytesReplaced := replaceCustomData(jsonBytes)

// Append the funding_outpoint_id field.
jsonBytesReplaced = appendFundingOutpointID(jsonBytesReplaced)

// Append the chan_id_str field.
jsonBytesReplaced = appendChanIDStr(jsonBytesReplaced)

fmt.Printf("%s\n", jsonBytesReplaced)
}

Expand Down
7 changes: 7 additions & 0 deletions docs/release-notes/release-notes-0.19.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@
This is a protocol gadget required for Dynamic Commitments and Splicing that
will be added later.

* [Added]((https://github.com/lightningnetwork/lnd/pull/9390))
`chan_id_str`, a string representation of `chan_id` in the format
(`block x transaction x output`), and `funding_outpoint_id` to align with the
BOLT-2 Peer Protocol specification for standardized channel identification,
to the `lncli listchannels` output.

## Functional Enhancements
* [Add ability](https://github.com/lightningnetwork/lnd/pull/8998) to paginate
wallet transactions.
Expand Down Expand Up @@ -274,6 +280,7 @@ The underlying functionality between those two options remain the same.
* hieblmi
* Jesse de Wit
* Keagan McClelland
* Nishant Bansal
* Oliver Gugger
* Pins
* Viktor Tigerström
Expand Down
18 changes: 9 additions & 9 deletions lnwire/reply_channel_range_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,9 @@ func TestReplyChannelRangeDecode(t *testing.T) {
"0045a6c4",
expEncoding: EncodingSortedPlain,
expSCIDs: []string{
"0:0:142",
"0:0:15465",
"0:69:42692",
"0x0x142",
"0x0x15465",
"0x69x42692",
},
},
{
Expand All @@ -280,9 +280,9 @@ func TestReplyChannelRangeDecode(t *testing.T) {
"01789c636000833e08659309a65878be010010a9023a",
expEncoding: EncodingSortedZlib,
expSCIDs: []string{
"0:0:142",
"0:0:15465",
"0:4:3318",
"0x0x142",
"0x0x15465",
"0x4x3318",
},
},
{
Expand All @@ -295,9 +295,9 @@ func TestReplyChannelRangeDecode(t *testing.T) {
"000115c000015b300001a0a",
expEncoding: EncodingSortedPlain,
expSCIDs: []string{
"0:0:12355",
"0:7:30934",
"0:70:57793",
"0x0x12355",
"0x7x30934",
"0x70x57793",
},
expTimestamps: Timestamps{
{
Expand Down
2 changes: 1 addition & 1 deletion lnwire/short_channel_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (c ShortChannelID) ToUint64() uint64 {

// String generates a human-readable representation of the channel ID.
func (c ShortChannelID) String() string {
return fmt.Sprintf("%d:%d:%d", c.BlockHeight, c.TxIndex, c.TxPosition)
return fmt.Sprintf("%dx%dx%d", c.BlockHeight, c.TxIndex, c.TxPosition)
}

// Record returns a TLV record that can be used to encode/decode a
Expand Down