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

1506 lines
144 KiB
Plaintext
Raw Normal View History

{
"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
}