def calculate_votes_for(self, round): """ Calculate what votes a node should gossip out in the provided round. These are proposals that match the criteria given in 4.1, and that a node has not previously added to its s_i set and broadcast votes for. This function should also update the relevant data structures with the current node's vote. Args: round (int): Round to target. Returns: list of str: Returns a list of proposals to broadcast votes for. """ # Get all proposals with r votes, including sender # proposal is new proposal that has just achieved threshold (m not in Sj) # Pseudocode: then j adds m to its set Sj, signs m using its secret key skj, and multicasts... broadcast_votes_for = [] for m in self.get_proposals_with_threshold(round): if m not in self.s_i: self.s_i.append(m) self.votes[m].add(config.node_id) proposal_sig = util.sign_message(m, config.SECRET_KEYS[config.node_id]) self.signatures[m].append((config.node_id, proposal_sig)) broadcast_votes_for.append(m) return broadcast_votes_for
def calculate_votes_for(self, round): """ Calculate what votes a node should gossip out in the provided round. These are proposals that match the criteria given in 4.1, and that a node has not previously added to its s_i set and broadcast votes for. This function should also update the relevant data structures with the current node's vote. Args: round (int): Round to target. Returns: list of str: Returns a list of proposals to broadcast votes for. """ # Get all proposals with r votes, including sender all_proposals = self.get_proposals_with_threshold(round) proposals_broadcast = [] for prop in all_proposals: if prop not in self.s_i: self.s_i.append(prop) self.votes[prop].add(config.node_id) proposal_sig = util.sign_message(prop, config.SECRET_KEYS[config.node_id]) self.signatures[prop].append([config.node_id, proposal_sig]) proposals_broadcast.append(prop) return proposals_broadcast
def __init__(self, sender): """ A simple PKI based protocol for Byzantine agreement. Args: sender (int): Node ID of sender in peer list. Attributes: s_i (list of tuples of str): represents accepted proposals. votes (map of str to set of int): represents nodes that broadcasted signatures on a message/proposal. signatures (map of str to list of (tuple of int, str)): maps string messages/proposals to accepted signatures; each signature is a tuple of the node ID that signed and string hex signature. sender (int): node ID acting as the protocol sender (see protocol description in notes) curr_round_number (int): last round processed internally by the BA protocol """ # Pseudocode: All players i maintain a set Si (of possible outputs) that starts off as empty self.s_i = [] self.votes = {} # maps proposed messages to sets of node IDs that voted for that message self.signatures = {} # maps proposed messages to list of accepted (node_id, signature) tuples, corresponding to valid votes self.sender = sender self.curr_round_number = -1 # Player s (the sender) receiving (s; m) as input computes and multicasts mpks, and adds m to his set Ss. if config.node_id == sender: string_to_vote_for = str(int(random.random() * 2 ** 256)) # for demo purposes, we'll vote for a random string self.votes[string_to_vote_for] = set([config.node_id]) proposal_sig = util.sign_message(string_to_vote_for, config.SECRET_KEYS[config.node_id]) self.signatures[string_to_vote_for] = [(config.node_id, proposal_sig)] self.run_protocol_loop()
def calculate_votes_for(self, round): """ Calculate what votes a node should gossip out in the provided round. These are proposals that match the criteria given in 4.1, and that a node has not previously added to its s_i set and broadcast votes for. This function should also update the relevant data structures with the current node's vote. Args: round (int): Round to target. Returns: list of str: Returns a list of proposals to broadcast votes for. """ # Get all proposals with r votes, including sender prop_list = [] for each_prop in self.votes.keys(): if each_prop not in self.s_i: if len(self.votes[each_prop]) >= round and len(self.votes[each_prop]) != 0 and (1 in self.votes[each_prop]): prop_list.append(each_prop) self.s_i.append(each_prop) self.votes[each_prop].add(config.node_id) self.signatures[each_prop].append((config.node_id, util.sign_message( each_prop, config.SECRET_KEYS[config.node_id]))) # placeholder for (3.1) # proposal is new proposal that has just achieved threshold (m not in Sj) # Pseudocode: then j adds m to its set Sj, signs m using its secret key skj, and multicasts... return prop_list
def mine(self): """ PoA signer; seals a block with new seal data by signing it, checking that signature is valid, and returning. """ while not self.seal_is_valid(): signature = util.sign_message(self.unsealed_header(), config.AUTHORITY_SK) self.set_seal_data(int(signature, 16))