Display best iters in UI

This commit is contained in:
Mariano Sorgente 2020-04-12 19:55:56 +09:00 committed by Richard Kiss
parent 51ab6260dc
commit 053185265e
9 changed files with 146 additions and 10 deletions

View File

@ -66,7 +66,8 @@
<tr>
<th scope="col">Block hash</th>
<th scope="col" style="width: 100px;">Height</th>
<th scope="col" style-"width: 200px;">Time created</th>
<th scope="col" style="">Time created</th>
<th scope="col" style="">Expected VDF finish</th>
</tr>
<tbody id="latest-blocks-tbody">
</tbody>

View File

@ -16,6 +16,11 @@ class FullNodeRpcClient {
"header_hash": header_hash,
});
}
async get_unfinished_block_headers(height) {
return await this.make_request("get_unfinished_block_headers", {
"height": height,
});
}
async get_block(header_hash) {
return await this.make_request("get_block", {

View File

@ -72,7 +72,7 @@ async function render() {
block_tbody.appendChild(create_table_row("Cost", block.header.data.cost));
block_tbody.appendChild(create_table_row("Difficulty", BigInt(diff).toLocaleString()));
block_tbody.appendChild(create_table_row("Total VDF Iterations", BigInt(block.header.data.total_iters).toLocaleString()));
block_tbody.appendChild(create_table_row("Block VDF Iterations", block.proof_of_time.number_of_iterations));
block_tbody.appendChild(create_table_row("Block VDF Iterations", BigInt(block.proof_of_time.number_of_iterations).toLocaleString()));
block_tbody.appendChild(create_table_row("Proof of Space Size", block.proof_of_space.size));
block_tbody.appendChild(create_table_row("Plot Public Key", block.proof_of_space.plot_pubkey));
block_tbody.appendChild(create_table_row("Pool Public Key", block.proof_of_space.pool_pubkey));

View File

@ -37,6 +37,7 @@ class FullNodeView {
this.state = {
tip_hashes: new Set(),
getting_info: false,
getting_info_unfinished: false,
connections: {},
displayed_connections: new Set(),
max_height: 0,
@ -48,11 +49,14 @@ class FullNodeView {
ips: 0,
min_iters: 0,
latest_blocks: [],
latest_unfinished_blocks: [],
}
this.update_view(true);
this.initialize_handlers();
this.get_info();
this.get_info_unfinished();
this.interval = setInterval(() => this.get_info(), 2000);
this.interval = setInterval(() => this.get_info_unfinished(), 7000);
}
initialize_handlers() {
@ -164,6 +168,54 @@ class FullNodeView {
return blocks;
}
async get_latest_unfinished_blocks(tips, ips) {
let num_headers_to_display = 3;
let min_height = 9999999999;
let max_height = 0;
for (let tip of tips) {
if (tip.data.height < min_height) min_height = tip.data.height;
if (tip.data.height > max_height) max_height = tip.data.height;
}
let headers = [];
for (let height=max_height + 1; height >= min_height; height--) {
let fetched = await rpc_client.get_unfinished_block_headers(height);
for (let fetched_h of fetched) {
fetched_h.header_hash = await hash_header(fetched_h);
headers.push(fetched_h);
}
if (headers.length >= num_headers_to_display) {
break;
}
}
// Get prev headers to check iterations required for this block
let iters_map = {};
for (let header of headers) {
let prev = await rpc_client.get_header(header.data.prev_header_hash);
iters_map[header.header_hash] = BigInt(header.data.total_iters) - BigInt(prev.data.total_iters);
}
let blocks = [];
// Add the expected_finish property to each header
for (let i=0; i < headers.length; i++) {
let iters = iters_map[headers[i].header_hash];
let finish_time = BigInt(headers[i].data.timestamp) + BigInt(iters) / BigInt(ips);
blocks.push({
"header_hash": headers[i].header_hash,
"header": headers[i],
"expected_finish": finish_time,
"iters": iters,
})
}
// Sort by block height, then expected finish time
blocks.sort((b1, b2) => {
if (b2.header.data.height != b1.header.data.height) {
return b2.header.data.height - b1.header.data.height;
}
return Number(b1.expected_finish - b2.expected_finish);
})
return blocks.slice(0, num_headers_to_display);
}
create_table_cell(text) {
let cell = document.createElement("td");
let cellText = document.createTextNode(text);
@ -211,7 +263,14 @@ class FullNodeView {
}
if (redisplay_blocks) {
latest_blocks_tbody.innerHTML = "";
for (let block of this.state.latest_blocks) {
let display_blocks = this.state.latest_unfinished_blocks.concat(this.state.latest_blocks);
let latest_blocks_hh = this.state.latest_blocks.map((b) => b.header_hash);
for (let block of display_blocks) {
if ("expected_finish" in block && latest_blocks_hh.includes(block.header_hash)) {
// Don't display unfinished blocks that are already in finished blocks list
continue;
}
let row = document.createElement("tr");
let link = document.createElement("a");
let action_cell = document.createElement("td");
@ -227,12 +286,21 @@ class FullNodeView {
if (hh === this.state.lca_hash) {
height_str += " (LCA)";
}
link.innerHTML = block.header_hash;
link.innerHTML = block.header_hash.substring(0, 5) + "..." + block.header_hash.substring(59);
link.style.textDecoration = "underline";
action_cell.appendChild(link);
row.appendChild(action_cell);
row.appendChild(this.create_table_cell(height_str));
row.appendChild(this.create_table_cell(unix_to_short_date(block.header.data.timestamp)));
if ("expected_finish" in block) {
row.append(this.create_table_cell(link.innerHTML))
row.appendChild(this.create_table_cell(height_str + " (unfinished)"));
row.appendChild(this.create_table_cell(unix_to_short_date(block.header.data.timestamp)));
row.appendChild(this.create_table_cell(unix_to_short_date(block.expected_finish.toString()) + " (" + BigInt(block.iters).toLocaleString() + " iter)"));
row.style.color = "orange";
} else {
row.appendChild(action_cell);
row.appendChild(this.create_table_cell(height_str));
row.appendChild(this.create_table_cell(unix_to_short_date(block.header.data.timestamp)));
row.appendChild(this.create_table_cell("Finished"));
}
latest_blocks_tbody.appendChild(row);
}
}
@ -287,6 +355,36 @@ class FullNodeView {
}
this.state.getting_info = false;
};
async get_info_unfinished() {
if ((max_block_height_textfield === undefined) || (max_block_height_textfield === null)) {
// Stop the interval if we changed tabs.
this.stop();
return;
}
if (this.state.getting_info_unfinished) {
return;
}
this.state.getting_info_unfinished = true;
try {
let blockchain_state = await rpc_client.get_blockchain_state();
let unfinished_blocks = await this.get_latest_unfinished_blocks(blockchain_state.tips, blockchain_state.ips);
let update = false;
for (let b of unfinished_blocks) {
if (!this.state.latest_unfinished_blocks.map(x => x.header_hash).includes(b.header_hash)) {
update = true;
this.state.latest_unfinished_blocks = unfinished_blocks;
break;
}
}
await this.update_view(update);
} catch (error) {
console.error("Error getting unfinished info from node", error);
this.node_not_connected();
}
this.state.getting_info_unfinished = false;
}
}
if (!(max_block_height_textfield === undefined) && !(max_block_height_textfield === null)) {

View File

@ -228,7 +228,9 @@ async def show_async(args, parser):
result_txt = f"NodeID {args.remove_connection}... not found."
print(result_txt)
if args.block_header_hash != "":
block_header = await client.get_block(hexstr_to_bytes(args.block_header_hash))
block_header = await client.get_block(
hexstr_to_bytes(args.block_header_hash)
)
# print(dir(block_header))
if block_header is not None:
print("Block header:")
@ -256,7 +258,7 @@ async def show_async(args, parser):
f"Difficulty {block.header.data.weight-prev_block_header.header.data.weight}\n"
f"Total VDF Iterations {block.header.data.total_iters}\n"
f"Block VDF Iterations {block.proof_of_time.number_of_iterations}\n"
f"Proof of Space \'k\' Size {block.proof_of_space.size}\n"
f"Proof of Space 'k' Size {block.proof_of_space.size}\n"
# f"Plot Public Key 0x{block.proof_of_space.plot_pubkey}\n"
# f"Pool Public Key 0x{block.proof_of_space.pool_pubkey}\n"
f"Tx Filter Hash {(block.transactions_filter)}\n"

View File

@ -6,7 +6,7 @@ from src.util.byte_types import hexstr_to_bytes
from src.types.full_block import FullBlock
from src.types.header import Header
from src.types.sized_bytes import bytes32
from src.util.ints import uint16
from src.util.ints import uint16, uint32
from src.types.coin_record import CoinRecord
@ -62,6 +62,10 @@ class RpcClient:
raise
return Header.from_json_dict(response)
async def get_unfinished_block_headers(self, height: uint32) -> List[Header]:
response = await self.fetch("get_unfinished_block_headers", {"height": height})
return [Header.from_json_dict(r) for r in response]
async def get_connections(self) -> List[Dict]:
response = await self.fetch("get_connections", {})
for connection in response:

View File

@ -110,6 +110,18 @@ class RpcApiHandler:
raise web.HTTPNotFound()
return obj_to_response(header)
async def get_unfinished_block_headers(self, request) -> web.Response:
request_data = await request.json()
if "height" not in request_data:
raise web.HTTPBadRequest()
height = request_data["height"]
response_headers: List[Header] = []
for block in (self.full_node.store.get_unfinished_blocks()).values():
if block.height == height:
response_headers.append(block.header)
return obj_to_response(response_headers)
async def get_connections(self, request) -> web.Response:
"""
Retrieves all connections to this full node, including farmers and timelords.
@ -228,6 +240,9 @@ async def start_rpc_server(
web.post("/get_blockchain_state", handler.get_blockchain_state),
web.post("/get_block", handler.get_block),
web.post("/get_header", handler.get_header),
web.post(
"/get_unfinished_block_headers", handler.get_unfinished_block_headers
),
web.post("/get_connections", handler.get_connections),
web.post("/open_connection", handler.open_connection),
web.post("/close_connection", handler.close_connection),

View File

@ -314,6 +314,7 @@ class ChiaServer:
async def serve_forever():
async for connection, message in expanded_messages_aiter:
if message is None:
# Does not ban the peer, this is just a graceful close of connection.
self.global_connections.close(connection, True)
continue
self.log.info(
@ -518,6 +519,7 @@ class ChiaServer:
except Exception:
tb = traceback.format_exc()
self.log.error(f"Error, closing connection {connection}. {tb}")
# TODO: Exception means peer gave us invalid information, so ban this peer.
self.global_connections.close(connection)
async def expand_outbound_messages(
@ -556,4 +558,5 @@ class ChiaServer:
else:
yield (peer, outbound_message.message)
elif outbound_message.delivery_method == Delivery.CLOSE:
# Close the connection but don't ban the peer
yield (connection, None)

View File

@ -29,6 +29,10 @@ class TestRpc:
blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10)
for i in range(1, num_blocks):
async for _ in full_node_1.respond_unfinished_block(
full_node_protocol.RespondUnfinishedBlock(blocks[i])
):
pass
async for _ in full_node_1.respond_block(
full_node_protocol.RespondBlock(blocks[i])
):
@ -54,6 +58,10 @@ class TestRpc:
assert block == blocks[7]
assert (await client.get_block(bytes([1] * 32))) is None
unf_block_headers = await client.get_unfinished_block_headers(5)
assert len(unf_block_headers) == 1
assert unf_block_headers[0] == blocks[5].header
header = await client.get_header(state["lca"].header_hash)
assert header == blocks[7].header