Skip to content

Commit

Permalink
Merge pull request #49 from karlfloersch/apply-some-pylint
Browse files Browse the repository at this point in the history
lints part 3, line length & docstring
  • Loading branch information
djrtwo committed Oct 14, 2017
2 parents 5cac1e2 + 0de9ed2 commit 57a36ac
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 50 deletions.
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

0 comments on commit 57a36ac

Please sign in to comment.