mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Add LndInstanceRemote (#3710)
This commit is contained in:
parent
466de3e46a
commit
f6169cc3af
5 changed files with 171 additions and 16 deletions
|
@ -0,0 +1,119 @@
|
|||
package org.bitcoins.lnd.rpc
|
||||
|
||||
import lnrpc.Invoice.InvoiceState
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.protocol.ln.LnInvoice
|
||||
import org.bitcoins.core.protocol.ln.currency._
|
||||
import org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0
|
||||
import org.bitcoins.testkit.fixtures.RemoteLndFixture
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class LndRemoteClientTest extends RemoteLndFixture {
|
||||
|
||||
it must "get info from lnd" in { lnd =>
|
||||
for {
|
||||
info <- lnd.getInfo
|
||||
} yield assert(info.blockHeight >= 0)
|
||||
}
|
||||
|
||||
it must "create an invoice using sats" in { lnd =>
|
||||
val memo = "this is my memo"
|
||||
val amount = Satoshis(1000)
|
||||
|
||||
for {
|
||||
invoiceResult <- lnd.addInvoice(memo, amount, 1000)
|
||||
} yield {
|
||||
val invoice = invoiceResult.invoice
|
||||
|
||||
assert(invoice.lnTags.description.map(_.string).contains(memo))
|
||||
assert(invoice.amount.map(_.toSatoshis).contains(amount))
|
||||
}
|
||||
}
|
||||
|
||||
it must "create an invoice using msats" in { lnd =>
|
||||
val memo = "this is my memo"
|
||||
val amount = MilliSatoshis(1000)
|
||||
|
||||
for {
|
||||
invoiceResult <- lnd.addInvoice(memo, amount, 1000)
|
||||
} yield {
|
||||
val invoice = invoiceResult.invoice
|
||||
|
||||
assert(invoice.lnTags.description.map(_.string).contains(memo))
|
||||
assert(invoice.amount.map(_.toMSat).contains(amount))
|
||||
}
|
||||
}
|
||||
|
||||
it must "get an on-chain address" in { lnd =>
|
||||
for {
|
||||
addr <- lnd.getNewAddress
|
||||
} yield assert(addr.scriptPubKey.isInstanceOf[P2WPKHWitnessSPKV0])
|
||||
}
|
||||
|
||||
it must "get unspent utxos" in { lnd =>
|
||||
for {
|
||||
utxos <- lnd.listUnspent
|
||||
} yield assert(utxos.isEmpty)
|
||||
}
|
||||
|
||||
it must "look up an invoice" in { lnd =>
|
||||
val memo = "this is my memo"
|
||||
val amount = MilliSatoshis(1000)
|
||||
|
||||
for {
|
||||
invoiceResult <- lnd.addInvoice(memo, amount, 1000)
|
||||
invoice = invoiceResult.invoice
|
||||
_ = {
|
||||
assert(invoice.lnTags.description.map(_.string).contains(memo))
|
||||
assert(invoice.amount.map(_.toMSat).contains(amount))
|
||||
}
|
||||
|
||||
lookupResult <- lnd.lookupInvoice(invoiceResult.rHash)
|
||||
} yield {
|
||||
val lookupInvoice = LnInvoice.fromString(lookupResult.paymentRequest)
|
||||
|
||||
assert(lookupInvoice.lnTags.description.map(_.string).contains(memo))
|
||||
assert(lookupInvoice.amount.map(_.toMSat).contains(amount))
|
||||
assert(lookupResult.state == InvoiceState.OPEN)
|
||||
}
|
||||
}
|
||||
|
||||
it must "get wallet balance" in { lnd =>
|
||||
for {
|
||||
balances <- lnd.walletBalance()
|
||||
} yield {
|
||||
assert(balances.balance == Satoshis.zero)
|
||||
assert(balances.unconfirmedBalance == Satoshis.zero)
|
||||
assert(balances.confirmedBalance == Satoshis.zero)
|
||||
}
|
||||
}
|
||||
|
||||
it must "get channel balance" in { lnd =>
|
||||
for {
|
||||
balances <- lnd.channelBalance()
|
||||
} yield {
|
||||
assert(balances.localBalance == Satoshis.zero)
|
||||
assert(balances.remoteBalance == Satoshis.zero)
|
||||
assert(balances.pendingOpenLocalBalance == Satoshis.zero)
|
||||
assert(balances.pendingOpenRemoteBalance == Satoshis.zero)
|
||||
assert(balances.unsettledLocalBalance == Satoshis.zero)
|
||||
assert(balances.unsettledRemoteBalance == Satoshis.zero)
|
||||
}
|
||||
}
|
||||
|
||||
it must "lease and release an output" in { lnd =>
|
||||
for {
|
||||
utxos <- lnd.listUnspent
|
||||
leaseFs = utxos.map(u => lnd.leaseOutput(u.outPointOpt.get, 100))
|
||||
_ <- Future.sequence(leaseFs)
|
||||
leases <- lnd.listLeases()
|
||||
_ = assert(leases.size == utxos.size)
|
||||
|
||||
releaseFs = utxos.map(u => lnd.releaseOutput(u.outPointOpt.get))
|
||||
_ <- Future.sequence(releaseFs)
|
||||
|
||||
leases <- lnd.listLeases()
|
||||
} yield assert(leases.isEmpty)
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import org.bitcoins.core.wallet.fee.{SatoshisPerKW, SatoshisPerVirtualByte}
|
|||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.lnd.rpc.LndRpcClient._
|
||||
import org.bitcoins.lnd.rpc.LndUtils._
|
||||
import org.bitcoins.lnd.rpc.config.{LndInstance, LndInstanceLocal}
|
||||
import org.bitcoins.lnd.rpc.config._
|
||||
import scodec.bits._
|
||||
import signrpc._
|
||||
import walletrpc.{
|
||||
|
@ -62,12 +62,14 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)(
|
|||
case _: LndInstanceLocal =>
|
||||
require(binaryOpt.isDefined,
|
||||
s"Binary must be defined with a local instance of lnd")
|
||||
case _: LndInstanceRemote => ()
|
||||
}
|
||||
|
||||
/** The command to start the daemon on the underlying OS */
|
||||
override def cmd: String = instance match {
|
||||
case local: LndInstanceLocal =>
|
||||
s"${binaryOpt.get} --lnddir=${local.datadir.toAbsolutePath}"
|
||||
case _: LndInstanceRemote => ""
|
||||
}
|
||||
|
||||
implicit val executionContext: ExecutionContext = system.dispatcher
|
||||
|
|
|
@ -13,18 +13,8 @@ import java.nio.file._
|
|||
import scala.util.Properties
|
||||
|
||||
sealed trait LndInstance {
|
||||
def network: BitcoinNetwork
|
||||
def listenBinding: URI
|
||||
def restUri: URI
|
||||
def rpcUri: URI
|
||||
def bitcoindAuthCredentials: PasswordBased
|
||||
def bitcoindRpcUri: URI
|
||||
def zmqConfig: ZmqConfig
|
||||
def debugLevel: LogLevel
|
||||
def macaroon: String
|
||||
|
||||
def datadir: Path
|
||||
|
||||
def certFile: File
|
||||
}
|
||||
|
||||
|
@ -107,3 +97,6 @@ object LndInstanceLocal
|
|||
config.lndInstance
|
||||
}
|
||||
}
|
||||
|
||||
case class LndInstanceRemote(rpcUri: URI, macaroon: String, certFile: File)
|
||||
extends LndInstance
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.bitcoins.testkit.fixtures
|
||||
|
||||
import org.bitcoins.lnd.rpc.LndRpcClient
|
||||
import org.bitcoins.lnd.rpc.config.LndInstanceRemote
|
||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||
import org.bitcoins.testkit.lnd._
|
||||
import org.bitcoins.testkit.rpc._
|
||||
|
@ -62,3 +63,37 @@ trait DualLndFixture extends BitcoinSFixture with CachedBitcoindV21 {
|
|||
)(test)
|
||||
}
|
||||
}
|
||||
|
||||
trait RemoteLndFixture extends BitcoinSFixture with CachedBitcoindV21 {
|
||||
|
||||
override type FixtureParam = LndRpcClient
|
||||
|
||||
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
|
||||
withLnd(test)
|
||||
}
|
||||
|
||||
def withLnd(test: OneArgAsyncTest): FutureOutcome = {
|
||||
makeDependentFixture[LndRpcClient](
|
||||
() => {
|
||||
for {
|
||||
bitcoind <- cachedBitcoindWithFundsF
|
||||
|
||||
// start and initialize a lnd
|
||||
client = LndRpcTestClient.fromSbtDownload(Some(bitcoind))
|
||||
lnd <- client.start()
|
||||
|
||||
// create a remote instance and client
|
||||
remoteInstance = LndInstanceRemote(lnd.instance.rpcUri,
|
||||
lnd.instance.macaroon,
|
||||
lnd.instance.certFile)
|
||||
remoteLnd = LndRpcClient(remoteInstance)
|
||||
} yield remoteLnd
|
||||
},
|
||||
{ lnd =>
|
||||
for {
|
||||
_ <- lnd.stop()
|
||||
} yield ()
|
||||
}
|
||||
)(test)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.bitcoins.core.protocol.ln.node.NodeId
|
|||
import org.bitcoins.core.protocol.transaction.TransactionOutPoint
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.lnd.rpc.LndRpcClient
|
||||
import org.bitcoins.lnd.rpc.config.LndInstanceLocal
|
||||
import org.bitcoins.lnd.rpc.config.{LndInstanceLocal, LndInstanceRemote}
|
||||
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
|
||||
import org.bitcoins.rpc.config.{
|
||||
BitcoindAuthCredentials,
|
||||
|
@ -22,7 +22,7 @@ import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
|
|||
import org.bitcoins.testkit.util.{FileUtil, TestkitBinaries}
|
||||
|
||||
import java.io.{File, PrintWriter}
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.{InetSocketAddress, URI}
|
||||
import java.nio.file.Path
|
||||
import scala.concurrent.duration.DurationInt
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
@ -75,6 +75,7 @@ trait LndRpcTestUtil extends Logging {
|
|||
|debuglevel=critical
|
||||
|listen=127.0.0.1:$port
|
||||
|rpclisten=127.0.0.1:$rpcPort
|
||||
|externalip=127.0.0.1
|
||||
|bitcoind.rpcuser = ${bitcoindInstance.authCredentials
|
||||
.asInstanceOf[BitcoindAuthCredentials.PasswordBased]
|
||||
.username}
|
||||
|
@ -164,9 +165,14 @@ trait LndRpcTestUtil extends Logging {
|
|||
val infoF = otherClient.getInfo
|
||||
val nodeIdF = client.getInfo.map(_.identityPubkey)
|
||||
val connectionF: Future[Unit] = infoF.flatMap { info =>
|
||||
val uri = otherClient.instance.listenBinding
|
||||
client.connectPeer(NodeId(info.identityPubkey),
|
||||
new InetSocketAddress(uri.getHost, uri.getPort))
|
||||
val uriF: Future[URI] = otherClient.instance match {
|
||||
case local: LndInstanceLocal => Future.successful(local.listenBinding)
|
||||
case _: LndInstanceRemote =>
|
||||
otherClient.getInfo.map(info => new URI(info.uris.head))
|
||||
}
|
||||
uriF.flatMap(uri =>
|
||||
client.connectPeer(NodeId(info.identityPubkey),
|
||||
new InetSocketAddress(uri.getHost, uri.getPort)))
|
||||
}
|
||||
|
||||
def isConnected: Future[Boolean] = {
|
||||
|
|
Loading…
Add table
Reference in a new issue