Files
carrotcoin/node.py

91 lines
2.6 KiB
Python
Executable File

#! /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()