def validator_rotation(self, slot: int, message: Message): self.checkpoint_rotation_count.setdefault(message.estimate.height, 0) name = Validator.gen_name( message, slot, self.config.checkpoint_interval, self.checkpoint_rotation_count[message.estimate.height]) # NOTE: Now, we assume the oldest validator exit for simplicity oldest_validator = self.network.validator_set.validators[0] self.network.exit(oldest_validator) new_validator = Validator(name, 1.0, self.ticker) self.network.join(new_validator) self.checkpoint_rotation_count[message.estimate.height] += 1
def receive(self, receiver: Validator) -> List[Packet]: to_be_received: List[Packet] = [] packets = self.buffer.read(receiver, self.ticker.current()) for packet in packets: if receiver.message_is_to_be_pending(packet.message): self.buffer.add_packet_to_be_arrived(receiver, self.ticker.current() + 1, packet) else: to_be_received.append(packet) return to_be_received
def validator_rotation(self, validators: List[Validator], name_prefix: str) -> List[Validator]: # NOTE: Now, we assume older validators exit for simplicity of visualization validators: List[Validator] = validators[int(self.validator_num * self.rotation_ratio) + 1:] new_validators: List[Validator] = [] for i in range(self.validator_num - len(validators)): validator = Validator("v{}.{}".format(name_prefix, i), 1.0, self.ticker) # Add genesis message FIXME: Add genesis as default res = validator.add_message(self.validator_set.genesis) assert res.is_ok(), res.value # Do simulation of message arrival from the start for new validator for past_slot in range(self.ticker.current()): past_message = self.broadcast_slot_to_message[past_slot] # Sending in past arrival_slot = past_slot + Delay.get(DELAY_MIN, DELAY_MAX) self.add_message_to_be_arrived(validator, arrival_slot, past_message) # Receiving in past messages = self.arrival_slot_to_messages.get( validator, dict()).get(past_slot, []) for message in messages: res = validator.add_message(message) if not res.is_ok(): # If the message is not valid, skip that for the next round (assuming the reason is reordering) self.add_message_to_be_arrived(validator, past_slot + 1, message) new_validators.append(validator) validators.append(validator) assert len(validators) == self.validator_num self.validator_set.validators += new_validators return validators
def join(self, new_validator: Validator, source_validator: Optional[Validator] = None): assert new_validator not in self.validator_set.validators, "{} already exists".format(new_validator.name) if source_validator is None: source_validator = self.validator_set.validators[0] if new_validator.state.store.genesis is None: res = new_validator.add_message(source_validator.state.store.genesis) assert res.is_ok(), res.value # FIXME: Decide appropriate delay for each message for message in source_validator.state.store.messages.values(): self.send(message, source_validator, new_validator) self.validator_set.validators.append(new_validator)
def with_equal_weight(cls, num, ticker) -> ValidatorSet: validators: List[Validator] = [] for i in range(num): validators.append(Validator("v0.0.{}".format(i), 1.0, ticker)) return ValidatorSet(validators)
def add(self, validator: Validator): self.validators.append(validator) res = validator.add_message(self.genesis) assert res.is_ok(), res.value
def with_random_weight(cls, num, ticker) -> ValidatorSet: validators: List[Validator] = [] for i in range(num): validators.append(Validator("v{}".format(i), r.random(), ticker)) return ValidatorSet(validators)
def test_store(): ticker = Ticker() validator = Validator("v0", 1.0, ticker) genesis = Message.genesis(validator) store = Store() store.add(genesis) b1 = Block(0, genesis.estimate.hash) child = Message(validator, b1, Justification(store.latest_message_hashes()), 0) store.add(child) message_history = {validator: [genesis.hash, child.hash]} assert store.message_history == message_history messages = {genesis.hash: genesis, child.hash: child} assert store.messages == messages children = {genesis.hash: [child.hash]} assert store.children == children parent = {child.hash: genesis.hash} assert store.parent == parent block_to_message_in_hash = { genesis.estimate.hash: genesis.hash, child.estimate.hash: child.hash } assert store.block_to_message_in_hash == block_to_message_in_hash assert store.genesis == genesis assert store.message(child.hash) == child assert store.message(genesis.hash) == genesis assert store.message(000) is None latest_message_hashes = {validator: child.hash} assert store.latest_message_hashes() == latest_message_hashes latest_messages = {validator: child} assert store.latest_messages() == latest_messages assert store.parent_message(child) == genesis assert store.parent_message(genesis) is None assert store.children_messages(child) == [] assert store.children_messages(genesis) == [child] assert store.parent_block(genesis.estimate) is None assert store.parent_block(child.estimate) == genesis.estimate assert store.children_blocks(child.estimate) == [] assert store.children_blocks(genesis.estimate) == [child.estimate] assert store.has_children_blocks(genesis.estimate) assert not store.has_children_blocks(child.estimate) assert store.justified(genesis) assert store.justified(child) assert not store.justified(000) assert store.genesis_block() == genesis.estimate
def add_message_or_pending(self, receiver: Validator, message: Message): res = receiver.add_message(message) if not res.is_ok(): # If the message is not valid, skip that for the next round (assuming the reason is reordering) self.add_message_to_be_arrived(receiver, self.ticker.current() + 1, message)