cmd/lncli: implement remaining RPC commands

Currently positional arguments *are not* supported, and all arguments
must be passed via unix-style command line arguments.

In a later commit support for concurrent positional, and manually
specified arguments will be added.
This commit is contained in:
Olaoluwa Osuntokun 2016-06-21 12:35:07 -07:00
parent cf32b07f61
commit 8066195d23
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
2 changed files with 182 additions and 2 deletions

@ -2,21 +2,29 @@ package main
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"strings"
"github.com/Roasbeef/btcd/wire"
"github.com/codegangsta/cli"
"github.com/lightningnetwork/lnd/lnrpc"
"golang.org/x/net/context"
)
// TODO(roasbeef): cli logic for supporting both positional and unix style
// arguments.
func printRespJson(resp interface{}) {
b, err := json.Marshal(resp)
if err != nil {
fatal(err)
}
// TODO(roasbeef): disable 'omitempty' like behavior
var out bytes.Buffer
json.Indent(&out, b, "", "\t")
out.WriteTo(os.Stdout)
@ -32,7 +40,7 @@ var ShellCommand = cli.Command{
var NewAddressCommand = cli.Command{
Name: "newaddress",
Usage: "Generates a new address. Three address types are supported: p2wkh, np2wkh, p2pkh",
Usage: "generates a new address. Three address types are supported: p2wkh, np2wkh, p2pkh",
Action: newAddress,
}
@ -104,7 +112,12 @@ func connectPeer(ctx *cli.Context) {
client := getClient(ctx)
targetAddress := ctx.Args().Get(0)
req := &lnrpc.ConnectPeerRequest{targetAddress}
splitAddr := strings.Split(targetAddress, "@")
addr := &lnrpc.LightningAddress{
PubKeyHash: splitAddr[0],
Host: splitAddr[1],
}
req := &lnrpc.ConnectPeerRequest{addr}
lnid, err := client.ConnectPeer(ctxb, req)
if err != nil {
@ -113,3 +126,166 @@ func connectPeer(ctx *cli.Context) {
printRespJson(lnid)
}
// TODO(roasbeef): default number of confirmations
var OpenChannelCommand = cli.Command{
Name: "openchannel",
Description: "Attempt to open a new channel to an existing peer, " +
"blocking until the channel is 'open'. Once the channel is " +
"open, a channelPoint (txid:vout) of the funding output is " +
"returned.",
Usage: "openchannel --peer_id=X --local_amt=N --remote_amt=N --num_confs=N",
Flags: []cli.Flag{
cli.IntFlag{
Name: "peer_id",
Usage: "the id of the peer to open a channel with",
},
cli.IntFlag{
Name: "local_amt",
Usage: "the number of satoshis the wallet should commit to the channel",
},
cli.IntFlag{
Name: "remote_amt",
Usage: "the number of satoshis the remote peer should commit to the channel",
},
cli.IntFlag{
Name: "num_confs",
Usage: "the number of confirmations required before the " +
"channel is considered 'open'",
},
},
Action: openChannel,
}
func openChannel(ctx *cli.Context) {
// TODO(roasbeef): add deadline to context
ctxb := context.Background()
client := getClient(ctx)
req := &lnrpc.OpenChannelRequest{
TargetPeerId: int32(ctx.Int("peer_id")),
LocalFundingAmount: int64(ctx.Int("local_amt")),
RemoteFundingAmount: int64(ctx.Int("remote_amt")),
NumConfs: uint32(ctx.Int("num_confs")),
}
resp, err := client.OpenChannel(ctxb, req)
if err != nil {
fatal(err)
}
txid, err := wire.NewShaHash(resp.ChannelPoint.FundingTxid)
if err != nil {
fatal(err)
}
index := resp.ChannelPoint.OutputIndex
printRespJson(struct {
ChannelPoint string
}{
ChannelPoint: fmt.Sprintf("%v:%v", txid, index),
},
)
}
// TODO(roasbeef): also allow short relative channel ID.
var CloseChannelCommand = cli.Command{
Name: "closechannel",
Description: "Close an existing channel. The channel can be closed either " +
"cooperatively, or uncooperatively (forced).",
Usage: "closechannel funding_txid output_index time_limit allow_force",
Flags: []cli.Flag{
cli.StringFlag{
Name: "funding_txid",
Usage: "the txid of the channel's funding transaction",
},
cli.IntFlag{
Name: "output_index",
Usage: "the output index for the funding output of the funding " +
"transaction",
},
cli.StringFlag{
Name: "time_limit",
Usage: "a relative deadline afterwhich the attempt should be " +
"abandonded",
},
cli.BoolFlag{
Name: "force",
Usage: "after the time limit has passed, attempted an " +
"uncooperative closure",
},
},
Action: closeChannel,
}
func closeChannel(ctx *cli.Context) {
ctxb := context.Background()
client := getClient(ctx)
txid, err := hex.DecodeString(ctx.String("funding_txid"))
if err != nil {
fatal(err)
}
req := &lnrpc.CloseChannelRequest{
ChannelPoint: &lnrpc.ChannelPoint{
FundingTxid: txid,
OutputIndex: uint32(ctx.Int("output_index")),
},
}
resp, err := client.CloseChannel(ctxb, req)
if err != nil {
fatal(err)
}
printRespJson(resp)
}
var ListPeersCommand = cli.Command{
Name: "listpeers",
Description: "List all active, currently connected peers.",
Action: listPeers,
}
func listPeers(ctx *cli.Context) {
ctxb := context.Background()
client := getClient(ctx)
req := &lnrpc.ListPeersRequest{}
resp, err := client.ListPeers(ctxb, req)
if err != nil {
fatal(err)
}
printRespJson(resp)
}
var WalletBalanceCommand = cli.Command{
Name: "walletbalance",
Description: "compute and display the wallet's current balance",
Usage: "walletbalance --witness_only=[true|false]",
Flags: []cli.Flag{
cli.BoolFlag{
Name: "witness_only",
Usage: "if only witness outputs should be considered when " +
"calculating the wallet's balance",
},
},
Action: walletBalance,
}
func walletBalance(ctx *cli.Context) {
ctxb := context.Background()
client := getClient(ctx)
req := &lnrpc.WalletBalanceRequest{
WitnessOnly: ctx.Bool("witness_only"),
}
resp, err := client.WalletBalance(ctxb, req)
if err != nil {
fatal(err)
}
printRespJson(resp)
}

@ -51,6 +51,10 @@ func main() {
NewAddressCommand,
SendManyCommand,
ConnectCommand,
OpenChannelCommand,
CloseChannelCommand,
ListPeersCommand,
WalletBalanceCommand,
ShellCommand,
}