-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathlightning.py
More file actions
109 lines (92 loc) · 3.25 KB
/
Copy pathlightning.py
File metadata and controls
109 lines (92 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
"""Lightning network API for a lightning node.
Interface:
API -- the Blueprint returned by serverutil.api_factory
init(conf) - Set up the database
send(url, amount)
- Send amount satoshis to the node identified by url. The url is not
necessarily a direct peer.
Error conditions have not been defined.
Database:
PEERS contains information nodes we have channels open with
address: their url
fees: how much we require as fees for relaying across this channel
ROUTES is the routing table. It has one row for every other lightning node
address: their url
cost: total fees to route payment to that node
nexthop: where should payment go next on the path to that node
"""
from flask import g
import jsonrpcproxy
from serverutil import api_factory, database
import channel
from sqlalchemy import Column, Integer, String
API, REMOTE, Model = api_factory('lightning')
class Peer(Model):
"""Database model of a peer node."""
__tablename__ = "peers"
address = Column(String, primary_key=True)
fees = Column(Integer)
class Route(Model):
"""Database model of a route."""
__tablename__ = "routes"
address = Column(String, primary_key=True)
cost = Column(Integer)
next_hop = Column(String)
@channel.CHANNEL_OPENED.connect_via('channel')
def on_open(dummy_sender, address, **dummy_args):
"""Routing update on open."""
fees = 10000
# Add the new peer
peer = Peer(address=address, fees=fees)
database.session.add(peer)
# Broadcast a routing update
update(address, address, 0)
# The new peer doesn't know all our routes.
# As a hack, rebuild/rebroadcast the whole routing table.
routes = Route.query.all()
Route.query.delete()
database.session.commit()
for route in routes:
update(route.next_hop, route.address, route.cost)
@REMOTE
def update(next_hop, address, cost):
"""Routing update."""
# Check previous route, and only update if this is an improvement
if address == g.addr:
return
route = Route.query.get(address)
if route is None:
route = Route(address=address, cost=cost, next_hop=next_hop)
database.session.add(route)
elif route.cost <= cost:
return
else:
route.cost = cost
route.next_hop = next_hop
# Tell all our peers
database.session.commit()
for peer in Peer.query.all():
bob = jsonrpcproxy.Proxy(peer.address + 'lightning/')
bob.update(g.addr, address, cost + peer.fees)
return True
@REMOTE
def send(url, amount):
"""Send coin, perhaps through more than one hop.
After this call, the node at url should have recieved amount satoshis.
Any fees should be collected from this node's balance.
"""
# Paying ourself is easy
if url == g.addr:
return
route = Route.query.get(url)
if route is None:
# If we don't know how to get there, let channel try.
# As set up currently, this shouldn't ever work, but
# we can let channel throw the error
channel.send(url, amount)
else:
# Send the next hop money over our payment channel
channel.send(route.next_hop, amount + route.cost)
# Ask the next hop to send money to the destination
bob = jsonrpcproxy.Proxy(route.next_hop+'lightning/')
bob.send(url, amount)