如何使用`node.js`在 Javascript 中编写一个简单的 `lnd` 客户端

本文介绍了如何使用 Node.js 和 gRPC 编写一个简单的 lnd 客户端。内容包括环境配置、依赖安装、客户端创建以及示例代码, 演示了简单RPC调用、响应流式RPC和双向流式RPC的使用方法,以及如何使用Macaroons进行身份验证。文章还提供了在线API文档链接。

如何使用 node.js 在 Javascript 中编写一个简单的 lnd 客户端

设置和安装

首先,你需要初始化一个简单的 nodejs 项目:

npm init (或者 npm init -f,如果你想使用默认值而不做任何提示)

然后你需要安装 Javascript grpc 和 proto loader 库的依赖:

npm install @grpc/grpc-js @grpc/proto-loader --save

你还需要将 lndlightning.proto 文件复制到你的项目目录中 (或者至少是你的 Javascript 代码可以访问到的地方)。

lightning.proto 文件位于 lnd 源码的 lnrpc 目录中

导入和客户端

每次你使用 Javascript gRPC 时,你都需要导入 @grpc/grpc-js,加载 lightning.proto,并创建一个到你的客户端的连接,就像这样。

请注意,当使用 IP 地址连接到节点时(例如,192.168.1.21 而不是 localhost),你需要将 --tlsextraip=192.168.1.21 添加到你的 lnd 配置中,并重新生成证书(删除 tls.cert 和 tls.key 并重启 lnd)。

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const fs = require("fs");

// 由于更新的 ECDSA 生成的 tls.cert,我们需要让 gRPC 知道
// 我们需要使用该密码套件,否则当我们与 lnd rpc 服务器通信时,
// 会出现握手错误。
process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA'

// 我们需要给 proto loader 一些额外的选项,否则代码将无法
// 完全与 lnd 一起工作。
const loaderOptions = {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
};
const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions);

//  Lnd 证书位于 Linux 上的 ~/.lnd/tls.cert 和
//  Mac 上的 ~/Library/Application Support/Lnd/tls.cert
let lndCert = fs.readFileSync("~/.lnd/tls.cert");
let credentials = grpc.credentials.createSsl(lndCert);
let lnrpcDescriptor = grpc.loadPackageDefinition(packageDefinition);
let lnrpc = lnrpcDescriptor.lnrpc;
let lightning = new lnrpc.Lightning('localhost:10009', credentials);

例子

让我们来看一些 Javascript gRPC 客户端的例子。这些例子 假设你至少运行了两个 lnd 节点,其中一个节点的 RPC 位置在默认的 localhost:10009,并且两个节点之间有一个开放的通道。

简单的 RPC

lightning.getInfo({}, function(err, response) {
  if (err) {
    console.log('Error: ' + err);
  }
  console.log('GetInfo:', response);
});

你应该在你的控制台中得到类似这样的东西:

GetInfo: { identity_pubkey: '03c892e3f3f077ea1e381c081abb36491a2502bc43ed37ffb82e264224f325ff27',
  alias: '',
  num_pending_channels: 0,
  num_active_channels: 1,
  num_inactive_channels: 0,
  num_peers: 1,
  block_height: 1006,
  block_hash: '198ba1dc43b4190e507fa5c7aea07a74ec0009a9ab308e1736dbdab5c767ff8e',
  synced_to_chain: false,
  testnet: false,
  chains: [ 'bitcoin' ] }

响应流式 RPC

let call = lightning.subscribeInvoices({});
call.on('data', function(invoice) {
    console.log(invoice);
})
.on('end', function() {
  // 服务器已完成发送
})
.on('status', function(status) {
  // 处理状态
  console.log("Current status" + status);
});

现在,在 localhost:10009 为你的节点创建一个 invoice 并且从另一个节点向 它发送一笔支付。

$ lncli addinvoice --amt=100
{
    "r_hash": <RHASH>,
    "pay_req": <PAYMENT_REQUEST>
}
$ lncli sendpayment --pay_req=<PAYMENT_REQUEST>

你的 Javascript 控制台现在应该显示最近满足的 invoice 的详细信息。

双向流式 RPC

这个例子有一些依赖:

$  npm install --save async lodash

你可以在 shell 中运行以下命令,或者将其放在程序中并像这样运行它 node script.js

// 加载一些特定于此示例的库
const async = require('async');
const _ = require('lodash');

let dest_pubkey = <RECEIVER_ID_PUBKEY>;
let dest_pubkey_bytes = new Buffer(dest_pubkey, "hex");

// 在双向流上设置一个监听器
let call = lightning.sendPayment();
call.on('data', function(payment) {
  console.log("Payment sent:");
  console.log(payment);
});
call.on('end', function() {
  // 服务器已完成
  console.log("END");
});

// 你可以像这样发送单笔支付
call.write({ dest: dest_pubkey_bytes, amt: 6969 });

// 或者像这样发送一堆
function paymentSender(destination, amount) {
  return function(callback) {
    console.log("Sending " + amount + " satoshis");
    console.log("To: " + destination);
    call.write({
      dest: destination,
      amt: amount
    });
    _.delay(callback, 2000);
  };
}
let payment_senders = [];
for (let i = 0; i < 10; i++) {
  payment_senders[i] = paymentSender(dest_pubkey_bytes, 100);
}
async.series(payment_senders, function() {
  call.end();
});

这个例子会每 2 秒发送一笔100 satoshis 的支付。

使用 Macaroons

要使用 macaroons 进行身份验证,你需要将 macaroon 包含在每个请求的元数据中。

以下代码段会将 macaroon 自动添加到每个请求:

const fs = require('fs');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const loaderOptions = {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
};
const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions);

process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA'

// Lnd admin macaroon 位于 Linux 上的 ~/.lnd/data/chain/bitcoin/simnet/admin.macaroon 和
// Mac 上的 ~/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon
let m = fs.readFileSync('~/.lnd/data/chain/bitcoin/simnet/admin.macaroon');
let macaroon = m.toString('hex');

// 构建元数据凭证
let metadata = new grpc.Metadata()
metadata.add('macaroon', macaroon)
let macaroonCreds = grpc.credentials.createFromMetadataGenerator((_args, callback) => {
  callback(null, metadata);
});

// 使用与之前相同的证书构建 ssl 凭证
let lndCert = fs.readFileSync("~/.lnd/tls.cert");
let sslCreds = grpc.credentials.createSsl(lndCert);

// 组合证书凭证和 macaroon 身份验证凭证
// 以便每个调用都经过正确加密和身份验证
let credentials = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds);

// 在创建通道时传递凭证
let lnrpcDescriptor = grpc.loadPackageDefinition(packageDefinition);
let lnrpc = lnrpcDescriptor.lnrpc;
let client = new lnrpc.Lightning('some.address:10009', credentials);

client.getInfo({}, (err, response) => {
  if (err) {
    console.log('Error: ' + err);
  }
  console.log('GetInfo:', response);
});

结论

有了以上内容,你应该已经将所有 lnd 相关的 gRPC 依赖项本地安装在你的项目中。为了加快 Javascript 中 protofbuf 的使用,请参阅 这个官方 protobuf 参考资料,针对 Javascript。 此外,这个官方 gRPC 资源 提供了更多 关于如何从 node.js 驱动 gRPC 的细节。

API 文档

有一个在线 API 文档 可用,其中显示了所有当前存在的 RPC 方法,包括有关如何使用它们的代码片段。

  • 原文链接: github.com/lightningnetw...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
lightningnetwork
lightningnetwork
江湖只有他的大名,没有他的介绍。