Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lints part 3, line length & docstring #49

Merged
merged 1 commit into from
Oct 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions casper/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __hash__(self):
return hash(str(self.sequence_number) + str(self.estimate.hash) + str(10000*self.sender))

def is_in_blockchain(self, block):
"""Returns True if self is in block."""
assert isinstance(block, Block), "...expected a block"

if self == block:
Expand Down
2 changes: 2 additions & 0 deletions casper/forkchoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


def get_max_weight_indexes(scores):
"""Returns the max weight estimates."""

max_score = max(scores.values())

Expand All @@ -14,6 +15,7 @@ def get_max_weight_indexes(scores):


def get_fork_choice(last_finalized_block, children, latest_messages):
"""Returns the best block."""

scores = dict()

Expand Down
10 changes: 7 additions & 3 deletions casper/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@


class Network:
"""Simulates a network."""
def __init__(self):
self.validators = dict()
for v in s.VALIDATOR_NAMES:
self.validators[v] = Validator(v)
self.global_view = View()

def propagate_message_to_validator(self, message, validator_name):
assert message in self.global_view.messages, "...expected only to propagate messages from the global view"
"""Propogate a message to a validator."""
assert message in self.global_view.messages, "expected only to propagate messages from the global view"
self.validators[validator_name].receive_messages(set([message]))

def get_message_from_validator(self, validator_name):
assert validator_name in s.VALIDATOR_NAMES, "...expected a known validator"
"""Get a message from a validator."""
assert validator_name in s.VALIDATOR_NAMES, "expected a known validator"

new_message = self.validators[validator_name].make_new_message()
return new_message
Expand All @@ -40,4 +43,5 @@ def random_initialization(self):
self.global_view.add_messages(set([new_bet]))

def report(self, colored_messages=set(), color_mag=dict(), edges=[]):
plot_tool.plot_view(self.global_view, coloured_bets=colored_messages, colour_mag=color_mag, edges=edges)
plot_tool.plot_view(self.global_view, coloured_bets=colored_messages,
colour_mag=color_mag, edges=edges)
8 changes: 5 additions & 3 deletions casper/plot_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@ def plot_view(view, coloured_bets=[], colour_mag=dict(), edges=[]):
node_sizes.append(350*pow(s.WEIGHTS[b.sender]/pi, 0.5))
labels[b] = b.sequence_number

nx.draw_networkx_nodes(G, positions, alpha=0.1, node_color=color_values, nodelist=nodes, node_size=node_sizes, edge_color='black')
nx.draw_networkx_nodes(G, positions, alpha=0.1, node_color=color_values, nodelist=nodes,
node_size=node_sizes, edge_color='black')

for e in edges:
if isinstance(e, dict):
nx.draw_networkx_edges(G, positions, edgelist=(e['edges']), width=e['width'], edge_color=e['edge_color'], style=e['style'], alpha=0.5)
nx.draw_networkx_edges(G, positions, edgelist=(e['edges']), width=e['width'],
edge_color=e['edge_color'], style=e['style'], alpha=0.5)
else:
assert False, e
nx.draw_networkx_labels(G, positions, labels=labels)
Expand Down Expand Up @@ -100,7 +102,7 @@ def make_thumbnails(frame_count_limit=IMAGE_LIMIT, xsize=1000, ysize=1000):
if len(images) == frame_count_limit:
break

size = (1000, 1000)
size = (xsize, ysize)
iterator = 0
for im in images:
im.thumbnail(size, Image.ANTIALIAS)
Expand Down
10 changes: 9 additions & 1 deletion casper/presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ def message_maker(mode):
if mode == "rand":
pairs = list(itertools.permutations(range(s.NUM_VALIDATORS), 2))
def random():
"""Each round, some randomly selected validators propagate their most recent
message to other randomly selected validators, who then create new messages."""
return r.sample(pairs, s.NUM_MESSAGES_PER_ROUND)

return random

if mode == "rrob":
msg = [0, 1]
def round_robin():
"""Each round, the creator of the last round's block sends it to the next
receiver, who then creates a block."""
to_return = [[msg[0], msg[1]]]
msg[0] = (msg[0] + 1) % s.NUM_VALIDATORS
msg[1] = (msg[1] + 1) % s.NUM_VALIDATORS
Expand All @@ -27,14 +31,18 @@ def round_robin():
if mode == "full":
pairs = list(itertools.permutations(range(s.NUM_VALIDATORS), 2))
def full_propagation():
"""Each round, all validators receive all other validators previous
messages, and then all create messages."""
return pairs

return full_propagation

if mode == "nofinal":
# Depending on val weights, this message prop order could never finalize a block.
msg = [0, 1]
def no_final():
"""Each round, two simultaneous round-robin message propagations occur at the same
time. This results in validators never being able to finalize later blocks (they
may finalize initial blocks, depending on validator weight distribution)."""
to_return = [[msg[0], msg[1]]]
msg[0] = (msg[0] + 1) % s.NUM_VALIDATORS
msg[1] = (msg[1] + 1) % s.NUM_VALIDATORS
Expand Down
20 changes: 11 additions & 9 deletions casper/safety_oracles/adversary_models/adversary.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@


class Adversary:
"""Simulates an adversary."""

def __init__(self, victim_estimate, latest_bets, viewables):

# Estimate being attacked
# Estimate being attacked.
self.victim_estimate = victim_estimate

# Estimate adversary is attack towards
# Estimate adversary is attack towards.
self.target_estimate = 1 - victim_estimate

# The attacker adds the bets they created in the attack to this view...
# The attacker adds the bets they created in the attack to this view.
self.attack_view = set()

self.validator_models = dict()
Expand All @@ -28,7 +29,8 @@ def __init__(self, victim_estimate, latest_bets, viewables):
success, new_bet = self.validator_models[v].make_new_latest_bet()

if success:
assert new_bet.estimate == self.target_estimate # sanity check
# Sanity check!
assert new_bet.estimate == self.target_estimate
self.voting_with_attacker.add(v)
else:
self.voting_against_attacker.add(v)
Expand All @@ -40,7 +42,7 @@ def __init__(self, victim_estimate, latest_bets, viewables):
assert len(self.voting_with_attacker) + len(self.voting_against_attacker) == s.NUM_VALIDATORS
assert round(self.weight_of_victim_estimate + self.weight_of_target_estimate, 2) == round(s.TOTAL_WEIGHT, 2)

# The attacker produces a log of the bets added during the attack...
# The attacker produces a log of the bets added during the attack.
self.operations_log = []

def is_attack_complete(self):
Expand All @@ -60,12 +62,12 @@ def ideal_network_attack(self):
# all bets that are on the target_estimate
for v in self.voting_with_attacker:
on_target, bet = self.validator_models[v].make_new_latest_bet()
assert on_target and bet.estimate == self.target_estimate, '...in voting_with_attacker!'
assert on_target and bet.estimate == self.target_estimate, 'in voting_with_attacker!'
for v2 in self.voting_against_attacker:
self.validator_models[v2].show(bet)

# We'll continue the attack until we no longer make progress
# Or until the attack is successful and the victim estimate dethroned
# We'll continue the attack until we no longer make progress,
# or until the attack is successful and the victim estimate dethroned.
progress_made = True
while progress_made:
progress_made = False
Expand Down Expand Up @@ -105,6 +107,6 @@ def ideal_network_attack(self):
self.voting_against_attacker.difference_update(to_remove)

# Sanity check!
assert not self.is_attack_complete(), "...expected attack to be ongoing, at this point"
assert not self.is_attack_complete(), "expected attack to be ongoing, at this point"

return False, self.operations_log, self.attack_view
7 changes: 4 additions & 3 deletions casper/safety_oracles/adversary_models/model_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@


class ModelValidator:
"""Simulates a model validator."""

def __init__(self, validator_name, my_latest_bet, latest_bets, target_estimate):

assert validator_name in s.VALIDATOR_NAMES, "... model dator should be a dator!"
assert validator_name in s.VALIDATOR_NAMES, "model dator should be a dator!"

self.model_of = validator_name

Expand All @@ -26,8 +27,8 @@ def my_estimate(self):
def show(self, bet):
"""This method makes a bet viewable to the model validator."""

assert isinstance(bet, ModelBet), "...expected a bet!"
assert bet.estimate == self.target_estimate, "...should only show bets on the target_estimate!"
assert isinstance(bet, ModelBet), "expected a bet!"
assert bet.estimate == self.target_estimate, "should only show bets on the target_estimate!"

self.latest_observed_bets[bet.sender] = bet

Expand Down
11 changes: 7 additions & 4 deletions casper/safety_oracles/adversary_oracle.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""The adversary oracle module ... """
import casper.settings as s
from casper.adversary_models.model_bet import ModelBet
from casper.adversary_models.adversary import Adversary
from casper.safety_oracles.adversary_models.model_bet import ModelBet
from casper.safety_oracles.adversary_models.adversary import Adversary
import capser.utils as utils


class AdversaryOracle:
"""Simulate an adversary oracle."""

# We say candidate_estimate is 0, other is 1
CAN_ESTIMATE = 0
ADV_ESTIMATE = 1
Expand Down Expand Up @@ -47,8 +49,8 @@ def get_recent_messages_and_viewables(self):
# now construct the messages that they can see from other validators
for v2 in s.VALIDATOR_NAMES:
# if they have seen nothing from some validator, assume the worst
# NOTE: This may not be necessary, might be possible to do a free block check here?
# see issue #44
# NOTE: This may not be necessary, might be possible to do a free
# block check here? see issue #44
if v2 not in self.view.latest_messages[v].justification.latest_messages:
viewables[v][v2] = ModelBet(AdversaryOracle.ADV_ESTIMATE, v2)
continue
Expand All @@ -66,6 +68,7 @@ def get_recent_messages_and_viewables(self):


def check_estimate_safety(self):
"""Check the safety of the estimate."""

recent_messages, viewables = self.get_recent_messages_and_viewables()

Expand Down
28 changes: 16 additions & 12 deletions casper/safety_oracles/clique_oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class CliqueOracle:

"""Simulates a clique oracle."""
def __init__(self, candidate_estimate, view):
if candidate_estimate is None:
raise Exception("cannot decide if safe without an estimate")
Expand All @@ -23,19 +23,20 @@ def __init__(self, candidate_estimate, view):
# NOTE: if biggest clique can easily be determined to be < 50% by weight, will
# return with empty set and 0 weight.
def find_biggest_clique(self):
"""Finds the biggest clique."""

# only consider validators whose messages are compatable w/ candidate_estimate
# Only consider validators whose messages are compatable w/ candidate_estimate.
with_candidate = {v for v in s.VALIDATOR_NAMES if v in self.view.latest_messages and \
not utils.are_conflicting_estimates(self.candidate_estimate, self.view.latest_messages[v])}

# do not have safety if less than half have candidate_estimate
# Do not have safety if less than half have candidate_estimate.
if utils.get_weight(with_candidate) < s.TOTAL_WEIGHT / 2:
return set(), 0

edges = []
#for each pair of validators, v, w, add an edge if...
# For each pair of validators, v, w, add an edge if...
for v, w in itertools.combinations(with_candidate, 2):
# the latest message v has seen from w is on the candidate estimate
# ... the latest message v has seen from w is on the candidate estimate ...
v_msg = self.view.latest_messages[v]
if w not in v_msg.justification.latest_messages:
continue
Expand All @@ -44,7 +45,7 @@ def find_biggest_clique(self):
if utils.are_conflicting_estimates(self.candidate_estimate, w_msg_in_v_view):
continue

# the latest block w has seen from v is on the candidate estimate
# ... the latest block w has seen from v is on the candidate estimate ...
w_msg = self.view.latest_messages[w]
if v not in w_msg.justification.latest_messages:
continue
Expand All @@ -53,11 +54,11 @@ def find_biggest_clique(self):
if utils.are_conflicting_estimates(self.candidate_estimate, v_msg_in_w_view):
continue

# there are no blocks from w, that v has not seen, that might change v's estimate
# ... there are no blocks from w, that v has not seen, that might change v's estimate ...
if utils.exists_free_message(self.candidate_estimate, w, w_msg_in_v_view.sequence_number, self.view):
continue

# there are no blocks from v, that w has not seen, that might change w's estimate
# ... and if there are no blocks from v, that w has not seen, that might change w's estimate.
if utils.exists_free_message(self.candidate_estimate, v, v_msg_in_w_view.sequence_number, self.view):
continue

Expand All @@ -84,18 +85,21 @@ def check_estimate_safety(self):

biggest_clique, clique_weight = self.find_biggest_clique()

# minumum amount of weight that has to equivocate
# Minumum amount of weight that has to equivocate.
fault_tolerance = 2 * clique_weight - s.TOTAL_WEIGHT

if fault_tolerance > 0:
clique_weights = {s.WEIGHTS[v] for v in biggest_clique}

# minimum number of validators that need to equivocate
# Minimum number of validators that need to equivocate.
equivocating = set()
while round(sum(equivocating), 2) < round(fault_tolerance, 2): # round to stop issues w/ floating point rounding

# Round to stop issues w/ floating point rounding.
while round(sum(equivocating), 2) < round(fault_tolerance, 2):
equivocating.add(max(clique_weights.difference(equivocating)))

# return the number of faults we can tolerate, which is one less than the number that need to equivocate.
# Return the number of faults we can tolerate, which is one less
# than the number that need to equivocate.
return fault_tolerance, len(equivocating) - 1
else:
return 0, 0
8 changes: 6 additions & 2 deletions casper/settings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
"""The settings module ... """
import random as r # to ensure the tie-breaking property

# Used to ensure the tie-breaking property.
import random as r


def init():
"""Initialize all the default settings."""
r.seed()

# Declare our global variables.
Expand Down Expand Up @@ -32,7 +35,7 @@ def init():
# It's a bit underwhelming, sure, but it's foundational.
ESTIMATE_SPACE = set([0, 1])

# Here are the weights ...!
# Here are the weights!
WEIGHTS = {i: max(20, r.gauss(mu=60, sigma=40)) + 1.0/(BIGINT + r.uniform(0, 1)) + r.random() for i in VALIDATOR_NAMES}

TOTAL_WEIGHT = sum(WEIGHTS.values())
Expand All @@ -45,6 +48,7 @@ def init():


def update(val_weights):
"""Update the global settings given new validator weights."""
global NUM_VALIDATORS
global VALIDATOR_NAMES
global WEIGHTS
Expand Down
Loading