def on_receive(self, obj, reprocess=False): if obj.hash in self.processed and not reprocess: return if random.random() > self.reliability: return self.processed[obj.hash] = True self.log("Processing %s %s" % ("block" if isinstance(obj, BeaconBlock) else "sig", to_hex(obj.hash[:4])), lvl=1) if isinstance(obj, BeaconBlock): return self.on_receive_beacon_block(obj) elif isinstance(obj, MainChainBlock): return self.on_receive_main_block(obj) elif isinstance(obj, ShardCollation): return self.on_receive_shard_collation(obj) elif isinstance(obj, Sig): return self.on_receive_sig(obj) elif isinstance(obj, BlockMakingRequest): if self.beacon_chain[-1] == obj.parent: mc_ref = self.blocks[obj.parent] for i in range(2): if mc_ref.number == 0: break #mc_ref = self.blocks[mc_ref].parent_hash x = BeaconBlock( self.blocks[obj.parent], self.id, self.ts, self.sigs[obj.parent] if obj.parent in self.sigs else [], self.blocks[self.main_chain[-1]], self.nb_notaries, self.nb_shards) self.log("Broadcasting block %s" % to_hex(x.hash[:4]), lvl=1) self.broadcast(x) self.on_receive(x)
def on_receive_main_block(self, block): # Parent not yet received if block.parent_hash not in self.blocks: self.add_to_multiset(self.parentqueue, block.parent_hash, block) return None self.log("Processing main chain block %s" % to_hex(block.hash[:4]), lvl=1) self.blocks[block.hash] = block # Reorg the main chain if new head if block.number > self.blocks[self.main_chain[-1]].number: reorging = (block.parent_hash != self.main_chain[-1]) self.change_head(self.main_chain, block) if reorging: self.recalculate_head( self.beacon_chain, lambda b: isinstance(b, BeaconBlock) and b.main_chain_ref in self.main_chain) for i in range(self.nb_shards): self.recalculate_head( self.shard_chains[i], lambda b: isinstance(b, ShardCollation) and b.shard_id == i and b.beacon_ref in self.beacon_chain) # Add child record self.add_to_multiset(self.children, block.parent_hash, block.hash) # Final steps self.process_children(block.hash) self.broadcast(block)
def broadcast(self, obj): self.log("Broadcasting %s %s" % ("block" if isinstance(obj, BeaconBlock) else "sig", to_hex(obj.hash[:4])), lvl=3) #self.network.broadcast(self, x) for p in self.network.peers[self.id]: recv_time = self.network.time + self.network.latency_distribution_sample( ) if recv_time not in self.network.objqueue: self.network.objqueue[recv_time] = [] self.network.objqueue[recv_time].append((p, obj))
def send(self, p, obj): #global commChannel #msg = [self.id, p.id, obj] #commChannel.append(msg) if isinstance(obj, BeaconBlock): object_type = "Beacon block" elif isinstance(obj, MainChainBlock): object_type = "Main chain block" elif isinstance(obj, ShardCollation): object_type = "Shard Collation" elif isinstance(obj, Sig): object_type = "Signature" elif isinstance(obj, BlockMakingRequest): object_type = "Block request" #print str(obj) req = self.comm.isend(obj, dest=p, tag=self.tag) self.log("%s %s sent from %d to %d" % (object_type, to_hex(obj.hash[:4]), self.id, p)) return req
def on_receive_beacon_block(self, block): # Parent not yet received if block.parent_hash not in self.blocks: self.add_to_multiset(self.parentqueue, block.parent_hash, block) return # Main chain parent not yet received if block.main_chain_ref not in self.blocks: self.add_to_multiset(self.parentqueue, block.main_chain_ref, block) return # Too early if block.ts > self.ts: self.add_to_timequeue(block) return # Check consistency of cross-link reference assert self.is_descendant( self.blocks[block.parent_hash].main_chain_ref, block.main_chain_ref) # Add the block self.log("Processing beacon block %s" % to_hex(block.hash[:4]), lvl=1) self.blocks[block.hash] = block # Am I a notary, and is the block building on the head? Then broadcast a signature. if block.parent_hash == self.beacon_chain[-1] or self.careless: if self.id in block.notaries: self.broadcast(Sig(self.id, block)) self.on_receive(Sig(self.id, block)) # Check for sigs, add to head?, make a block? if len(self.sigs.get(block.hash, [])) >= block.notary_req: if block.number > self.blocks[self.beacon_chain[ -1]].number and block.main_chain_ref in self.main_chain: self.change_beacon_head(block) if self.id in self.blocks[block.hash].child_proposers: my_index = self.blocks[block.hash].child_proposers.index( self.id) target_ts = block.ts + self.base_ts_diff + my_index * self.skip_ts_diff self.add_to_timequeue(BlockMakingRequest( block.hash, target_ts)) # Add child record self.add_to_multiset(self.children, block.parent_hash, block.hash) # Final steps self.process_children(block.hash) self.broadcast(block)
def on_receive_shard_collation(self, block): # Parent not yet received if block.parent_hash not in self.blocks: self.add_to_multiset(self.parentqueue, block.parent_hash, block) return None # Beacon ref not yet received if block.beacon_ref not in self.blocks: self.add_to_multiset(self.parentqueue, block.beacon_ref, block) return None # Check consistency of cross-link reference assert self.is_descendant(self.blocks[block.parent_hash].beacon_ref, block.beacon_ref) self.log("Processing shard collation %s" % to_hex(block.hash[:4])) self.blocks[block.hash] = block # Set head if needed if block.number > self.blocks[self.shard_chains[block.shard_id][-1]].number and block.beacon_ref in self.beacon_chain: self.change_head(self.shard_chains[block.shard_id], block) # Add child record self.add_to_multiset(self.children, block.parent_hash, block.hash) # Final steps self.process_children(block.hash) self.broadcast(block)
def print_sig_digest(self): for sig_hash in self.sigs: print("%s : %s" % (to_hex(sig_hash[:4]), str(len(self.sigs[sig_hash]))))
def print_chain_digest(self): for block_hash in self.blocks: print("%s : %s" % (to_hex(block_hash[:4]), str(self.blocks[block_hash])))
def add_to_multiset(self, set, k, v): if k not in set: set[k] = [] set[k].append(v) self.log("Adding %s to multiset" % to_hex(k[:4]))
def __str__(self): sti = " <MB Number : " + str(self.number) sti += ", hash : " + to_hex(self.hash[:4]) sti += ", parent : " + to_hex(self.parent_hash[:4]) + "> " return sti