mirror of
https://github.com/RoboSats/robosats.git
synced 2024-09-11 14:05:51 +03:00
Add draft LND gRCP mocks
This commit is contained in:
parent
4270f2d0a2
commit
89ae6cd4a6
@ -45,6 +45,17 @@ DISABLE_ONCHAIN = config("DISABLE_ONCHAIN", cast=bool, default=True)
|
||||
MAX_SWAP_AMOUNT = config("MAX_SWAP_AMOUNT", cast=int, default=500_000)
|
||||
|
||||
|
||||
# Logger function used to build tests/mocks/lnd.py
|
||||
def log(name, request, response):
|
||||
if not config("LOG_LND", cast=bool, default=True):
|
||||
return
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_message = f"######################################\nEvent: {name}\nTime: {current_time}\nRequest:\n{request}\nResponse:\n{response}\nType: {type(response)}\n"
|
||||
|
||||
with open("lnd_log.txt", "a") as file:
|
||||
file.write(log_message)
|
||||
|
||||
|
||||
class LNDNode:
|
||||
os.environ["GRPC_SSL_CIPHER_SUITES"] = "HIGH+ECDSA"
|
||||
|
||||
@ -76,6 +87,7 @@ class LNDNode:
|
||||
try:
|
||||
request = verrpc.VersionRequest()
|
||||
response = cls.verstub.GetVersion(request)
|
||||
log("verstub.GetVersion", request, response)
|
||||
return "v" + response.version
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@ -86,17 +98,21 @@ class LNDNode:
|
||||
"""Decodes a lightning payment request (invoice)"""
|
||||
request = lnrpc.PayReqString(pay_req=invoice)
|
||||
response = cls.lightningstub.DecodePayReq(request)
|
||||
log("lightningstub.DecodePayReq", request, response)
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def estimate_fee(cls, amount_sats, target_conf=2, min_confs=1):
|
||||
"""Returns estimated fee for onchain payouts"""
|
||||
is_testnet = lightningstub.GetInfo(lnrpc.GetInfoRequest()).testnet
|
||||
if is_testnet:
|
||||
|
||||
request = lnrpc.GetInfoRequest()
|
||||
response = lightningstub.GetInfo(request)
|
||||
log("lightningstub.GetInfo", request, response)
|
||||
|
||||
if response.testnet:
|
||||
dummy_address = "tb1qehyqhruxwl2p5pt52k6nxj4v8wwc3f3pg7377x"
|
||||
else:
|
||||
dummy_address = "bc1qgxwaqe4m9mypd7ltww53yv3lyxhcfnhzzvy5j3"
|
||||
|
||||
# We assume segwit. Use hardcoded address as shortcut so there is no need of user inputs yet.
|
||||
request = lnrpc.EstimateFeeRequest(
|
||||
AddrToAmount={dummy_address: amount_sats},
|
||||
@ -106,6 +122,7 @@ class LNDNode:
|
||||
)
|
||||
|
||||
response = cls.lightningstub.EstimateFee(request)
|
||||
log("lightningstub.EstimateFee", request, response)
|
||||
|
||||
return {
|
||||
"mining_fee_sats": response.fee_sat,
|
||||
@ -120,6 +137,7 @@ class LNDNode:
|
||||
"""Returns onchain balance"""
|
||||
request = lnrpc.WalletBalanceRequest()
|
||||
response = cls.lightningstub.WalletBalance(request)
|
||||
log("lightningstub.WalletBalance", request, response)
|
||||
|
||||
return {
|
||||
"total_balance": response.total_balance,
|
||||
@ -135,6 +153,7 @@ class LNDNode:
|
||||
"""Returns channels balance"""
|
||||
request = lnrpc.ChannelBalanceRequest()
|
||||
response = cls.lightningstub.ChannelBalance(request)
|
||||
log("lightningstub.ChannelBalance", request, response)
|
||||
|
||||
return {
|
||||
"local_balance": response.local_balance.sat,
|
||||
@ -169,6 +188,7 @@ class LNDNode:
|
||||
onchainpayment.status = on_mempool_code
|
||||
onchainpayment.save(update_fields=["status"])
|
||||
response = cls.lightningstub.SendCoins(request)
|
||||
log("lightningstub.SendCoins", request, response)
|
||||
|
||||
if response.txid:
|
||||
onchainpayment.txid = response.txid
|
||||
@ -192,6 +212,7 @@ class LNDNode:
|
||||
"""Cancels or returns a hold invoice"""
|
||||
request = invoicesrpc.CancelInvoiceMsg(payment_hash=bytes.fromhex(payment_hash))
|
||||
response = cls.invoicesstub.CancelInvoice(request)
|
||||
log("invoicesstub.CancelInvoice", request, response)
|
||||
# Fix this: tricky because canceling sucessfully an invoice has no response. TODO
|
||||
return str(response) == "" # True if no response, false otherwise.
|
||||
|
||||
@ -200,6 +221,7 @@ class LNDNode:
|
||||
"""settles a hold invoice"""
|
||||
request = invoicesrpc.SettleInvoiceMsg(preimage=bytes.fromhex(preimage))
|
||||
response = cls.invoicesstub.SettleInvoice(request)
|
||||
log("invoicesstub.SettleInvoice", request, response)
|
||||
# Fix this: tricky because settling sucessfully an invoice has None response. TODO
|
||||
return str(response) == "" # True if no response, false otherwise.
|
||||
|
||||
@ -215,7 +237,6 @@ class LNDNode:
|
||||
time,
|
||||
):
|
||||
"""Generates hold invoice"""
|
||||
|
||||
hold_payment = {}
|
||||
# The preimage is a random hash of 256 bits entropy
|
||||
preimage = hashlib.sha256(secrets.token_bytes(nbytes=32)).digest()
|
||||
@ -233,6 +254,7 @@ class LNDNode:
|
||||
cltv_expiry=cltv_expiry_blocks,
|
||||
)
|
||||
response = cls.invoicesstub.AddHoldInvoice(request)
|
||||
log("invoicesstub.AddHoldInvoice", request, response)
|
||||
|
||||
hold_payment["invoice"] = response.payment_request
|
||||
payreq_decoded = cls.decode_payreq(hold_payment["invoice"])
|
||||
@ -257,6 +279,7 @@ class LNDNode:
|
||||
payment_hash=bytes.fromhex(lnpayment.payment_hash)
|
||||
)
|
||||
response = cls.invoicesstub.LookupInvoiceV2(request)
|
||||
log("invoicesstub.LookupInvoiceV2", request, response)
|
||||
|
||||
# Will fail if 'unable to locate invoice'. Happens if invoice expiry
|
||||
# time has passed (but these are 15% padded at the moment). Should catch it
|
||||
@ -297,6 +320,7 @@ class LNDNode:
|
||||
payment_hash=bytes.fromhex(lnpayment.payment_hash)
|
||||
)
|
||||
response = cls.invoicesstub.LookupInvoiceV2(request)
|
||||
log("invoicesstub.LookupInvoiceV2", request, response)
|
||||
|
||||
status = lnd_response_state_to_lnpayment_status[response.state]
|
||||
|
||||
@ -442,6 +466,7 @@ class LNDNode:
|
||||
)
|
||||
|
||||
for response in cls.routerstub.SendPaymentV2(request):
|
||||
log("routerstub.SendPaymentV2", request, response)
|
||||
if (
|
||||
response.status == lnrpc.Payment.PaymentStatus.UNKNOWN
|
||||
): # Status 0 'UNKNOWN'
|
||||
@ -597,6 +622,7 @@ class LNDNode:
|
||||
|
||||
try:
|
||||
for response in cls.routerstub.SendPaymentV2(request):
|
||||
log("routerstub.SendPaymentV2", request, response)
|
||||
handle_response(response)
|
||||
|
||||
except Exception as e:
|
||||
@ -609,6 +635,7 @@ class LNDNode:
|
||||
)
|
||||
|
||||
for response in cls.routerstub.TrackPaymentV2(request):
|
||||
log("routerstub.TrackPaymentV2", request, response)
|
||||
handle_response(response, was_in_transit=True)
|
||||
|
||||
except Exception as e:
|
||||
@ -648,6 +675,7 @@ class LNDNode:
|
||||
)
|
||||
|
||||
for response in cls.routerstub.TrackPaymentV2(request):
|
||||
log("routerstub.TrackPaymentV2", request, response)
|
||||
handle_response(response, was_in_transit=True)
|
||||
|
||||
elif "invoice is already paid" in str(e):
|
||||
@ -658,6 +686,7 @@ class LNDNode:
|
||||
)
|
||||
|
||||
for response in cls.routerstub.TrackPaymentV2(request):
|
||||
log("routerstub.TrackPaymentV2", request, response)
|
||||
handle_response(response)
|
||||
|
||||
else:
|
||||
@ -721,6 +750,7 @@ class LNDNode:
|
||||
allow_self_payment=ALLOW_SELF_KEYSEND,
|
||||
)
|
||||
for response in cls.routerstub.SendPaymentV2(request):
|
||||
log("routerstub.SendPaymentV2", request, response)
|
||||
if response.status == lnrpc.Payment.PaymentStatus.IN_FLIGHT:
|
||||
keysend_payment["status"] = LNPayment.Status.FLIGHT
|
||||
if response.status == lnrpc.Payment.PaymentStatus.SUCCEEDED:
|
||||
@ -744,6 +774,7 @@ class LNDNode:
|
||||
"""Just as it sounds. Better safe than sorry!"""
|
||||
request = invoicesrpc.LookupInvoiceMsg(payment_hash=bytes.fromhex(payment_hash))
|
||||
response = cls.invoicesstub.LookupInvoiceV2(request)
|
||||
log("invoicesstub.LookupInvoiceV2", request, response)
|
||||
|
||||
return (
|
||||
response.state == lnrpc.Invoice.InvoiceState.SETTLED
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM lightninglabs/lnd:v0.16.3-beta
|
||||
FROM lightninglabs/lnd:v0.17.0-beta
|
||||
|
||||
ARG LOCAL_USER_ID=9999
|
||||
ARG LOCAL_GROUP_ID=9999
|
||||
|
@ -1,11 +1,11 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
||||
# Mock up of LND gRPC responses
|
||||
|
||||
|
||||
class MockLightningStub:
|
||||
def GetInfo(self, request):
|
||||
response = MagicMock()
|
||||
# Set the testnet attribute to True for testing purposes
|
||||
response.testnet = True
|
||||
return response
|
||||
|
||||
@ -15,18 +15,120 @@ class MockLightningStub:
|
||||
response.sat_per_vbyte = 13
|
||||
return response
|
||||
|
||||
def DecodePayReq(self, request):
|
||||
response = MagicMock()
|
||||
if request.pay_req == "lntb17314....x":
|
||||
response.destination = "00000000"
|
||||
response.payment_hash = "00000000"
|
||||
response.num_satoshis = 1731
|
||||
response.timestamp = 1699359597
|
||||
response.expiry = 450
|
||||
response.description = "Payment reference: xxxxxxxxxxxxxxxxxxxxxxx. This payment WILL FREEZE IN YOUR WALLET, check on RoboSats if the lock was successful. It will be unlocked (fail) unless you cheat or cancel unilaterally."
|
||||
response.cltv_expiry = 650
|
||||
response.payment_addr = "\275\205\224\002\036h\322"
|
||||
response.num_msat = 1731000
|
||||
|
||||
def CancelInvoice(self, request):
|
||||
response = MagicMock()
|
||||
if request == b"xU\305\212\306":
|
||||
response = {}
|
||||
return response
|
||||
|
||||
def WalletBalance(self, request):
|
||||
response = MagicMock()
|
||||
response.total_balance = 10_000_000
|
||||
response.confirmed_balance = 9_000_000
|
||||
response.unconfirmed_balance = 1_000_000
|
||||
response.reserved_balance_anchor_chan = 30_000
|
||||
response.account_balance = {}
|
||||
return response
|
||||
|
||||
def ChannelBalance(self, request):
|
||||
response = MagicMock()
|
||||
response.balance: 10_000_000
|
||||
response.local_balance.sat = 10_000_000
|
||||
response.local_balance.msat = 10_000_000_000
|
||||
response.remote_balance.sat = 30_000_000
|
||||
response.remote_balance.msat = 30_000_000_000
|
||||
response.unsettled_local_balance.sat = 500_000
|
||||
response.unsettled_local_balance.msat = 500_000_000
|
||||
response.unsettled_remote_balance.sat = 100_000
|
||||
response.unsettled_remote_balance.msat = 100_000_000
|
||||
response.pending_open_local_balance = 2_000_000
|
||||
response.pending_open_local_balance = 2_000_000_000
|
||||
response.pending_open_remote_balance = 5_000_000
|
||||
response.pending_open_remote_balance = 5_000_000_000
|
||||
return response
|
||||
|
||||
def SendCoins(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
|
||||
class MockInvoicesStub:
|
||||
pass
|
||||
def AddHoldInvoice(self, request):
|
||||
response = MagicMock()
|
||||
if request.value == 1731:
|
||||
response.payment_request = "lntb17314....x"
|
||||
response.add_index = 1
|
||||
response.payment_addr = b"\275\205\322"
|
||||
|
||||
def CancelInvoice(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
def SettleInvoice(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
def LookupInvoiceV2(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
|
||||
class MockRouterStub:
|
||||
pass
|
||||
def ResetMissionControl(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
def SendPaymentV2(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
def TrackPaymentV2(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
|
||||
class MockSignerStub:
|
||||
pass
|
||||
def SignMessage(self, request):
|
||||
response = MagicMock()
|
||||
return response
|
||||
|
||||
|
||||
class MockVersionerStub:
|
||||
pass
|
||||
def GetVersion(self, request):
|
||||
response = MagicMock()
|
||||
response.commit = "v0.17.0-beta"
|
||||
response.commit_hash = "2fb150c8fe827df9df0520ef9916b3afb7b03a8d"
|
||||
response.version = "0.17.0-beta"
|
||||
response.app_minor = 17
|
||||
response.app_patch = 0
|
||||
response.app_pre_release = "beta"
|
||||
response.build_tags = [
|
||||
"autopilotrpc",
|
||||
"signrpc",
|
||||
"walletrpc",
|
||||
"chainrpc",
|
||||
"invoicesrpc",
|
||||
"watchtowerrpc",
|
||||
"neutrinorpc",
|
||||
"monitoring",
|
||||
"peersrpc",
|
||||
"kvdb_postgres",
|
||||
"kvdb_etcd",
|
||||
"kvdb_sqlite",
|
||||
"go1.20.3",
|
||||
]
|
||||
response.go_version = "go1.21.0"
|
||||
return response
|
||||
|
Loading…
Reference in New Issue
Block a user