__bytes__, cbor, etc

This commit is contained in:
Mariano Sorgente 2019-11-01 14:53:48 -07:00
parent 85b1b04173
commit e65d9bad71
20 changed files with 65 additions and 55 deletions

View File

@ -26,7 +26,7 @@ python -m src.server.start_plotter
python -m src.server.start_timelord
python -m src.server.start_farmer
python -m src.server.start_full_node "127.0.0.1" 8002 -f
python -m src.server.start_full_node "127.0.0.1" 8004 -t -u
python -m src.server.start_full_node "127.0.0.1" 8004 -t -u 8222
python -m src.server.start_full_node "127.0.0.1" 8005
```

View File

@ -1,10 +1,17 @@
asyncssh==2.0.0
atomicwrites==1.3.0
attrs==19.3.0
bitstring==3.1.6
blspy==0.1.11
cbor2==4.1.2
cffi==1.13.1
cppimport==18.11.8
cryptography==2.8
entrypoints==0.3
flake8==3.7.9
importlib-metadata==0.23
Mako==1.1.0
MarkupSafe==1.1.1
mccabe==0.6.1
more-itertools==7.2.0
mypy==0.740
@ -12,7 +19,9 @@ mypy-extensions==0.4.3
packaging==19.2
pluggy==0.13.0
py==1.8.0
pybind11==2.4.3
pycodestyle==2.5.0
pycparser==2.19
pyflakes==2.1.1
pyparsing==2.4.2
pytest==5.2.2

View File

@ -405,7 +405,7 @@ class Blockchain:
return False
# 11. Check coinbase signature with pool pk
if not block.body.coinbase_signature.verify([blspy.Util.hash256(block.body.coinbase.serialize())],
if not block.body.coinbase_signature.verify([blspy.Util.hash256(bytes(block.body.coinbase))],
[block.trunk_block.proof_of_space.pool_pubkey]):
return False

View File

@ -19,8 +19,8 @@ pool_sks:
# sha256(PrivateKey.from_seed(b'0').get_public_key().serialize()).digest()
pool_target: "9940b95222a1d19abb73c192f2c10dc65b32bcc7a703db1b40456f2dbf1e416e"
pool_share_threshold: 500 # To send to pool, must be expected to take less than these seconds
propagate_threshold: 400 # To propagate to network, must be expected to take less than these seconds
pool_share_threshold: 1500 # To send to pool, must be expected to take less than these seconds
propagate_threshold: 1000 # To propagate to network, must be expected to take less than these seconds
plotter_peer:
host: "127.0.0.1"

View File

@ -11,8 +11,6 @@ short_sync_download_count: 6
host: "127.0.0.1"
port: 8002
# SSH server started, for UI
ssh_port: 8222
ssh_filename: "src/config/ssh_host_key"
farmer_peer:

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@ from bson.codec_options import CodecOptions
def fallback_encoder(obj):
if isinstance(obj, Streamable):
return Binary(obj.serialize())
return Binary(bytes(obj))
return obj

View File

@ -205,7 +205,7 @@ class Farmer:
pool_sks: List[PrivateKey] = [PrivateKey.from_bytes(bytes.fromhex(ce))
for ce in self.config["pool_sks"]]
coinbase_signature: PrependSignature = pool_sks[0].sign_prepend(coinbase.serialize())
coinbase_signature: PrependSignature = pool_sks[0].sign_prepend(bytes(coinbase))
self.coinbase_rewards[uint32(self.current_height + 1)] = (coinbase, coinbase_signature)
log.info(f"\tCurrent height set to {self.current_height}")

View File

@ -295,6 +295,7 @@ class ChiaServer:
try:
f = getattr(api, full_message.function)
if f is not None:
log.info(f"<- {f.__name__} from peer {connection.get_peername()}")
result = f(full_message.data)
if isinstance(result, AsyncGenerator):
async for outbound_message in result:

View File

@ -50,8 +50,10 @@ async def main():
log.info("Server closed.")
if "-u" in sys.argv:
index = sys.argv.index("-u")
ui_ssh_port = int(sys.argv[index + 1])
from src.ui.prompt_ui import FullNodeUI
ui = FullNodeUI(store, blockchain, server.global_connections, port, full_node.config['ssh_port'],
ui = FullNodeUI(store, blockchain, server.global_connections, port, ui_ssh_port,
full_node.config['ssh_filename'], master_close_cb)
connect_to_farmer = ("-f" in sys.argv)
@ -64,9 +66,9 @@ async def main():
NodeType.FULL_NODE, full_node.on_connect))
await asyncio.gather(*peer_tasks)
log.info("Waiting to perform handshake with all peers...")
# TODO: have a cleaner way to wait for all the handshakes
log.info("Waiting to connect to some peers...")
await asyncio.sleep(3)
if server_closed:
return

View File

@ -13,7 +13,7 @@ python -m src.server.start_farmer &
P3=$!
python -m src.server.start_full_node "127.0.0.1" 8002 -f &
P4=$!
python -m src.server.start_full_node "127.0.0.1" 8004 -t -u &
python -m src.server.start_full_node "127.0.0.1" 8004 -t -u 8222 &
P5=$!
python -m src.server.start_full_node "127.0.0.1" 8005 &
P6=$!

View File

@ -62,7 +62,6 @@ class Timelord:
log.info(f"Will not execute challenge at height {challenge_start}, too old")
return
assert(len(self.active_heights) > 0)
log.info(f"{challenge_start.height}, max is {max(self.active_heights)}")
if (challenge_start.height == max(self.active_heights)):
if (len(self.free_servers) != 0):
port = self.free_servers[0]
@ -120,15 +119,10 @@ class Timelord:
log.info("Stopped server")
# Server is now available.
async with self.lock:
log.info("Acquired lock for writing")
writer.write(b"ACK")
log.info("Wrote ack to server")
await writer.drain()
log.info("Drained VDF server")
await proc.wait()
log.info("Waited for process to exit")
self.free_servers.append(port)
log.info(f"Appended {port} to free ports")
if challenge_start.challenge_hash in self.active_discriminants:
del self.active_discriminants[challenge_start.challenge_hash]
del self.active_discriminants_start_time[challenge_start.challenge_hash]

View File

@ -26,6 +26,5 @@ def api_request(f):
if param_name != "return" and isinstance(inter[param_name], dict):
inter[param_name] = param_class(**inter[param_name])
log.info(f"<- {f.__name__}")
return f(**inter)
return f_substitute

View File

@ -29,7 +29,7 @@ def make_sized_bytes(size):
f = io.BytesIO(blob)
return cls.parse(f)
def serialize(self: Any) -> bytes:
def __bytes__(self: Any) -> bytes:
f = io.BytesIO()
self.stream(f)
return bytes(f.getvalue())
@ -41,6 +41,6 @@ def make_sized_bytes(size):
return "<%s: %s>" % (self.__class__.__name__, str(self))
namespace = dict(__new__=__new__, parse=parse, stream=stream, from_bytes=from_bytes,
serialize=serialize, __str__=__str__, __repr__=__repr__)
__bytes__=__bytes__, __str__=__str__, __repr__=__repr__)
return type(name, (bytes,), namespace)

View File

@ -19,7 +19,10 @@ def default_encoder(encoder, value: Any):
fields: Dict = get_type_hints(value)
els = {f_name: getattr(value, f_name) for f_name in fields.keys()}
encoder.encode(els)
elif hasattr(type(value), "__bytes__"):
encoder.encode(bytes(value))
elif hasattr(type(value), "serialize"):
# Useful for blspy objects
encoder.encode(value.serialize())
else:
raise NotImplementedError(f"can't CBOR encode {type(value)}:{value}")

View File

@ -98,7 +98,10 @@ class Streamable:
self.stream_one_item(inner_type, item, f)
elif hasattr(f_type, "stream"):
item.stream(f)
elif hasattr(f_type, "__bytes__"):
f.write(bytes(item))
elif hasattr(f_type, "serialize"):
# Useful for blspy objects
f.write(item.serialize())
else:
raise NotImplementedError(f"can't stream {item}, {f_type}")
@ -108,14 +111,14 @@ class Streamable:
self.stream_one_item(f_type, getattr(self, f_name), f)
def get_hash(self) -> bytes32:
return bytes32(sha256(self.serialize()).digest())
return bytes32(sha256(bytes(self)).digest())
@classmethod
def from_bytes(cls: Any, blob: bytes) -> Any:
f = io.BytesIO(blob)
return cls.parse(f)
def serialize(self: Any) -> bytes:
def __bytes__(self: Any) -> bytes:
f = io.BytesIO()
self.stream(f)
return bytes(f.getvalue())

View File

@ -31,7 +31,7 @@ class StructStream(int):
f = io.BytesIO(blob)
return cls.parse(f)
def serialize(self: Any) -> bytes:
def __bytes__(self: Any) -> bytes:
f = io.BytesIO()
self.stream(f)
return bytes(f.getvalue())

View File

@ -69,7 +69,7 @@ class BlockTools:
num_blocks: int,
block_list: List[FullBlock] = [],
seconds_per_block=constants["BLOCK_TIME_TARGET"],
seed: uint64 = uint64(0)) -> List[FullBlock]:
seed: bytes = b'') -> List[FullBlock]:
test_constants: Dict[str, Any] = constants.copy()
for key, value in input_constants.items():
test_constants[key] = value
@ -78,7 +78,7 @@ class BlockTools:
if "GENESIS_BLOCK" in test_constants:
block_list.append(FullBlock.from_bytes(test_constants["GENESIS_BLOCK"]))
else:
block_list.append(self.create_genesis_block(test_constants, bytes([(seed) % 256]*32), seed))
block_list.append(self.create_genesis_block(test_constants, sha256(seed).digest(), seed))
prev_difficulty = test_constants["DIFFICULTY_STARTING"]
curr_difficulty = prev_difficulty
curr_ips = test_constants["VDF_IPS_STARTING"]
@ -162,7 +162,7 @@ class BlockTools:
return block_list
def create_genesis_block(self, input_constants: Dict, challenge_hash=bytes([0]*32),
seed: uint64 = uint64(0)) -> FullBlock:
seed: bytes = b'') -> FullBlock:
"""
Creates the genesis block with the specified details.
"""
@ -185,7 +185,7 @@ class BlockTools:
def create_next_block(self, input_constants: Dict, prev_block: FullBlock, timestamp: uint64,
difficulty: uint64, ips: uint64,
seed: int = 0) -> FullBlock:
seed: bytes = b'') -> FullBlock:
"""
Creates the next block with the specified details.
"""
@ -210,7 +210,7 @@ class BlockTools:
def _create_block(self, test_constants: Dict, challenge_hash: bytes32, height: uint32, prev_header_hash: bytes32,
prev_iters: uint64, prev_weight: uint64, timestamp: uint64, difficulty: uint64,
ips: uint64, seed: int) -> FullBlock:
ips: uint64, seed: bytes) -> FullBlock:
"""
Creates a block with the specified details. Uses the stored plots to create a proof of space,
and also evaluates the VDF for the proof of time.
@ -220,7 +220,8 @@ class BlockTools:
plot_sk = None
qualities: List[bytes] = []
for pn in range(num_plots):
seeded_pn = (pn + 17 * seed) % num_plots # Allow passing in seed, to create reorgs and different chains
# Allow passing in seed, to create reorgs and different chains
seeded_pn = (pn + 17 * int.from_bytes(seed, "big")) % num_plots
filename = self.filenames[seeded_pn]
plot_pk = plot_pks[seeded_pn]
plot_sk = plot_sks[seeded_pn]
@ -253,11 +254,12 @@ class BlockTools:
coinbase: CoinbaseInfo = CoinbaseInfo(height, block_rewards.calculate_block_reward(uint32(height)),
coinbase_target)
coinbase_sig: PrependSignature = pool_sk.sign_prepend(coinbase.serialize())
coinbase_sig: PrependSignature = pool_sk.sign_prepend(bytes(coinbase))
fees_target: FeesTarget = FeesTarget(fee_target, uint64(0))
body: BlockBody = BlockBody(coinbase, coinbase_sig, fees_target, None, bytes([0]*32))
solutions_generator: bytes32 = sha256(seed).digest()
body: BlockBody = BlockBody(coinbase, coinbase_sig, fees_target, None, solutions_generator)
header_data: BlockHeaderData = BlockHeaderData(prev_header_hash, timestamp, bytes([0]*32),
proof_of_space.get_hash(), body.get_hash(),
@ -279,5 +281,5 @@ class BlockTools:
# This code generates a genesis block, uncomment to output genesis block to terminal
# This might take a while, using the python VDF implementation.
# Run by doing python -m tests.block_tools
# bt = BlockTools()
# print(bt.create_genesis_block({}, bytes([1]*32), uint64(0)).serialize())
bt = BlockTools()
print(bytes(bt.create_genesis_block({}, bytes([1]*32), b'0')))

View File

@ -29,7 +29,7 @@ test_constants: Dict[str, Any] = {
"DIFFICULTY_WARP_FACTOR": 4, # DELAY divides EPOCH in order to warp efficiently.
"DIFFICULTY_DELAY": 3 # EPOCH / WARP_FACTOR
}
test_constants["GENESIS_BLOCK"] = bt.create_genesis_block(test_constants, bytes([0]*32), uint64(0)).serialize()
test_constants["GENESIS_BLOCK"] = bytes(bt.create_genesis_block(test_constants, bytes([0]*32), b'0'))
@pytest.fixture(scope="module")
@ -236,7 +236,7 @@ class TestReorgs():
await b.receive_block(block)
assert b.get_current_heads()[0].height == 100
blocks_reorg_chain = bt.get_consecutive_blocks(test_constants, 30, blocks[:90], 9, uint64(1))
blocks_reorg_chain = bt.get_consecutive_blocks(test_constants, 30, blocks[:90], 9, b'1')
for reorg_block in blocks_reorg_chain:
result = await b.receive_block(reorg_block)
if reorg_block.height < 90:
@ -249,7 +249,7 @@ class TestReorgs():
@pytest.mark.asyncio
async def test_reorg_from_genesis(self):
blocks = bt.get_consecutive_blocks(test_constants, 20, [], 9, uint64(0))
blocks = bt.get_consecutive_blocks(test_constants, 20, [], 9, b'0')
store = FullNodeStore()
await store.initialize()
b: Blockchain = Blockchain(store, test_constants)
@ -259,7 +259,7 @@ class TestReorgs():
assert b.get_current_heads()[0].height == 20
# Reorg from genesis
blocks_reorg_chain = bt.get_consecutive_blocks(test_constants, 21, [blocks[0]], 9, uint64(1))
blocks_reorg_chain = bt.get_consecutive_blocks(test_constants, 21, [blocks[0]], 9, b'1')
for reorg_block in blocks_reorg_chain:
result = await b.receive_block(reorg_block)
if reorg_block.height == 0:
@ -271,32 +271,31 @@ class TestReorgs():
assert b.get_current_heads()[0].height == 21
# Reorg back to original branch
blocks_reorg_chain_2 = bt.get_consecutive_blocks(test_constants, 3, blocks, 9, uint64(3))
blocks_reorg_chain_2 = bt.get_consecutive_blocks(test_constants, 3, blocks, 9, b'3')
await b.receive_block(blocks_reorg_chain_2[20]) == ReceiveBlockResult.ADDED_AS_ORPHAN
assert (await b.receive_block(blocks_reorg_chain_2[21])) == ReceiveBlockResult.ADDED_TO_HEAD
assert (await b.receive_block(blocks_reorg_chain_2[22])) == ReceiveBlockResult.ADDED_TO_HEAD
@pytest.mark.asyncio
async def test_lca(self):
blocks = bt.get_consecutive_blocks(test_constants, 5, [], 9, uint64(0))
blocks = bt.get_consecutive_blocks(test_constants, 5, [], 9, b'0')
store = FullNodeStore()
await store.initialize()
b: Blockchain = Blockchain(store, test_constants)
await b.initialize()
for block in blocks:
await b.receive_block(block)
assert b.lca_block == blocks[2]
block_5_2 = bt.get_consecutive_blocks(test_constants, 1, blocks[:4], 9, uint64(1))[0]
block_5_3 = bt.get_consecutive_blocks(test_constants, 1, blocks[:4], 9, uint64(2))[0]
assert b.lca_block == blocks[3]
block_5_2 = bt.get_consecutive_blocks(test_constants, 1, blocks[:5], 9, b'1')[5]
block_5_3 = bt.get_consecutive_blocks(test_constants, 1, blocks[:5], 9, b'2')[5]
await b.receive_block(block_5_2)
assert b.lca_block == blocks[3]
assert b.lca_block == blocks[4]
await b.receive_block(block_5_3)
assert b.lca_block == blocks[3]
assert b.lca_block == blocks[4]
reorg = bt.get_consecutive_blocks(test_constants, 6, [], 9, uint64(3))
reorg = bt.get_consecutive_blocks(test_constants, 6, [], 9, b'3')
for block in reorg:
await b.receive_block(block)
assert b.lca_block == blocks[0]

View File

@ -19,7 +19,7 @@ class TestStreamable(unittest.TestCase):
a = TestClass(24, 352, [1, 2, 4], [[1, 2, 3], [3, 4]], 728, None) # type: ignore
b: bytes = a.serialize()
b: bytes = bytes(a)
assert a == TestClass.from_bytes(b)
def test_variablesize(self):
@ -32,7 +32,7 @@ class TestStreamable(unittest.TestCase):
a = TestClass2(uint32(1), uint32(2), "3")
try:
a.serialize()
bytes(a)
assert False
except NotImplementedError:
pass
@ -44,7 +44,7 @@ class TestStreamable(unittest.TestCase):
b = TestClass3(1)
try:
b.serialize()
bytes(b)
assert False
except NotImplementedError:
pass