This commit is contained in:
Mariano Sorgente 2019-10-10 13:04:52 +09:00
commit a22e606f75
10 changed files with 46 additions and 35 deletions

2
.gitignore vendored
View File

@ -5,6 +5,8 @@ __pycache__/
# C extensions
*.so
**/*.o
.DS_Store
# PyInstaller
# Usually these files are written by a python script from a template

View File

@ -8,6 +8,11 @@ Python 3.7 is used for this project.
sudo apt-get install build-essential cmake python3-dev --no-install-recommends
git submodule update --init --recursive
cd lib/chiavdf
# Install libgmp, libboost, and libflint, and then run the following
sh install.sh
python3 -m venv .venv
. .venv/bin/activate
pip install wheel
@ -18,6 +23,7 @@ pip install lib/chiapos
### Run servers
Run the servers in the following order (you can also use ipython):
```bash
./lib/chiavdf/fast_vdf/vdf 8889
python -m src.server.start_plotter
python -m src.server.start_timelord
python -m src.server.start_farmer

@ -1 +1 @@
Subproject commit 28942e66fda6397443aa33c0cb6515d8e8b991e7
Subproject commit 6a5570ba4d1b71d8e0e8e3f7e19acb898d601ff5

View File

@ -361,8 +361,8 @@ class Blockchain:
return False
# 4. Check PoT
#TODO(Florin): Change the hardcode of the genesis with new pot format.
if not block.trunk_block.proof_of_time.is_valid(self.constants["DISCRIMINANT_SIZE_BITS"]) and not genesis:
# TODO(Florin): Change the hardcode of the genesis with new pot format.
if not block.trunk_block.proof_of_time.is_valid(self.constants["DISCRIMINANT_SIZE_BITS"]):
return False
if block.body.coinbase.height != block.trunk_block.challenge.height:

File diff suppressed because one or more lines are too long

View File

@ -627,4 +627,3 @@ async def block(block: peer_protocol.Block) -> AsyncGenerator[OutboundMessage, N
timelord_request_end = timelord_protocol.ChallengeStart(block.block.trunk_block.proof_of_time.
output.challenge_hash)
yield OutboundMessage(NodeType.TIMELORD, Message("challenge_end", timelord_request_end), Delivery.BROADCAST)

View File

@ -197,19 +197,19 @@ async def initialize_pipeline(aiter,
handshake_finished_3 = forker.fork(is_active=True)
# Reads messages one at a time from the TCP connection
messages_aiter = join_aiters(parallel_map_aiter(connection_to_message, 100, handshake_finished_1))
messages_aiter = join_aiters(parallel_map_aiter(connection_to_message, handshake_finished_1, 100))
# Handles each message one at a time, and yields responses to send back or broadcast
responses_aiter = join_aiters(parallel_map_aiter(
partial_func.partial_async_gen(handle_message, api),
100, messages_aiter))
messages_aiter, 100))
if on_connect is not None:
# Uses a forked aiter, and calls the on_connect function to send some initial messages
# as soon as the connection is established
on_connect_outbound_aiter = join_aiters(parallel_map_aiter(
partial_func.partial_async_gen(connection_to_outbound, on_connect), 100, handshake_finished_2))
partial_func.partial_async_gen(connection_to_outbound, on_connect), handshake_finished_2, 100))
responses_aiter = join_aiters(iter_to_aiter([responses_aiter, on_connect_outbound_aiter]))
if outbound_aiter is not None:
@ -220,7 +220,7 @@ async def initialize_pipeline(aiter,
# For each outbound message, replicate for each peer that we need to send to
expanded_messages_aiter = join_aiters(parallel_map_aiter(
expand_outbound_messages, 100, responses_aiter))
expand_outbound_messages, responses_aiter, 100))
# This will run forever. Sends each message through the TCP connection, using the
# length encoding and CBOR serialization

View File

@ -7,6 +7,7 @@ from src import timelord
logging.basicConfig(format='Timelord %(name)-25s: %(levelname)-20s %(message)s', level=logging.INFO)
async def main():
host, port = parse_host_port(timelord)
server, _ = await start_chia_server(host, port, timelord, NodeType.FULL_NODE)

View File

@ -1,11 +1,9 @@
import logging
import asyncio
import time
import io
import sys
import yaml
from asyncio import Lock
from typing import Dict
from typing import Dict, Optional
from lib.chiavdf.inkfish.create_discriminant import create_discriminant
from lib.chiavdf.inkfish.proof_of_time import check_proof_of_time_nwesolowski
@ -18,6 +16,7 @@ from src.util.ints import uint8
from src.consensus.constants import constants
from src.server.outbound_message import OutboundMessage, Delivery, Message, NodeType
class Database:
lock: Lock = Lock()
free_servers = []
@ -25,11 +24,13 @@ class Database:
active_discriminants: Dict = {}
done_discriminants = []
log = logging.getLogger(__name__)
config = yaml.safe_load(open("src/config/timelord.yaml", "r"))
db = Database()
db.free_servers.append(8889)
@api_request
async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
"""
@ -37,7 +38,7 @@ async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
should be started on it. We can generate a classgroup (discriminant), and start
a new VDF process here. But we don't know how many iterations to run for, so we run
forever.
"""
"""
disc: int = create_discriminant(challenge_start.challenge_hash, constants["DISCRIMINANT_SIZE_BITS"])
@ -46,19 +47,19 @@ async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
log.info("This discriminant was already done..")
return
#Wait for a server to become free.
port = None
# Wait for a server to become free.
port: Optional[int] = None
while (port is None):
async with db.lock:
if (len(db.free_servers) != 0):
port = db.free_servers[0]
db.free_servers = db.free_servers[1:]
log.info(f"Discriminant {disc} attached to port {port}.")
#Poll until a server becomes free.
# Poll until a server becomes free.
if (port is None):
await asyncio.sleep(3)
#TODO(Florin): Handle connection failure (attempt another server)
# TODO(Florin): Handle connection failure (attempt another server)
try:
reader, writer = await asyncio.open_connection('127.0.0.1', port)
except Exception as e:
@ -70,17 +71,17 @@ async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
ok = await reader.readexactly(2)
assert(ok.decode() == "OK")
log.info("Got handshake with VDF server.")
async with db.lock:
db.active_discriminants[challenge_start.challenge_hash] = writer
#Listen to the server until "STOP" is received.
while(True):
# Listen to the server until "STOP" is received.
while True:
data = await reader.readexactly(4)
if (data.decode() == "STOP"):
#Server is now available.
# Server is now available.
async with db.lock:
writer.write(b"ACK")
await writer.drain()
@ -88,7 +89,7 @@ async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
break
else:
try:
#This must be a proof, read the continuation.
# This must be a proof, read the continuation.
proof = await reader.readexactly(1860)
stdout_bytes_io: io.BytesIO = io.BytesIO(bytes.fromhex(data.decode() + proof.decode()))
iterations_needed = int.from_bytes(stdout_bytes_io.read(8), "big", signed=True)
@ -101,13 +102,13 @@ async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
assert check_proof_of_time_nwesolowski(disc, x, proof_blob, iterations_needed, 1024, 2)
output = ProofOfTimeOutput(challenge_start.challenge_hash,
iterations_needed,
ClassgroupElement(y.a, y.b))
iterations_needed,
ClassgroupElement(y.a, y.b))
proof_of_time = ProofOfTime(output, config['n_wesolowski'], [uint8(b) for b in proof_bytes])
response = timelord_protocol.ProofOfTimeFinished(proof_of_time)
log.info(f"Got PoT for challenge {challenge_start.challenge_hash}")
#async with db.lock:
# async with db.lock:
# if (challenge_start.challenge_hash in db.solved_discriminants):
# log.info("I've already propagated one proof... Ignoring for now...")
# continue
@ -117,7 +118,7 @@ async def challenge_start(challenge_start: timelord_protocol.ChallengeStart):
e_to_str = str(e)
log.error(f"Socket error: {e_to_str}")
@api_request
async def challenge_end(challenge_end: timelord_protocol.ChallengeEnd):
"""
@ -126,7 +127,7 @@ async def challenge_end(challenge_end: timelord_protocol.ChallengeEnd):
"""
async with db.lock:
if (challenge_end.challenge_hash in db.done_discriminants):
return
return
if (challenge_end.challenge_hash in db.active_discriminants):
writer = db.active_discriminants[challenge_end.challenge_hash]
writer.write(b'10')
@ -135,6 +136,7 @@ async def challenge_end(challenge_end: timelord_protocol.ChallengeEnd):
db.done_discriminants.append(challenge_end.challenge_hash)
await asyncio.sleep(0.5)
@api_request
async def proof_of_space_info(proof_of_space_info: timelord_protocol.ProofOfSpaceInfo):
"""
@ -143,15 +145,15 @@ async def proof_of_space_info(proof_of_space_info: timelord_protocol.ProofOfSpac
many iterations to run for. TODO: process should be started in challenge_start instead.
"""
while (True):
while True:
async with db.lock:
if (proof_of_space_info.challenge_hash in db.active_discriminants):
writer = db.active_discriminants[proof_of_space_info.challenge_hash]
writer.write((str(len(str(proof_of_space_info.iterations_needed)))
+ str(proof_of_space_info.iterations_needed)).encode())
writer.write((str(len(str(proof_of_space_info.iterations_needed)))
+ str(proof_of_space_info.iterations_needed)).encode())
await writer.drain()
return
return
if (proof_of_space_info.challenge_hash in db.done_discriminants):
log.info("Got iters for a finished challenge")
return
return
await asyncio.sleep(0.5)

View File

@ -208,5 +208,5 @@ class BlockTools:
# print(create_genesis_block().serialize())
# bt = BlockTools()
# print(bt.create_genesis_block(bytes([4]*32)).serialize())
bt = BlockTools()
print(bt.create_genesis_block(bytes([4]*32)).serialize())