From ca2d92c30ca2c9db7a67d7ed44963cd52ea5478e Mon Sep 17 00:00:00 2001 From: cryptosharks131 Date: Mon, 7 Jun 2021 11:02:03 -0400 Subject: [PATCH] Add new api serializers to replace forms and few updates to rebalancer and html forms --- gui/forms.py | 4 +- gui/rebalancer.py | 2 +- gui/serializers.py | 20 +++++++- gui/templates/home.html | 6 +-- gui/urls.py | 15 ++++-- gui/views.py | 110 +++++++++++++++++++++++++++++++++++----- 6 files changed, 133 insertions(+), 24 deletions(-) diff --git a/gui/forms.py b/gui/forms.py index 56bdee7..6f9fc53 100644 --- a/gui/forms.py +++ b/gui/forms.py @@ -39,8 +39,8 @@ class CloseChannelForm(forms.Form): force = forms.BooleanField(widget=forms.CheckboxSelectMultiple, required=False) class ConnectPeerForm(forms.Form): - peer_pubkey = forms.CharField(label='funding_txid', max_length=66) - host = forms.CharField(label='funding_txid', max_length=120) + peer_pubkey = forms.CharField(label='peer_pubkey', max_length=66) + host = forms.CharField(label='host', max_length=120) class AddInvoiceForm(forms.Form): value = forms.IntegerField(label='value') diff --git a/gui/rebalancer.py b/gui/rebalancer.py index 39f7cad..34d9a02 100644 --- a/gui/rebalancer.py +++ b/gui/rebalancer.py @@ -107,7 +107,7 @@ def auto_schedule(): else: LocalSettings(key='AR-Inbound%', value='0.85').save() inbound_percent = 0.85 * 100 - outbound_cans = list(auto_rebalance_channels.filter(percent_outbound__gte=outbound_percent).values_list('chan_id', flat=True)) + outbound_cans = list(auto_rebalance_channels.filter(auto_rebalance=False, percent_outbound__gte=outbound_percent).values_list('chan_id', flat=True)) inbound_cans = auto_rebalance_channels.filter(auto_rebalance=True, percent_inbound__gte=inbound_percent) if len(inbound_cans) > 0 and len(outbound_cans) > 0: if LocalSettings.objects.filter(key='AR-Target%').exists(): diff --git a/gui/serializers.py b/gui/serializers.py index 406d1cd..86c054b 100644 --- a/gui/serializers.py +++ b/gui/serializers.py @@ -35,4 +35,22 @@ class RebalancerSerializer(serializers.HyperlinkedModelSerializer): status = serializers.ReadOnlyField() class Meta: model = Rebalancer - exclude = [] \ No newline at end of file + exclude = [] + +class ConnectPeerSerializer(serializers.Serializer): + peer_pubkey = serializers.CharField(label='peer_pubkey', max_length=66) + host = serializers.CharField(label='host', max_length=120) + +class OpenChannelSerializer(serializers.Serializer): + peer_pubkey = serializers.CharField(label='peer_pubkey', max_length=66) + local_amt = serializers.IntegerField(label='local_amt') + sat_per_byte = serializers.IntegerField(label='sat_per_btye') + +class CloseChannelSerializer(serializers.Serializer): + funding_txid = serializers.CharField(label='funding_txid', max_length=64) + output_index = serializers.IntegerField(label='output_index') + target_fee = serializers.IntegerField(label='target_fee') + force = serializers.BooleanField(default=False) + +class AddInvoiceSerializer(serializers.Serializer): + value = serializers.IntegerField(label='value') \ No newline at end of file diff --git a/gui/templates/home.html b/gui/templates/home.html index 011880c..1865c51 100644 --- a/gui/templates/home.html +++ b/gui/templates/home.html @@ -351,7 +351,7 @@ - + @@ -366,7 +366,7 @@ - + @@ -417,7 +417,7 @@ - + diff --git a/gui/urls.py b/gui/urls.py index 83b26e9..62cd321 100644 --- a/gui/urls.py +++ b/gui/urls.py @@ -13,13 +13,18 @@ urlpatterns = [ path('', views.home, name='home'), path('route', views.route, name='route'), path('peers', views.peers, name='peers'), - path('openchannel/', views.open_channel, name='open-channel'), - path('closechannel/', views.close_channel, name='close-channel'), - path('connectpeer/', views.connect_peer, name='connect-peer'), - path('newaddress/', views.new_address, name='new-address'), - path('createinvoice/', views.add_invoice, name='add-invoice'), + path('openchannel/', views.open_channel_form, name='open-channel-form'), + path('closechannel/', views.close_channel_form, name='close-channel-form'), + path('connectpeer/', views.connect_peer_form, name='connect-peer-form'), + path('newaddress/', views.new_address_form, name='new-address-form'), + path('createinvoice/', views.add_invoice_form, name='add-invoice-form'), path('rebalancer/', views.rebalance, name='rebalancer'), path('updatechanpolicy/', views.update_chan_policy, name='updatechanpolicy'), path('autorebalance/', views.auto_rebalance, name='auto-rebalance'), path('api/', include(router.urls), name='api-root'), + path('api/connectpeer/', views.connect_peer, name='connect-peer'), + path('api/openchannel/', views.open_channel, name='open-channel'), + path('api/closechannel/', views.close_channel, name='close-channel'), + path('api/createinvoice/', views.add_invoice, name='add-invoice'), + path('api/newaddress/', views.new_address, name='new-address'), ] diff --git a/gui/views.py b/gui/views.py index 209595e..29ffeea 100644 --- a/gui/views.py +++ b/gui/views.py @@ -3,13 +3,13 @@ from django.contrib import messages from django.shortcuts import render, redirect from django.db.models import Sum from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework.decorators import api_view from .forms import OpenChannelForm, CloseChannelForm, ConnectPeerForm, AddInvoiceForm, RebalancerForm, ChanPolicyForm, AutoRebalanceForm from .models import Payments, PaymentHops, Invoices, Forwards, Channels, Rebalancer, LocalSettings -from .serializers import PaymentSerializer, InvoiceSerializer, ForwardSerializer, ChannelSerializer, RebalancerSerializer +from .serializers import ConnectPeerSerializer, OpenChannelSerializer, CloseChannelSerializer, AddInvoiceSerializer, PaymentSerializer, InvoiceSerializer, ForwardSerializer, ChannelSerializer, RebalancerSerializer from . import rpc_pb2 as ln from . import rpc_pb2_grpc as lnrpc -from . import router_pb2 as lnr -from . import router_pb2_grpc as lnrouter #Define lnd connection for repeated use def lnd_connect(): @@ -50,7 +50,7 @@ def home(request): total_invoices = Invoices.objects.filter(state=1).count() total_received = 0 if total_invoices == 0 else Invoices.objects.aggregate(Sum('amt_paid'))['amt_paid__sum'] #Get recorded forwarding events - forwards = Forwards.objects.all().order_by('-forward_date') + forwards = Forwards.objects.all().order_by('-id') total_forwards = Forwards.objects.count() total_value_forwards = 0 if total_forwards == 0 else int(Forwards.objects.aggregate(Sum('amt_out_msat'))['amt_out_msat__sum']/1000) total_earned = 0 if total_forwards == 0 else Forwards.objects.aggregate(Sum('fee'))['fee__sum'] @@ -146,7 +146,7 @@ def peers(request): else: return redirect('home') -def open_channel(request): +def open_channel_form(request): if request.method == 'POST': form = OpenChannelForm(request.POST) if form.is_valid(): @@ -169,7 +169,7 @@ def open_channel(request): else: return redirect('home') -def close_channel(request): +def close_channel_form(request): if request.method == 'POST': form = CloseChannelForm(request.POST) if form.is_valid(): @@ -192,7 +192,7 @@ def close_channel(request): break except Exception as e: error = str(e) - messages.error(request, 'Channel creation failed! Error: ' + error) + messages.error(request, 'Channel close failed! Error: ' + error) return redirect('home') else: messages.error(request, 'Invalid Request. Please try again.') @@ -200,7 +200,7 @@ def close_channel(request): else: return redirect('home') -def connect_peer(request): +def connect_peer_form(request): if request.method == 'POST': form = ConnectPeerForm(request.POST) if form.is_valid(): @@ -223,7 +223,7 @@ def connect_peer(request): else: return redirect('home') -def new_address(request): +def new_address_form(request): if request.method == 'POST': try: stub = lnrpc.LightningStub(lnd_connect()) @@ -236,9 +236,9 @@ def new_address(request): else: return redirect('home') -def add_invoice(request): +def add_invoice_form(request): if request.method == 'POST': - form = AddInvoice(request.POST) + form = AddInvoiceForm(request.POST) if form.is_valid(): try: stub = lnrpc.LightningStub(lnd_connect()) @@ -412,4 +412,90 @@ class RebalancerViewSet(viewsets.ReadOnlyModelViewSet): return redirect('api-root') else: print(serializer.errors) - return redirect('api-root') \ No newline at end of file + return redirect('api-root') + +@api_view(['POST']) +def connect_peer(request): + serializer = ConnectPeerSerializer(data=request.data) + if serializer.is_valid(): + try: + stub = lnrpc.LightningStub(lnd_connect()) + peer_pubkey = serializer.validated_data['peer_pubkey'] + host = serializer.validated_data['host'] + ln_addr = ln.LightningAddress() + ln_addr.pubkey = peer_pubkey + ln_addr.host = host + response = stub.ConnectPeer(ln.ConnectPeerRequest(addr=ln_addr)) + return Response({'message': 'Connection successful! ' + str(response)}) + except Exception as e: + error = str(e) + return Response({'error': 'Connection request failed! Error: ' + error}) + else: + return Response({'error': 'Invalid request!'}) + +@api_view(['POST']) +def open_channel(request): + serializer = OpenChannelSerializer(data=request.data) + if serializer.is_valid(): + try: + stub = lnrpc.LightningStub(lnd_connect()) + pubkey_bytes = bytes.fromhex(serializer.validated_data['peer_pubkey']) + for response in stub.OpenChannel(ln.OpenChannelRequest(node_pubkey=pubkey_bytes, local_funding_amount=serializer.validated_data['local_amt'], sat_per_byte=serializer.validated_data['sat_per_byte'])): + return Response({'message': 'Channel created! Funding TXID: ' + str(response.chan_pending.txid[::-1].hex()) + ':' + str(response.chan_pending.output_index)}) + except Exception as e: + error = str(e) + details_index = error.find('details =') + 11 + debug_error_index = error.find('debug_error_string =') - 3 + error_msg = error[details_index:debug_error_index] + return Response({'error': 'Channel creation failed! Error: ' + error_msg}) + else: + return Response({'error': 'Invalid request!'}) + +@api_view(['POST']) +def close_channel(request): + serializer = CloseChannelSerializer(data=request.data) + if serializer.is_valid(): + try: + stub = lnrpc.LightningStub(lnd_connect()) + funding_txid = serializer.validated_data['funding_txid'] + output_index = serializer.validated_data['output_index'] + target_fee = serializer.validated_data['target_fee'] + channel_point = ln.ChannelPoint() + channel_point.funding_txid_bytes = bytes.fromhex(funding_txid) + channel_point.funding_txid_str = funding_txid + channel_point.output_index = output_index + if serializer.validated_data['force']: + for response in stub.CloseChannel(ln.CloseChannelRequest(channel_point=channel_point, force=True)): + return Response({'message': 'Channel force closed! Closing TXID: ' + str(response.close_pending.txid[::-1].hex()) + ':' + str(response.close_pending.output_index)}) + else: + for response in stub.CloseChannel(ln.CloseChannelRequest(channel_point=channel_point, sat_per_byte=target_fee)): + return Response({'message': 'Channel gracefully closed! Closing TXID: ' + str(response.close_pending.txid[::-1].hex()) + ':' + str(response.close_pending.output_index)}) + except Exception as e: + error = str(e) + return Response({'error': 'Channel close failed! Error: ' + error}) + else: + return Response({'error': 'Invalid request!'}) + +@api_view(['POST']) +def add_invoice(request): + serializer = AddInvoiceSerializer(data=request.data) + if serializer.is_valid() and serializer.validated_data['value'] >= 0: + try: + stub = lnrpc.LightningStub(lnd_connect()) + response = stub.AddInvoice(ln.Invoice(value=serializer.validated_data['value'])) + return Response({'message': 'Invoice created!', 'data':str(response.payment_request)}) + except Exception as e: + error = str(e) + return Response({'error': 'Invoice creation failed! Error: ' + error}) + else: + return Response({'error': 'Invalid request!'}) + +@api_view(['POST']) +def new_address(request): + try: + stub = lnrpc.LightningStub(lnd_connect()) + response = stub.NewAddress(ln.NewAddressRequest(type=0)) + return Response({'message': 'Retrieved new deposit address!', 'data':str(response.address)}) + except Exception as e: + error = str(e) + return Response({'error': 'Address creation failed! Error: ' + error}) \ No newline at end of file