Implement sending of heartbeats
This commit is contained in:
90
node.py
Executable file
90
node.py
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import hashlib, socket, sys, threading, time
|
||||||
|
|
||||||
|
DEFAULT_PORT = 62039
|
||||||
|
|
||||||
|
class Peer:
|
||||||
|
def __init__(self, ipv6, port, lifetime_counter):
|
||||||
|
self.ipv6 = ipv6
|
||||||
|
self.port = port
|
||||||
|
self.lifetime_counter = lifetime_counter
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, node_socket, peers):
|
||||||
|
self.node_socket = node_socket
|
||||||
|
self.peers = peers
|
||||||
|
|
||||||
|
def parse_address(addr_str):
|
||||||
|
if addr_str.startswith('['):
|
||||||
|
closing = addr_str.find(']:')
|
||||||
|
if closing == -1:
|
||||||
|
raise Exception(f'Not a valid address: {addr_str}')
|
||||||
|
ipv6 = addr_str[1:closing]
|
||||||
|
port = int(addr_str[closing+2:])
|
||||||
|
else:
|
||||||
|
ipv6 = addr_str
|
||||||
|
port = DEFAULT_PORT
|
||||||
|
return Peer(ipv6, port, 10)
|
||||||
|
|
||||||
|
def wait_until(target_time):
|
||||||
|
duration = target_time - time.time()
|
||||||
|
if duration > 0:
|
||||||
|
time.sleep(duration)
|
||||||
|
|
||||||
|
def empty_transaction_list_hash():
|
||||||
|
current_hash = 32 * b"\0"
|
||||||
|
for _ in range(1024):
|
||||||
|
entry = current_hash + 44 * b"\0"
|
||||||
|
current_hash = hashlib.sha256(entry).digest()
|
||||||
|
return current_hash
|
||||||
|
|
||||||
|
def send_heartbeat(node, peer):
|
||||||
|
protocol_version = 2 * b"\0"
|
||||||
|
capable_version = 2 * b"\0"
|
||||||
|
msg_type = b"\0"
|
||||||
|
difficulty_sum = 32 * b"\0"
|
||||||
|
hash_value = empty_transaction_list_hash()
|
||||||
|
partner_ipv6 = 16 * b"\0"
|
||||||
|
partner_port = 2 * b"\0"
|
||||||
|
|
||||||
|
heartbeat_msg = protocol_version + capable_version + msg_type + \
|
||||||
|
difficulty_sum + hash_value + partner_ipv6 + partner_port
|
||||||
|
node.node_socket.sendto(heartbeat_msg, (peer.ipv6, peer.port))
|
||||||
|
|
||||||
|
def heartbeat(node):
|
||||||
|
while True:
|
||||||
|
peer_count = len(node.peers)
|
||||||
|
start_time = time.time()
|
||||||
|
for i, peer in enumerate(node.peers):
|
||||||
|
wait_until(start_time + 60 * (i+1) / peer_count)
|
||||||
|
send_heartbeat(node, peer)
|
||||||
|
|
||||||
|
def receiver(node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def main():
|
||||||
|
address_arguments = sys.argv[1:]
|
||||||
|
peers = [parse_address(argument) for argument in address_arguments]
|
||||||
|
|
||||||
|
node_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||||
|
try:
|
||||||
|
node_socket.bind(("::", DEFAULT_PORT))
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == 98:
|
||||||
|
node_socket.bind(("::", 0))
|
||||||
|
port = node_socket.getsockname()[1]
|
||||||
|
print(f"Default port {DEFAULT_PORT} is in use, listening on port {port} instead.")
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
node = Node(node_socket, peers)
|
||||||
|
heartbeat_thread = threading.Thread(target = heartbeat, args = (node,))
|
||||||
|
receiving_thread = threading.Thread(target = receiver, args = (node,))
|
||||||
|
heartbeat_thread.start()
|
||||||
|
receiving_thread.start()
|
||||||
|
heartbeat_thread.join()
|
||||||
|
receiving_thread.join()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user