Skip to content

Commit

Permalink
chore(consensus): allow running multiple simulations of consensus
Browse files Browse the repository at this point in the history
  • Loading branch information
asmaastarkware committed Jul 15, 2024
1 parent 15b7af8 commit 9f0ea57
Showing 1 changed file with 49 additions and 46 deletions.
95 changes: 49 additions & 46 deletions crates/sequencing/papyrus_consensus/run_consensus.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def check_height(self):
height = self.get_height()
if self.height_and_timestamp[0] != height:
if self.height_and_timestamp[0] is not None and height is not None:
assert height > self.height_and_timestamp[0] , "Height should be increasing."
assert height > self.height_and_timestamp[0], "Height should be increasing."
self.height_and_timestamp = (height, time.time())

return self.height_and_timestamp
Expand All @@ -55,6 +55,9 @@ def find_free_port():
return s.getsockname()[1]


BOOTNODE_TCP_PORT = find_free_port()


# Returns if the simulation should exit.
def monitor_simulation(nodes, start_time, duration, stagnation_timeout):
curr_time = time.time()
Expand Down Expand Up @@ -91,31 +94,65 @@ def run_simulation(nodes, duration, stagnation_timeout):
node.stop()


def build_peernode(base_layer_node_url, temp_dir, num_validators, i):
def build_node(base_layer_node_url, temp_dir, num_validators, i):

monitoring_gateway_server_port = find_free_port()
cmd = (
tcp_port = BOOTNODE_TCP_PORT if i == 1 else find_free_port()

common_command = (
f"RUST_LOG=papyrus_consensus=debug,papyrus=info "
f"target/release/papyrus_node --network.#is_none false "
f"--base_layer.node_url {base_layer_node_url} "
f"--storage.db_config.path_prefix {temp_dir}/data{i} "
f"--consensus.#is_none false --consensus.validator_id 0x{i} "
f"--consensus.num_validators {num_validators} "
f"--network.tcp_port {find_free_port()} "
f"--network.tcp_port {tcp_port} "
f"--rpc.server_address 127.0.0.1:{find_free_port()} "
f"--monitoring_gateway.server_address 127.0.0.1:{monitoring_gateway_server_port} "
f"--network.bootstrap_peer_multiaddr.#is_none false "
f"--network.bootstrap_peer_multiaddr /ip4/127.0.0.1/tcp/10000/p2p/{BOOT_NODE_PEER_ID} "
f"--collect_metrics true"
# Use sed to strip special formatting characters
f"| sed -r 's/\\x1B\\[[0-9;]*[mK]//g' > {temp_dir}/validator{i}.txt"
f"--collect_metrics true "
)

if i == 1:
specific_command = f"--network.secret_key {SECRET_KEY} "
else:
specific_command = (
f"--network.bootstrap_peer_multiaddr.#is_none false "
f"--network.bootstrap_peer_multiaddr /ip4/127.0.0.1/tcp/{BOOTNODE_TCP_PORT}/p2p/{BOOT_NODE_PEER_ID} "
)

full_command = (
common_command
+ specific_command
+ f" | sed -r 's/\\x1B\\[[0-9;]*[mK]//g' > {temp_dir}/validator{i}.txt"
)

return Node(
validator_id=i,
monitoring_gateway_server_port=monitoring_gateway_server_port,
cmd=cmd,
cmd=full_command,
)


def build_all_nodes(base_layer_node_url, temp_dir, num_validators):
# Validators are started in a specific order to ensure proper network formation:
# 1. The bootnode (validator 1) is started first for network peering.
# 2. Validators 2+ are started next to join the network through the bootnode.
# 3. Validator 0, which is the proposer, is started last so the validators don't miss the proposals.
nodes = []

# Ensure validator 1 (bootnode) runs first
nodes.append(build_node(base_layer_node_url, temp_dir, num_validators, 1))

# Add other validators
for i in range(2, num_validators):
nodes.append(build_node(base_layer_node_url, temp_dir, num_validators, i))

# Ensure validator 0 runs last
nodes.append(build_node(base_layer_node_url, temp_dir, num_validators, 0))

return nodes


def main(base_layer_node_url, num_validators, stagnation_threshold, duration):
assert num_validators >= 2, "At least 2 validators are required for the simulation."
# Building the Papyrus Node package assuming its output will be located in the papyrus target directory.
Expand All @@ -130,46 +167,12 @@ def main(base_layer_node_url, num_validators, stagnation_threshold, duration):
data_dir = os.path.join(temp_dir, f"data{i}")
os.makedirs(data_dir)

# Validators are started in a specific order to ensure proper network formation:
# 1. The bootnode (validator 1) is started first for network peering.
# 2. Validators 2+ are started next to join the network through the bootnode.
# 3. Validator 0, which is the proposer, is started last so the validators don't miss the proposals.

nodes = []
# Ensure validator 1 runs first
monitoring_gateway_server_port = find_free_port()
bootnode_command = (
f"RUST_LOG=papyrus_consensus=debug,papyrus=info "
f"target/release/papyrus_node --network.#is_none false "
f"--base_layer.node_url {base_layer_node_url} "
f"--network.secret_key {SECRET_KEY} "
f"--storage.db_config.path_prefix {temp_dir}/data1 "
f"--consensus.#is_none false --consensus.validator_id 0x1 "
f"--consensus.num_validators {num_validators} "
f"--monitoring_gateway.server_address 127.0.0.1:{monitoring_gateway_server_port} "
f"--collect_metrics true"
# Use sed to strip special formatting characters
f"| sed -r 's/\\x1B\\[[0-9;]*[mK]//g' > {temp_dir}/validator1.txt"
)
nodes.append(
Node(
validator_id=1,
monitoring_gateway_server_port=monitoring_gateway_server_port,
cmd=bootnode_command,
)
)

# Add other validators
nodes.extend(
build_peernode(base_layer_node_url, temp_dir, num_validators, i)
for i in range(2, num_validators)
)
# Ensure validator 0 runs last
nodes.append(build_peernode(base_layer_node_url, temp_dir, num_validators, 0))
nodes = build_all_nodes(base_layer_node_url, temp_dir, num_validators)

# Run validator commands in parallel and manage duration time
print("Running validators...")
run_simulation(nodes, duration, stagnation_threshold)
print(f"Output files were stored in: {temp_dir}")
print("Simulation complete.")


Expand Down

0 comments on commit 9f0ea57

Please sign in to comment.