mirror of
https://github.com/logos-blockchain/logos-blockchain-pocs.git
synced 2026-01-07 15:43:07 +00:00
1506 lines
144 KiB
Plaintext
1506 lines
144 KiB
Plaintext
|
|
{
|
||
|
|
"cells": [
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 1,
|
||
|
|
"id": "ad657d5a-bd36-4329-b134-6745daff7ae9",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"import numpy as np\n",
|
||
|
|
"import matplotlib.pyplot as plt\n",
|
||
|
|
"from dataclasses import dataclass, replace\n",
|
||
|
|
"from pyvis.network import Network\n",
|
||
|
|
"from pyvis.options import Layout\n",
|
||
|
|
"import time"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 2,
|
||
|
|
"id": "a9e0b910-c633-4dbe-827c-4ddb804f7a9a",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"def phi(f, alpha):\n",
|
||
|
|
" return 1 - (1-f)**alpha"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 3,
|
||
|
|
"id": "aa0aadce-a0be-4873-ba23-293be74db313",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"@dataclass\n",
|
||
|
|
"class Block:\n",
|
||
|
|
" id: int\n",
|
||
|
|
" slot: int\n",
|
||
|
|
" height: int\n",
|
||
|
|
" parent: int\n",
|
||
|
|
" leader: int"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 4,
|
||
|
|
"id": "a538cf45-d551-4603-b484-dbbc3f3d0a73",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"@dataclass\n",
|
||
|
|
"class NetworkParams:\n",
|
||
|
|
" broadcast_delay_mean: int # second\n",
|
||
|
|
" pol_proof_time: int # seconds\n",
|
||
|
|
" # ---- blend network -- \n",
|
||
|
|
" blending_delay: int\n",
|
||
|
|
" desimenation_delay_mean: float\n",
|
||
|
|
" # desimenation_delay_var: float\n",
|
||
|
|
" blend_hops: int\n",
|
||
|
|
" no_network_delay: bool = False\n",
|
||
|
|
"\n",
|
||
|
|
" def sample_blending_delay(self):\n",
|
||
|
|
" return np.random.uniform(0, self.blending_delay)\n",
|
||
|
|
"\n",
|
||
|
|
" def sample_desimenation_delay(self):\n",
|
||
|
|
" return np.random.exponential(self.desimenation_delay_mean)\n",
|
||
|
|
" # scale = self.desimenation_delay_var / self.desimenation_delay_mean\n",
|
||
|
|
" # shape = self.desimenation_delay_mean / scale\n",
|
||
|
|
" # return np.random.gamma(shape=shape, scale=scale)\n",
|
||
|
|
"\n",
|
||
|
|
" def sample_blend_network_delay(self):\n",
|
||
|
|
" return sum(self.sample_blending_delay() + self.sample_desimenation_delay() for _ in range(self.blend_hops))\n",
|
||
|
|
" \n",
|
||
|
|
" def sample_broadcast_delay(self, blocks):\n",
|
||
|
|
" return np.random.exponential(self.broadcast_delay_mean, size=blocks.shape)\n",
|
||
|
|
"\n",
|
||
|
|
" def block_arrival_slot(self, block_slot):\n",
|
||
|
|
" if self.no_network_delay:\n",
|
||
|
|
" return block_slot\n",
|
||
|
|
" # return self.pol_proof_time + self.sample_mixnet_delay() + self.sample_broadcast_delay(block_slot) + block_slot\n",
|
||
|
|
" return self.pol_proof_time + self.sample_blend_network_delay() + self.sample_broadcast_delay(block_slot) + block_slot\n",
|
||
|
|
"\n",
|
||
|
|
" def empirical_network_delay(self, N=10000, M=1000):\n",
|
||
|
|
" return np.array([self.block_arrival_slot(np.zeros(M)) for _ in range(N)]).reshape(N*M)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 5,
|
||
|
|
"id": "17ef82f8-968c-48b0-bee7-f2642c8b3f3e",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 640x480 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"blend_net = NetworkParams(\n",
|
||
|
|
" broadcast_delay_mean=0.5,\n",
|
||
|
|
" pol_proof_time=1,\n",
|
||
|
|
" blending_delay=2,\n",
|
||
|
|
" desimenation_delay_mean=0.5,\n",
|
||
|
|
" blend_hops=3,\n",
|
||
|
|
")\n",
|
||
|
|
"no_blend_net = replace(blend_net, blend_hops=0)\n",
|
||
|
|
"\n",
|
||
|
|
"N = 100\n",
|
||
|
|
"M = 10000\n",
|
||
|
|
"no_blend_samples = no_blend_net.empirical_network_delay()\n",
|
||
|
|
"no_blend_mean = no_blend_samples.mean()\n",
|
||
|
|
"blend_samples = blend_net.empirical_network_delay()\n",
|
||
|
|
"blend_mean = blend_samples.mean()\n",
|
||
|
|
"\n",
|
||
|
|
"_ = plt.hist(no_blend_samples, bins=100, density=True, label=\"no-blend\")\n",
|
||
|
|
"_ = plt.hist(blend_samples, bins=100, density=True, label=\"blend\")\n",
|
||
|
|
"\n",
|
||
|
|
"for p in [50, 99, 99.9]:\n",
|
||
|
|
" no_blend_pct = np.percentile(no_blend_samples, p)\n",
|
||
|
|
" _ = plt.vlines(no_blend_pct, ymin=0, ymax=0.25, color='darkblue', label=f\"no-blend {p}p={no_blend_pct:.1f}s\")\n",
|
||
|
|
"\n",
|
||
|
|
"for p in [50, 99, 99.9]:\n",
|
||
|
|
" blend_pct = np.percentile(blend_samples, p)\n",
|
||
|
|
" _ = plt.vlines(blend_pct, ymin=0, ymax=0.25, color='brown', label=f\"blend {p}p={blend_pct:.1f}s\")\n",
|
||
|
|
"# _ = plt.vlines(blend_mean, ymin=0, ymax=1, color='brown', label=f\"blend 50p={blend_mean:.1f}s\")\n",
|
||
|
|
"# _ = plt.hist(blend_net.block_arrival_slot(np.zeros(1000)), bins=100, density=True, label=\"blend\")\n",
|
||
|
|
"_ = plt.legend()\n",
|
||
|
|
"_ = plt.xlabel(\"block delay\")"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 6,
|
||
|
|
"id": "24779de7-284f-4200-9e4a-d2aa6e1b823b",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"@dataclass\n",
|
||
|
|
"class Params:\n",
|
||
|
|
" SLOTS: int\n",
|
||
|
|
" f: float\n",
|
||
|
|
" honest_stake: np.array\n",
|
||
|
|
" adversary_control: float\n",
|
||
|
|
" total_stake_estimate: float\n",
|
||
|
|
"\n",
|
||
|
|
" @property\n",
|
||
|
|
" def N(self):\n",
|
||
|
|
" return len(self.honest_stake) + 1\n",
|
||
|
|
"\n",
|
||
|
|
" @property\n",
|
||
|
|
" def stake(self):\n",
|
||
|
|
" return np.append(self.honest_stake, self.honest_stake.sum() / (1/self.adversary_control - 1))\n",
|
||
|
|
" \n",
|
||
|
|
" @property\n",
|
||
|
|
" def relative_stake(self):\n",
|
||
|
|
" return self.stake / self.total_stake_estimate\n",
|
||
|
|
"\n",
|
||
|
|
" def slot_prob(self):\n",
|
||
|
|
" return phi(self.f, self.relative_stake)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 7,
|
||
|
|
"id": "a90495a8-fcda-4e47-92b4-cc5ceaa9ff9c",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"class Sim:\n",
|
||
|
|
" def __init__(self, params: Params, network: NetworkParams):\n",
|
||
|
|
" self.params = params\n",
|
||
|
|
" self.network = network\n",
|
||
|
|
" self.leaders = np.zeros((params.N, params.SLOTS), dtype=np.int64)\n",
|
||
|
|
" self.blocks = []\n",
|
||
|
|
" max_number_of_blocks = int(3 * params.SLOTS * params.f)\n",
|
||
|
|
" self.block_slots = np.zeros(max_number_of_blocks, dtype=np.int64)\n",
|
||
|
|
" self.block_heights = np.zeros(max_number_of_blocks, dtype=np.int64)\n",
|
||
|
|
" self.block_arrivals = np.zeros(shape=(params.N, max_number_of_blocks), dtype=np.int64) # arrival time to each leader for each block\n",
|
||
|
|
" self.block_arrivals[:,:] = self.params.SLOTS\n",
|
||
|
|
" # self.block_arrivals = np.zeros(shape=(params.N, 0), dtype=np.int64) # arrival time to each leader for each block\n",
|
||
|
|
"\n",
|
||
|
|
" \n",
|
||
|
|
" def emit_block(self, leader, slot, height, parent):\n",
|
||
|
|
" assert type(leader) in [int, np.int64]\n",
|
||
|
|
" assert type(slot) in [int, np.int64]\n",
|
||
|
|
" assert type(height) in [int, np.int64]\n",
|
||
|
|
" assert type(parent) in [int, np.int64]\n",
|
||
|
|
"\n",
|
||
|
|
" block = Block(\n",
|
||
|
|
" id=len(self.blocks),\n",
|
||
|
|
" slot=slot,\n",
|
||
|
|
" height=height,\n",
|
||
|
|
" parent=parent,\n",
|
||
|
|
" leader=leader,\n",
|
||
|
|
" )\n",
|
||
|
|
" self.blocks.append(block)\n",
|
||
|
|
" self.block_slots[block.id] = block.slot\n",
|
||
|
|
" self.block_heights[block.id] = block.height\n",
|
||
|
|
" \n",
|
||
|
|
" # decide when this block will arrive at each node\n",
|
||
|
|
" new_block_arrival_by_node = self.network.block_arrival_slot(np.repeat(block.slot, self.params.N))\n",
|
||
|
|
"\n",
|
||
|
|
" if parent != -1:\n",
|
||
|
|
" # the new block cannot arrive before it's parent\n",
|
||
|
|
" parent_arrival_by_node = self.block_arrivals[:,parent]\n",
|
||
|
|
" new_block_arrival_by_node = np.maximum(new_block_arrival_by_node, parent_arrival_by_node)\n",
|
||
|
|
"\n",
|
||
|
|
" self.block_arrivals[:,block.id] = new_block_arrival_by_node\n",
|
||
|
|
" # self.block_arrivals = np.append(self.block_arrivals, new_block_arrival_by_node.reshape((self.params.N, 1)), axis=1)\n",
|
||
|
|
"\n",
|
||
|
|
" return block.id\n",
|
||
|
|
"\n",
|
||
|
|
" def emit_leader_block(self, leader, slot):\n",
|
||
|
|
" assert type(leader) in [int, np.int64], type(leader)\n",
|
||
|
|
" assert isinstance(slot, int)\n",
|
||
|
|
"\n",
|
||
|
|
" parent = self.fork_choice(leader, slot)\n",
|
||
|
|
" return self.emit_block(\n",
|
||
|
|
" leader,\n",
|
||
|
|
" slot,\n",
|
||
|
|
" height=self.blocks[parent].height + 1,\n",
|
||
|
|
" parent=parent,\n",
|
||
|
|
" )\n",
|
||
|
|
"\n",
|
||
|
|
" def fork_choice(self, leader, slot):\n",
|
||
|
|
" assert type(leader) in [int, np.int64], type(leader)\n",
|
||
|
|
" assert isinstance(slot, int)\n",
|
||
|
|
" arrived_blocks = (self.block_arrivals[leader, :len(self.blocks)] <= slot) * self.block_heights[:len(self.blocks)]\n",
|
||
|
|
" concurrent = (arrived_blocks == np.max(arrived_blocks)).nonzero()[0]\n",
|
||
|
|
" return np.random.choice(concurrent)\n",
|
||
|
|
"\n",
|
||
|
|
" def plot_spacetime_diagram(self, MAX_SLOT=1000):\n",
|
||
|
|
" alpha_index = sorted(range(self.params.N), key=lambda n: self.params.relative_stake[n])\n",
|
||
|
|
" nodes = [f\"$N_{n}$($\\\\alpha$={self.params.relative_stake[n]:.2f})\" for n in alpha_index]\n",
|
||
|
|
" messages = [(nodes[alpha_index.index(self.blocks[b].leader)], nodes[alpha_index.index(node)], self.blocks[b].slot, arrival_slot, f\"$B_{{{b}}}$\") for b, arrival_slots in enumerate(self.block_arrivals[:,:len(self.blocks)].T) for node, arrival_slot in enumerate(arrival_slots) if arrival_slot < MAX_SLOT]\n",
|
||
|
|
" \n",
|
||
|
|
" fig, ax = plt.subplots(figsize=(8,4))\n",
|
||
|
|
" \n",
|
||
|
|
" # Plot vertical lines for each node\n",
|
||
|
|
" max_slot = max(s for _,_,start_t, end_t,_ in messages for s in [start_t, end_t])\n",
|
||
|
|
" for i, node in enumerate(nodes):\n",
|
||
|
|
" ax.plot([i, i], [0, max_slot], 'k-', linewidth=0.1)\n",
|
||
|
|
" ax.text(i, max_slot + 30 * (0 if i % 2 == 0 else 1), node, ha='center', va='bottom')\n",
|
||
|
|
" \n",
|
||
|
|
" # Plot messages\n",
|
||
|
|
" colors = plt.cm.rainbow(np.linspace(0, 1, len(messages)))\n",
|
||
|
|
" for (start, end, start_time, end_time, label), color in zip(messages, colors):\n",
|
||
|
|
" start_idx = nodes.index(start)\n",
|
||
|
|
" end_idx = nodes.index(end)\n",
|
||
|
|
" ax.annotate('', xy=(end_idx, end_time), xytext=(start_idx, start_time),\n",
|
||
|
|
" arrowprops=dict(arrowstyle='->', color=\"black\", lw=0.5))\n",
|
||
|
|
" placement = 0\n",
|
||
|
|
" mid_x = start_idx * (1 - placement) + end_idx * placement\n",
|
||
|
|
" mid_y = start_time * (1 - placement) + end_time * placement\n",
|
||
|
|
" ax.text(mid_x, mid_y, label, ha='center', va='center', \n",
|
||
|
|
" bbox=dict(facecolor='white', edgecolor='none', alpha=0.7))\n",
|
||
|
|
" \n",
|
||
|
|
" ax.set_xlim(-1, len(nodes))\n",
|
||
|
|
" ax.set_ylim(0, max_slot + 70)\n",
|
||
|
|
" ax.set_xticks(range(len(nodes)))\n",
|
||
|
|
" ax.set_xticklabels([])\n",
|
||
|
|
" # ax.set_yticks([])\n",
|
||
|
|
" ax.set_title('Space-Time Diagram')\n",
|
||
|
|
" ax.set_ylabel('Slot')\n",
|
||
|
|
" \n",
|
||
|
|
" plt.tight_layout()\n",
|
||
|
|
" plt.show()\n",
|
||
|
|
"\n",
|
||
|
|
" def honest_chain(self):\n",
|
||
|
|
" chain_head = max(self.blocks, key=lambda b: b.height)\n",
|
||
|
|
" honest_chain = {chain_head.id}\n",
|
||
|
|
" \n",
|
||
|
|
" curr_block = chain_head\n",
|
||
|
|
" while curr_block.parent >= 0:\n",
|
||
|
|
" honest_chain.add(curr_block.parent)\n",
|
||
|
|
" curr_block = self.blocks[curr_block.parent]\n",
|
||
|
|
" return sorted(honest_chain, key=lambda b: self.blocks[b].height)\n",
|
||
|
|
"\n",
|
||
|
|
" def visualize_chain(self):\n",
|
||
|
|
" honest_chain = self.honest_chain()\n",
|
||
|
|
" print(\"Honest chain length\", len(honest_chain))\n",
|
||
|
|
" honest_chain_set = set(honest_chain)\n",
|
||
|
|
" \n",
|
||
|
|
" layout = Layout()\n",
|
||
|
|
" layout.hierachical = True\n",
|
||
|
|
" \n",
|
||
|
|
" G = Network(width=1600, height=800, notebook=True, directed=True, layout=layout, cdn_resources='in_line')\n",
|
||
|
|
"\n",
|
||
|
|
" for block in self.blocks:\n",
|
||
|
|
" # level = slot\n",
|
||
|
|
" level = block.height\n",
|
||
|
|
" color = \"lightgrey\"\n",
|
||
|
|
" if block.id in honest_chain_set:\n",
|
||
|
|
" color = \"orange\"\n",
|
||
|
|
"\n",
|
||
|
|
" G.add_node(int(block.id), level=level, color=color, label=f\"{block.id},{block.slot}\")\n",
|
||
|
|
" if block.parent >= 0:\n",
|
||
|
|
" G.add_edge(int(block.id), int(block.parent), width=2, color=color)\n",
|
||
|
|
" \n",
|
||
|
|
" return G.show(\"chain.html\")\n",
|
||
|
|
"\n",
|
||
|
|
" def run(self, seed=None):\n",
|
||
|
|
" from collections import defaultdict\n",
|
||
|
|
" timings = defaultdict(float)\n",
|
||
|
|
" start_t = time.time()\n",
|
||
|
|
" if seed is not None:\n",
|
||
|
|
" np.random.seed(seed)\n",
|
||
|
|
"\n",
|
||
|
|
" # emit the genesis block\n",
|
||
|
|
" self.emit_block(\n",
|
||
|
|
" leader=0,\n",
|
||
|
|
" slot=0,\n",
|
||
|
|
" height=1,\n",
|
||
|
|
" parent=-1,\n",
|
||
|
|
" )\n",
|
||
|
|
" self.block_arrivals[:,0] = 0 # all nodes see the genesis block\n",
|
||
|
|
"\n",
|
||
|
|
" prep_t = time.time()\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
" for s in range(1, self.params.SLOTS):\n",
|
||
|
|
" slot_start_t = time.time()\n",
|
||
|
|
" # the adversary will not participate in the simulation\n",
|
||
|
|
" # (implemented by never delivering blocks to the adversary)\n",
|
||
|
|
" # self.block_arrivals[-1,:] = self.params.SLOTS\n",
|
||
|
|
"\n",
|
||
|
|
" self.leaders[:,s] = np.random.random(size=self.params.N) < self.params.slot_prob()\n",
|
||
|
|
" leader_lottery_t = time.time()\n",
|
||
|
|
"\n",
|
||
|
|
" for leader in np.nonzero(self.leaders[:,s])[0]:\n",
|
||
|
|
" lead_start_t = time.time()\n",
|
||
|
|
" if self.params.adversary_control is not None and leader == self.params.N - 1:\n",
|
||
|
|
" continue\n",
|
||
|
|
" \n",
|
||
|
|
" parent = self.fork_choice(leader, s)\n",
|
||
|
|
" fork_choice_t = time.time()\n",
|
||
|
|
" \n",
|
||
|
|
" self.emit_block(\n",
|
||
|
|
" leader,\n",
|
||
|
|
" s,\n",
|
||
|
|
" height=self.blocks[parent].height + 1,\n",
|
||
|
|
" parent=parent,\n",
|
||
|
|
" )\n",
|
||
|
|
" emit_leader_block_t = time.time()\n",
|
||
|
|
"\n",
|
||
|
|
" timings[\"forkchoice\"] += fork_choice_t - lead_start_t\n",
|
||
|
|
" timings[\"emit_leader_block\"] += emit_leader_block_t - fork_choice_t\n",
|
||
|
|
" \n",
|
||
|
|
" # self.emit_leader_block(leader, s)\n",
|
||
|
|
" slot_end_t = time.time()\n",
|
||
|
|
" timings[\"leader\"] += leader_lottery_t - slot_start_t\n",
|
||
|
|
" timings[\"emit\"] += slot_end_t - leader_lottery_t\n",
|
||
|
|
" timings[\"slot\"] += slot_end_t - slot_start_t\n",
|
||
|
|
"\n",
|
||
|
|
" end_t = time.time()\n",
|
||
|
|
" timings[\"prep\"] = prep_t - start_t\n",
|
||
|
|
" timings[\"total\"] = end_t - start_t\n",
|
||
|
|
" # for phase, duration in timings.items():\n",
|
||
|
|
" # print(f\"{phase}\\t{duration:.2f}s\")\n",
|
||
|
|
"\n",
|
||
|
|
" def adverserial_analysis(self, should_plot=False, seed=0, k=2160):\n",
|
||
|
|
" from collections import defaultdict\n",
|
||
|
|
"\n",
|
||
|
|
" timings = defaultdict(float)\n",
|
||
|
|
"\n",
|
||
|
|
" start_t = time.time()\n",
|
||
|
|
" np.random.seed(seed)\n",
|
||
|
|
" \n",
|
||
|
|
" adversary = self.params.N-1 # adversary is always the last node in our simulations\n",
|
||
|
|
"\n",
|
||
|
|
" self.block_arrivals[adversary,:len(self.blocks)] = self.block_slots[:len(self.blocks)] # we will say the adversary receives the blocks immidiately\n",
|
||
|
|
"\n",
|
||
|
|
" honest_chain = self.honest_chain()\n",
|
||
|
|
" \n",
|
||
|
|
" honest_chain_t = time.time()\n",
|
||
|
|
" \n",
|
||
|
|
" honest_height_by_slot = np.zeros(self.params.SLOTS, dtype=np.int64)\n",
|
||
|
|
"\n",
|
||
|
|
" for block_id in honest_chain:\n",
|
||
|
|
" honest_height_by_slot[self.blocks[block_id].slot] = 1\n",
|
||
|
|
" honest_height_by_slot = honest_height_by_slot.cumsum()\n",
|
||
|
|
" \n",
|
||
|
|
" honest_height_by_slot_t = time.time()\n",
|
||
|
|
" \n",
|
||
|
|
" reorg_depths = []\n",
|
||
|
|
" if should_plot:\n",
|
||
|
|
" plt.figure(figsize=(20, 6))\n",
|
||
|
|
" ax = plt.subplot(121)\n",
|
||
|
|
" advantage = np.zeros(self.params.SLOTS)\n",
|
||
|
|
" \n",
|
||
|
|
" adversary_active_slots = np.random.random(size=self.params.SLOTS) < phi(self.params.f, self.params.relative_stake[adversary])\n",
|
||
|
|
" adversary_cumsum = adversary_active_slots.cumsum()\n",
|
||
|
|
"\n",
|
||
|
|
" all_active_slots = (self.leaders.sum(axis=0) + adversary_active_slots) > 0\n",
|
||
|
|
" slot_lookahead = int(3 * k / self.params.f)\n",
|
||
|
|
" \n",
|
||
|
|
" prep_t = time.time()\n",
|
||
|
|
" timings[\"honest_chain\"] += honest_chain_t - start_t\n",
|
||
|
|
" timings[\"honest_height_by_slot\"] += honest_height_by_slot_t - honest_chain_t\n",
|
||
|
|
" timings[\"prep_analysis\"] += prep_t - start_t\n",
|
||
|
|
" for b in range(len(self.blocks)):\n",
|
||
|
|
" block_start_t = time.time()\n",
|
||
|
|
" block = self.blocks[b]\n",
|
||
|
|
" if block.id > 0 and block.id % 5000 == 0:\n",
|
||
|
|
" print(\"Processing block\", block)\n",
|
||
|
|
" \n",
|
||
|
|
" nearest_honest_block = block\n",
|
||
|
|
" while nearest_honest_block.height >= len(honest_chain) or honest_chain[nearest_honest_block.height-1] != nearest_honest_block.id:\n",
|
||
|
|
" nearest_honest_block = self.blocks[nearest_honest_block.parent]\n",
|
||
|
|
"\n",
|
||
|
|
" nearest_honest_t = time.time()\n",
|
||
|
|
" \n",
|
||
|
|
" cumulative_rel_height = adversary_cumsum[block.slot+1:block.slot+1 + slot_lookahead] - adversary_cumsum[block.slot]\n",
|
||
|
|
"\n",
|
||
|
|
" adverserial_height_by_slot = block.height + cumulative_rel_height\n",
|
||
|
|
"\n",
|
||
|
|
" honest_height_by_slot_lookahead = honest_height_by_slot[block.slot + 1:block.slot+1 + slot_lookahead]\n",
|
||
|
|
" \n",
|
||
|
|
" adverserial_wins = adverserial_height_by_slot > honest_height_by_slot_lookahead\n",
|
||
|
|
" \n",
|
||
|
|
" reorg_events = adverserial_wins & all_active_slots[block.slot+1:block.slot+1 + slot_lookahead]\n",
|
||
|
|
"\n",
|
||
|
|
" \n",
|
||
|
|
" reorg_events_t = time.time()\n",
|
||
|
|
" reorg_depth = honest_height_by_slot_lookahead[reorg_events] - nearest_honest_block.height\n",
|
||
|
|
" reorg_depth_t = time.time()\n",
|
||
|
|
" reorg_depths += list(reorg_depth)\n",
|
||
|
|
" block_end_t = time.time()\n",
|
||
|
|
" timings[\"nearest_honest\"] += nearest_honest_t - block_start_t\n",
|
||
|
|
" timings[\"reorg_events\"] += reorg_events_t - nearest_honest_t\n",
|
||
|
|
" timings[\"reorg_depth\"] += reorg_depth_t - reorg_events_t\n",
|
||
|
|
" timings[\"depth_append\"] += block_end_t - reorg_depth_t\n",
|
||
|
|
" \n",
|
||
|
|
" if should_plot:\n",
|
||
|
|
" if reorg_events.sum() > 0:\n",
|
||
|
|
" first_slot = block.slot+1\n",
|
||
|
|
" last_slot = first_slot + np.nonzero(reorg_events)[0].max() + 1\n",
|
||
|
|
" advantage[first_slot:last_slot] = np.maximum(advantage[first_slot:last_slot], adverserial_height_by_slot[:last_slot-first_slot]-honest_height_by_slot[first_slot:last_slot])\n",
|
||
|
|
"\n",
|
||
|
|
" for phase, duration in timings.items():\n",
|
||
|
|
" print(f\"{phase}\\t{duration:.2f}s\")\n",
|
||
|
|
" \n",
|
||
|
|
" if should_plot:\n",
|
||
|
|
" ax.plot(advantage, color='k', lw=\"0.5\")\n",
|
||
|
|
" _ = ax.set_title(f\"max chain weight with adversery controlling {self.params.relative_stake[adversary] * 100:.0f}% of stake\")\n",
|
||
|
|
" _ = ax.set_ylabel(\"adversary height advantage\")\n",
|
||
|
|
" _ = ax.set_xlabel(\"slot\")\n",
|
||
|
|
" _ = ax.legend()\n",
|
||
|
|
"\n",
|
||
|
|
" ax = plt.subplot(122)\n",
|
||
|
|
" _ = ax.grid(True)\n",
|
||
|
|
" _ = ax.hist(reorg_depths, density=False, bins=100)\n",
|
||
|
|
" _ = ax.set_title(f\"re-org depth with {self.params.relative_stake[adversary] * 100:.0f}% adversary\")\n",
|
||
|
|
" _ = ax.set_xlabel(\"re-org depth\")\n",
|
||
|
|
" _ = ax.set_ylabel(\"frequency\")\n",
|
||
|
|
" return reorg_depths"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 8,
|
||
|
|
"id": "acea0d51-2dc2-408a-8f88-10b9cf639599",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"def multi_epoch_sim(params: Params, network: NetworkParams, beta: float, epochs: int):\n",
|
||
|
|
" stake_estimate = params.total_stake_estimate\n",
|
||
|
|
" sims = []\n",
|
||
|
|
" for j in range(epochs):\n",
|
||
|
|
" print(f\"simulating epoch {j}\")\n",
|
||
|
|
" sim = Sim(\n",
|
||
|
|
" params=replace(params, total_stake_estimate=stake_estimate),\n",
|
||
|
|
" network=network,\n",
|
||
|
|
" )\n",
|
||
|
|
" sim.run()\n",
|
||
|
|
" sims.append(sim)\n",
|
||
|
|
" \n",
|
||
|
|
" honest = sim.honest_chain()\n",
|
||
|
|
" honest_slots = np.array([sim.blocks[b].slot for b in honest])\n",
|
||
|
|
" \n",
|
||
|
|
" error = 1 - len(honest) / (params.SLOTS * params.f)\n",
|
||
|
|
" h = beta * stake_estimate\n",
|
||
|
|
" stake_estimate = stake_estimate - h * error\n",
|
||
|
|
"\n",
|
||
|
|
" return sims"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "43ca547b-ac56-41c7-a46e-f63768dfd380",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"stake_real = np.random.pareto(10, 100)\n",
|
||
|
|
"f = 1/30\n",
|
||
|
|
"params = Params(\n",
|
||
|
|
" SLOTS=int(6 * 2160 / f),\n",
|
||
|
|
" f=f,\n",
|
||
|
|
" adversary_control = 10 ** -9,\n",
|
||
|
|
" honest_stake = stake_real,\n",
|
||
|
|
" total_stake_estimate = stake_real.sum(),\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"sims = multi_epoch_sim(\n",
|
||
|
|
" params=params,\n",
|
||
|
|
" network=blend_net,\n",
|
||
|
|
" beta=0.8,\n",
|
||
|
|
" epochs=10\n",
|
||
|
|
")"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "235c7ae0-05f7-451a-9ad6-2c852a81ccd7",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# Bias\n",
|
||
|
|
"\n",
|
||
|
|
"$\\boxed{\\langle D_{\\infty}\\rangle=\\frac{\\log(1-f)}{\\log(1-f/q)} D^0[\\mathbf{w}]}$"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "b755620d-d1f8-45d5-ad14-9b913cb7db7b",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# measure `q` - honest chain growth rate\n",
|
||
|
|
"sim = sims[0]\n",
|
||
|
|
"\n",
|
||
|
|
"f = sim.params.f\n",
|
||
|
|
"\n",
|
||
|
|
"honest_chain_growth_rate = len(sim.honest_chain()) / (sim.params.SLOTS * f)\n",
|
||
|
|
"wasted_block_rate = (len(sim.blocks) - len(sim.honest_chain())) / (sim.params.SLOTS * f)\n",
|
||
|
|
"q = (1 - wasted_block_rate)\n",
|
||
|
|
"q\n",
|
||
|
|
"network_ineffeciency_bias = np.log(1 - f) / np.log(1 - (f / q))\n",
|
||
|
|
"network_ineffeciency_bias"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "b0659dbe-6151-4a9a-aab0-0c9cdeaa4d32",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"EPOCHS = len(sims)\n",
|
||
|
|
"\n",
|
||
|
|
"plt.figure(figsize=(16, 8))\n",
|
||
|
|
"ax = plt.subplot(321)\n",
|
||
|
|
"ax.plot(range(EPOCHS), [s.params.total_stake_estimate / s.params.honest_stake.sum() for s in sims])\n",
|
||
|
|
"ax.plot(range(EPOCHS), [s.params.honest_stake.sum() / s.params.honest_stake.sum() for s in sims])\n",
|
||
|
|
"ax.plot(range(EPOCHS), np.repeat(network_ineffeciency_bias, EPOCHS))\n",
|
||
|
|
"ax.set_title(\"Total Stake Convergence\")\n",
|
||
|
|
"ax.set_ylabel(\"Total Stake Estimate / True Total Stake$\")\n",
|
||
|
|
"ax.set_xlabel(\"Epoch\")\n",
|
||
|
|
"# slots_list = np.array(range(epoch_length * EPOCHS))\n",
|
||
|
|
"\n",
|
||
|
|
"ax = plt.subplot(322)\n",
|
||
|
|
"ax.plot(range(EPOCHS), [len(s.blocks) / s.params.SLOTS for s in sims])\n",
|
||
|
|
"ax.set_title(\"Block Production Rate\")\n",
|
||
|
|
"ax.set_ylabel(\"Blocks per Slot\")\n",
|
||
|
|
"ax.set_xlabel(\"Epoch\")\n",
|
||
|
|
"\n",
|
||
|
|
"ax = plt.subplot(323)\n",
|
||
|
|
"ax.plot(range(EPOCHS), [len(s.honest_chain()) / s.params.SLOTS for s in sims])\n",
|
||
|
|
"ax.plot(range(EPOCHS), [s.params.f for s in sims])\n",
|
||
|
|
"ax.set_title(\"Honest Chain Growth\")\n",
|
||
|
|
"ax.set_ylabel(\"Blocks per Slot\")\n",
|
||
|
|
"ax.set_xlabel(\"Epoch\")\n",
|
||
|
|
"\n",
|
||
|
|
"ax = plt.subplot(324)\n",
|
||
|
|
"ax.plot(range(EPOCHS), [(s.leaders.sum(axis=0) > 0).sum() / s.params.SLOTS for s in sims])\n",
|
||
|
|
"ax.plot(range(EPOCHS), [s.params.f for s in sims])\n",
|
||
|
|
"ax.set_title(\"Active Slots by Epoch\")\n",
|
||
|
|
"ax.set_ylabel(\"Active Slot\")\n",
|
||
|
|
"ax.set_xlabel(\"Epoch\")\n",
|
||
|
|
"\n",
|
||
|
|
"ax = plt.subplot(325)\n",
|
||
|
|
"ax.hist([s.params.total_stake_estimate for s in sims[5:]], bins=50)\n",
|
||
|
|
"ax.set_title(\"Total Stake Estimate Distribution\")\n",
|
||
|
|
"ax.set_xlabel(\"Total Stake Estimate\")\n",
|
||
|
|
"\n",
|
||
|
|
"# plt.plot(slots_list, np.array(ratios_sims).ravel())\n",
|
||
|
|
"# plt.plot(slots_list, np.full(epoch_length * EPOCHS, f_value))\n",
|
||
|
|
"# plt.xlabel(\"Slot\")\n",
|
||
|
|
"# #plt.yscale('log')\n",
|
||
|
|
"# # plt.ylim(1/35, 1/25)\n",
|
||
|
|
"# plt.ylabel(\"Honest chain growth rate until this slot\")\n",
|
||
|
|
"# plt.title(\"Honest chain growth rate convergence\")\n",
|
||
|
|
"\n",
|
||
|
|
"plt.tight_layout()\n",
|
||
|
|
"plt.show()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 9,
|
||
|
|
"id": "7ff2af11-0ad6-4647-a17a-127143459bb8",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"def network_bias(sim: Sim):\n",
|
||
|
|
" f = sim.params.f\n",
|
||
|
|
" honest_chain_growth_rate = len(sim.honest_chain()) / (sim.params.SLOTS * f)\n",
|
||
|
|
" wasted_block_rate = (len(sim.blocks) - len(sim.honest_chain())) / (sim.params.SLOTS * f)\n",
|
||
|
|
" q = (1 - wasted_block_rate)\n",
|
||
|
|
" print(q)\n",
|
||
|
|
" return np.log(1 - f) / np.log(1 - (f / q))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "490adad2-00d4-4019-bb53-43659d060e37",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"stake_real = np.random.pareto(10, 100)\n",
|
||
|
|
"f = 1/30\n",
|
||
|
|
"params = Params(\n",
|
||
|
|
" SLOTS=int(6 * 2160 / f),\n",
|
||
|
|
" f=f,\n",
|
||
|
|
" adversary_control = 10 ** -9,\n",
|
||
|
|
" honest_stake = stake_real,\n",
|
||
|
|
" total_stake_estimate = stake_real.sum(),\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"vary_net_delay = [multi_epoch_sim(\n",
|
||
|
|
" params=params,\n",
|
||
|
|
" network=replace(blend_net, blend_hops=hops),\n",
|
||
|
|
" beta=1,\n",
|
||
|
|
" epochs=100\n",
|
||
|
|
") for hops in [0,2,4,6]]"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "51588658-0004-4445-ba7e-2db291a3aefd",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"plt.figure(figsize=(16, 8))\n",
|
||
|
|
"ax = plt.subplot(111)\n",
|
||
|
|
"\n",
|
||
|
|
"process_data = np.array([[s.params.total_stake_estimate / s.params.honest_stake.sum() for s in sims] for sims in vary_net_delay])[:,1:]\n",
|
||
|
|
"delay = [sims[0].network.empirical_network_delay().mean() for sims in vary_net_delay]\n",
|
||
|
|
"for pct in [99.5, 95, 90]:\n",
|
||
|
|
" # pct = 100\n",
|
||
|
|
" data_low = np.percentile(process_data, 100 - pct, axis=1)\n",
|
||
|
|
" data_high = np.percentile(process_data, pct, axis=1)\n",
|
||
|
|
" # ax.fill_between(delay, data_low, data_high, alpha=0.1, color=\"k\", label=f\"$D_\\\\infty$ {pct}pct\")\n",
|
||
|
|
" ax.fill_between(delay, data_low, data_high, alpha=0.1, lw=0, color=\"k\")\n",
|
||
|
|
"ax.plot(delay, [sims[0].params.honest_stake.sum() / sims[0].params.honest_stake.sum() for sims in vary_net_delay], label=\"$D_{TRUE}$\")\n",
|
||
|
|
"ax.plot(delay, process_data.mean(axis=1), color=\"k\", label=\"simulation $\\\\mathbb{E}\\\\left[D_\\\\infty\\\\right]$\")\n",
|
||
|
|
"ax.plot(delay, [network_bias(sims[0]) for sims in vary_net_delay], label=\"analysis $\\\\mathbb{E}\\\\left[D_\\\\infty\\\\right]$\")\n",
|
||
|
|
"\n",
|
||
|
|
"ax.set_title(\"Total Stake Convergence\")\n",
|
||
|
|
"ax.set_ylabel(\"$D_\\\\infty / D_\\\\text{TRUE}$\")\n",
|
||
|
|
"ax.set_xlabel(\"Mean Network Delay (seconds)\")\n",
|
||
|
|
"ax.legend()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "ffb7c8f9-c3c4-4e02-832b-d37faab324fd",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"stake_real = np.random.pareto(10, 100)\n",
|
||
|
|
"f = 1/30\n",
|
||
|
|
"params = Params(\n",
|
||
|
|
" SLOTS=int(6 * 2160 / f),\n",
|
||
|
|
" f=f,\n",
|
||
|
|
" adversary_control = 10 ** -9,\n",
|
||
|
|
" honest_stake = stake_real,\n",
|
||
|
|
" total_stake_estimate = stake_real.sum(),\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"expected_q = 0.85\n",
|
||
|
|
"max_beta = (2 * f) / ((expected_q - f) * np.log(1/(1-f/expected_q)))\n",
|
||
|
|
"betas = np.linspace(0.5, max_beta + 0.5, 10)\n",
|
||
|
|
"vary_net_delay = [multi_epoch_sim(\n",
|
||
|
|
" params=params,\n",
|
||
|
|
" network=blend_net,\n",
|
||
|
|
" beta=beta,\n",
|
||
|
|
" epochs=50\n",
|
||
|
|
") for beta in betas]"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "3359a7e2-0b3a-432a-bdea-c0315733b1dd",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"plt.figure(figsize=(16, 8))\n",
|
||
|
|
"ax = plt.subplot(111)\n",
|
||
|
|
"\n",
|
||
|
|
"process_data = np.array([[s.params.total_stake_estimate / s.params.honest_stake.sum() for s in sims] for sims in vary_net_delay])[:,5:]\n",
|
||
|
|
"for pct in [99.5, 95, 90]:\n",
|
||
|
|
" # pct = 100\n",
|
||
|
|
" data_low = np.percentile(process_data, 100 - pct, axis=1)\n",
|
||
|
|
" data_high = np.percentile(process_data, pct, axis=1)\n",
|
||
|
|
" # ax.fill_between(delay, data_low, data_high, alpha=0.1, color=\"k\", label=f\"$D_\\\\infty$ {pct}pct\")\n",
|
||
|
|
" ax.fill_between(betas, data_low, data_high, alpha=0.1, lw=0, color=\"k\")\n",
|
||
|
|
"ax.plot(betas, [sims[0].params.honest_stake.sum() / sims[0].params.honest_stake.sum() for sims in vary_net_delay], label=\"$D_{TRUE}$\")\n",
|
||
|
|
"ax.plot(betas, process_data.mean(axis=1), color=\"k\", label=\"simulation $\\\\mathbb{E}\\\\left[D_\\\\infty\\\\right]$\")\n",
|
||
|
|
"# ax.plot(betas, [network_bias(sims[0]) for sims in vary_net_delay], label=\"analysis $\\\\mathbb{E}\\\\left[D_\\\\infty\\\\right]$\")\n",
|
||
|
|
"\n",
|
||
|
|
"# sim = sims[0]\n",
|
||
|
|
"# f = sim.params.f\n",
|
||
|
|
"# honest_chain_growth_rate = len(sim.honest_chain()) / (sim.params.SLOTS * f)\n",
|
||
|
|
"# wasted_block_rate = (len(sim.blocks) - len(sim.honest_chain())) / (sim.params.SLOTS * f)\n",
|
||
|
|
"# q = (1 - wasted_block_rate)\n",
|
||
|
|
"# actual_max_beta = (2 * f) / ((q - f) * np.log(1/(1-f/q)))\n",
|
||
|
|
"# ax.vlines(actual_max_beta, ymin=process_data.min(), ymax=process_data.max(), color=\"cyan\", label=\"$\\\\beta=\\\\frac{2f}{(q-f)\\\\log(1/(1-f/q))}$\")\n",
|
||
|
|
"\n",
|
||
|
|
"ax.vlines(max_beta, ymin=process_data.min(), ymax=process_data.max(), color=\"red\", label=\"$\\\\beta=\\\\frac{2f}{(q-f)\\\\log(1/(1-f/q))}$\")\n",
|
||
|
|
"\n",
|
||
|
|
"ax.set_title(\"Total Stake Convergence Stability\")\n",
|
||
|
|
"ax.set_ylabel(\"$D_\\\\infty / D_\\\\text{TRUE}$\")\n",
|
||
|
|
"ax.set_xlabel(\"$\\\\beta$\")\n",
|
||
|
|
"ax.legend()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "a83fe658-72bf-442b-b27f-e2b3494e5e8b",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"stake_real = np.random.pareto(10, 100)\n",
|
||
|
|
"f = 1/30\n",
|
||
|
|
"params = Params(\n",
|
||
|
|
" SLOTS=int(6 * 2160 / f * 5),\n",
|
||
|
|
" f=f,\n",
|
||
|
|
" adversary_control = 10 ** -9,\n",
|
||
|
|
" honest_stake = stake_real,\n",
|
||
|
|
" total_stake_estimate = stake_real.sum() * 0.5,\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"expected_q = 0.85\n",
|
||
|
|
"max_beta = (2 * f) / ((expected_q - f) * np.log(1/(1-f/expected_q)))\n",
|
||
|
|
"betas = np.linspace(max_beta / 4, max_beta, 5)\n",
|
||
|
|
"vary_betas = [multi_epoch_sim(\n",
|
||
|
|
" params=params,\n",
|
||
|
|
" network=blend_net,\n",
|
||
|
|
" beta=beta,\n",
|
||
|
|
" epochs=10\n",
|
||
|
|
") for beta in betas]"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "047a9f35-7c01-4825-960b-54fab943952d",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"from matplotlib.colors import Normalize\n",
|
||
|
|
"import scipy\n",
|
||
|
|
"\n",
|
||
|
|
"D_ells = np.array([[s.params.total_stake_estimate for s in sims] for sims in vary_betas])\n",
|
||
|
|
"D_true = stake_real.sum()\n",
|
||
|
|
"\n",
|
||
|
|
"EPOCHS = len(vary_betas[0])\n",
|
||
|
|
"\n",
|
||
|
|
"# plt.figure(figsize=(16, 8))\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"eps = np.array(range(EPOCHS))\n",
|
||
|
|
"\n",
|
||
|
|
"q = expected_q\n",
|
||
|
|
"\n",
|
||
|
|
"cmap = plt.cm.tab10\n",
|
||
|
|
"norm = Normalize(vmin=min(betas), vmax=max(betas))\n",
|
||
|
|
"\n",
|
||
|
|
"for beta, sims in zip(betas, vary_betas):\n",
|
||
|
|
" sim = sims[0]\n",
|
||
|
|
" # wasted_block_rate = (len(sim.blocks) - len(sim.honest_chain())) / (sim.params.SLOTS * f)\n",
|
||
|
|
" # q = (1 - wasted_block_rate)\n",
|
||
|
|
"\n",
|
||
|
|
" normed_D_ell = np.array([s.params.total_stake_estimate for s in sims]) / D_true\n",
|
||
|
|
" normed_D_0 = normed_D_ell[0]\n",
|
||
|
|
" normed_D_infty = np.log(1 - f) / np.log(1 - f / q)\n",
|
||
|
|
" normed_err = np.abs(normed_D_ell - normed_D_infty)\n",
|
||
|
|
" \n",
|
||
|
|
" delta = np.abs(normed_D_0 - normed_D_infty)\n",
|
||
|
|
" h = beta / f\n",
|
||
|
|
" converge_base = np.abs(1 - h * (q - f) * np.log(1 / (1 - f/q)))\n",
|
||
|
|
" #upper_bound = delta * np.pow(np.repeat(converge_base, EPOCHS), eps)\n",
|
||
|
|
" upper_bound = delta * np.pow(converge_base, eps)\n",
|
||
|
|
"\n",
|
||
|
|
" \n",
|
||
|
|
" A_low = 0\n",
|
||
|
|
" A_high = 1000\n",
|
||
|
|
" for i in range(50):\n",
|
||
|
|
" A_mid = (A_low + A_high) * 0.5\n",
|
||
|
|
" if np.all((A_mid * upper_bound > normed_err)[normed_err > 0.05]):\n",
|
||
|
|
" A_high = A_mid\n",
|
||
|
|
" else:\n",
|
||
|
|
" A_low = A_mid\n",
|
||
|
|
" A = A_high\n",
|
||
|
|
" \n",
|
||
|
|
" # print(delta)\n",
|
||
|
|
" # print(converge_base)\n",
|
||
|
|
" # print(upper_bound)\n",
|
||
|
|
" color = cmap(norm(beta))\n",
|
||
|
|
"\n",
|
||
|
|
" plt.plot(eps, normed_err, color=color, lw=2, label=f\"$\\\\beta = {beta:.2f}$\")\n",
|
||
|
|
" plt.plot(eps, A * upper_bound, color=color, lw=0.5, label=f\"upper bound for $\\\\beta={beta:.2f}$, $A={A:.2f}$\")\n",
|
||
|
|
" plt.legend()\n",
|
||
|
|
" plt.show()\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"# plt.plot(range(EPOCHS), np.repeat(normed_D_infty, EPOCHS), label=\"$D_\\\\infty$\")\n",
|
||
|
|
"#plt.plot(eps, np.repeat(0, EPOCHS), label=\"$D_\\\\infty$\")\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"# for beta, upper_bound in zip(betas, analytical_upper_bound.T):\n",
|
||
|
|
"# plt.plot(eps, upper_bound, label=f\"upper bound for $\\\\beta={beta:.2f}$\")\n",
|
||
|
|
"\n",
|
||
|
|
"#plt.yscale(\"log\")\n",
|
||
|
|
"\n",
|
||
|
|
"#plt.legend()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "8ddeffbe-c781-40c8-8923-96677fd83770",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# Variance Plots"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 10,
|
||
|
|
"id": "b2eebfa4-2e9e-44c2-93f0-a8df04cc9bf2",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n",
|
||
|
|
"simulating epoch 0\n",
|
||
|
|
"simulating epoch 1\n",
|
||
|
|
"simulating epoch 2\n",
|
||
|
|
"simulating epoch 3\n",
|
||
|
|
"simulating epoch 4\n",
|
||
|
|
"simulating epoch 5\n",
|
||
|
|
"simulating epoch 6\n",
|
||
|
|
"simulating epoch 7\n",
|
||
|
|
"simulating epoch 8\n",
|
||
|
|
"simulating epoch 9\n",
|
||
|
|
"simulating epoch 10\n",
|
||
|
|
"simulating epoch 11\n",
|
||
|
|
"simulating epoch 12\n",
|
||
|
|
"simulating epoch 13\n",
|
||
|
|
"simulating epoch 14\n",
|
||
|
|
"simulating epoch 15\n",
|
||
|
|
"simulating epoch 16\n",
|
||
|
|
"simulating epoch 17\n",
|
||
|
|
"simulating epoch 18\n",
|
||
|
|
"simulating epoch 19\n",
|
||
|
|
"simulating epoch 20\n",
|
||
|
|
"simulating epoch 21\n",
|
||
|
|
"simulating epoch 22\n",
|
||
|
|
"simulating epoch 23\n",
|
||
|
|
"simulating epoch 24\n",
|
||
|
|
"simulating epoch 25\n",
|
||
|
|
"simulating epoch 26\n",
|
||
|
|
"simulating epoch 27\n",
|
||
|
|
"simulating epoch 28\n",
|
||
|
|
"simulating epoch 29\n",
|
||
|
|
"simulating epoch 30\n",
|
||
|
|
"simulating epoch 31\n",
|
||
|
|
"simulating epoch 32\n",
|
||
|
|
"simulating epoch 33\n",
|
||
|
|
"simulating epoch 34\n",
|
||
|
|
"simulating epoch 35\n",
|
||
|
|
"simulating epoch 36\n",
|
||
|
|
"simulating epoch 37\n",
|
||
|
|
"simulating epoch 38\n",
|
||
|
|
"simulating epoch 39\n",
|
||
|
|
"simulating epoch 40\n",
|
||
|
|
"simulating epoch 41\n",
|
||
|
|
"simulating epoch 42\n",
|
||
|
|
"simulating epoch 43\n",
|
||
|
|
"simulating epoch 44\n",
|
||
|
|
"simulating epoch 45\n",
|
||
|
|
"simulating epoch 46\n",
|
||
|
|
"simulating epoch 47\n",
|
||
|
|
"simulating epoch 48\n",
|
||
|
|
"simulating epoch 49\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"stake_real = np.random.pareto(10, 100)\n",
|
||
|
|
"f = 1/30\n",
|
||
|
|
"params = Params(\n",
|
||
|
|
" SLOTS=int(6 * 2160 / f),\n",
|
||
|
|
" f=f,\n",
|
||
|
|
" adversary_control = 10 ** -9,\n",
|
||
|
|
" honest_stake = stake_real,\n",
|
||
|
|
" total_stake_estimate = stake_real.sum(),\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"expected_q = 0.85\n",
|
||
|
|
"optimal_beta = f / ((expected_q - f) * np.log(1/(1-f/expected_q)))\n",
|
||
|
|
"betas = np.linspace(optimal_beta*0.50, optimal_beta*1.5, 10)\n",
|
||
|
|
"vary_betas = [multi_epoch_sim(\n",
|
||
|
|
" params=params,\n",
|
||
|
|
" network=blend_net,\n",
|
||
|
|
" beta=beta,\n",
|
||
|
|
" epochs=50\n",
|
||
|
|
") for beta in betas]"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 15,
|
||
|
|
"id": "6b221a7b-7f85-423f-9f8d-7c1bbe12409f",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"<matplotlib.legend.Legend at 0x8c1b32f390>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 15,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 800x400 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"\n",
|
||
|
|
"D_true = stake_real.sum()\n",
|
||
|
|
"var = np.array([np.array([s.params.total_stake_estimate / D_true for s in sims[10:]]).var() for sims in vary_betas])\n",
|
||
|
|
"\n",
|
||
|
|
"plt.figure(figsize=(8, 4))\n",
|
||
|
|
"\n",
|
||
|
|
"plt.plot(betas, var, label=\"emperical Var[$D_\\\\infty / D_{TRUE}$]\")\n",
|
||
|
|
"\n",
|
||
|
|
"sim = vary_betas[0][0]\n",
|
||
|
|
"f = sim.params.f\n",
|
||
|
|
"T = sim.params.SLOTS\n",
|
||
|
|
"q = expected_q\n",
|
||
|
|
"\n",
|
||
|
|
"plt.plot(betas, [(beta / f)**2 * q / T * (np.log(1 - f) / np.log(1 - f/q))**2 * (1-f) * f for beta in betas], label=\"predicted Var[$D_\\\\infty / D_{TRUE}$]\")\n",
|
||
|
|
"plt.plot(betas, [(beta / f)**2 / T * (1 - f) * f for beta in betas], label=\"predicted Var[$D_\\\\infty / D_{TRUE}$] upper bound (perfect network)\")\n",
|
||
|
|
"\n",
|
||
|
|
"plt.ylabel(\"Var[$D_\\\\infty / D_{TRUE}$]\")\n",
|
||
|
|
"plt.xlabel(\"$\\\\beta$\")\n",
|
||
|
|
"plt.legend()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "758b9445-7c8c-4f0e-8a1c-364f76122f73",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"stake_real = np.random.pareto(10, 100)\n",
|
||
|
|
"f = 1/30\n",
|
||
|
|
"params = Params(\n",
|
||
|
|
" SLOTS=int(6 * 2160 / f),\n",
|
||
|
|
" f=f,\n",
|
||
|
|
" adversary_control = 10 ** -9,\n",
|
||
|
|
" honest_stake = stake_real,\n",
|
||
|
|
" total_stake_estimate = stake_real.sum() / 2,\n",
|
||
|
|
")\n",
|
||
|
|
"\n",
|
||
|
|
"expected_q = 0.85\n",
|
||
|
|
"optimal_beta = f / ((expected_q - f) * np.log(1/(1-f/expected_q)))\n",
|
||
|
|
"betas = np.linspace(optimal_beta*0.50, optimal_beta*1.5, 10)\n",
|
||
|
|
"optimal_beta_sims = [multi_epoch_sim(\n",
|
||
|
|
" params=params,\n",
|
||
|
|
" network=blend_net,\n",
|
||
|
|
" beta=optimal_beta,\n",
|
||
|
|
" epochs=5\n",
|
||
|
|
") for _ in range(50)]"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "raw",
|
||
|
|
"id": "b580ba22-b046-47bf-9d3e-a3ded385a69c",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"eps = np.array(range(len(optimal_beta_sims[0])))\n",
|
||
|
|
"\n",
|
||
|
|
"D_true = stake_real.sum()\n",
|
||
|
|
"\n",
|
||
|
|
"norm_D_ell = np.array([[s.params.total_stake_estimate for s in sims] for sims in optimal_beta_sims]) / D_true\n",
|
||
|
|
"\n",
|
||
|
|
"q = 0.85\n",
|
||
|
|
"norm_D_infty = np.log(1 - f) / np.log(1 - f / q)\n",
|
||
|
|
"\n",
|
||
|
|
"norm_err = np.abs(norm_D_ell - norm_D_infty)\n",
|
||
|
|
"\n",
|
||
|
|
"pct = 90\n",
|
||
|
|
"low = np.percentile(norm_err, 100 - pct, axis=0)\n",
|
||
|
|
"high = np.percentile(norm_err, pct, axis=0)\n",
|
||
|
|
"\n",
|
||
|
|
"plt.fill_between(eps, low, high, color=\"grey\", label=f\"{pct}pct confidence interval\")\n",
|
||
|
|
"plt.plot(eps, norm_err.mean(axis=0), color=\"k\", label=\"mean\")\n",
|
||
|
|
"plt.ylabel(\"Normalized Error\")\n",
|
||
|
|
"plt.xlabel(\"Epoch\")\n",
|
||
|
|
"plt.yscale(\"log\")\n",
|
||
|
|
"plt.legend()\n",
|
||
|
|
"None"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": null,
|
||
|
|
"id": "b46afdf0-dad2-41f1-b152-a950aa84ca52",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": []
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"metadata": {
|
||
|
|
"kernelspec": {
|
||
|
|
"display_name": "Python 3 (ipykernel)",
|
||
|
|
"language": "python",
|
||
|
|
"name": "python3"
|
||
|
|
},
|
||
|
|
"language_info": {
|
||
|
|
"codemirror_mode": {
|
||
|
|
"name": "ipython",
|
||
|
|
"version": 3
|
||
|
|
},
|
||
|
|
"file_extension": ".py",
|
||
|
|
"mimetype": "text/x-python",
|
||
|
|
"name": "python",
|
||
|
|
"nbconvert_exporter": "python",
|
||
|
|
"pygments_lexer": "ipython3",
|
||
|
|
"version": "3.13.4"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nbformat": 4,
|
||
|
|
"nbformat_minor": 5
|
||
|
|
}
|