logos-blockchain-pocs/cryptarchia/cryptarchia-with-total-stake-inference.ipynb

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
}