def enter_any(self, prev_state): time.sleep(10) self.log.notice("Delegate connecting to other nodes ..") # Sub to other delegates for delegate_vk in VKBook.get_delegates(): # Do not sub to ourself if delegate_vk == self.parent.verifying_key: continue self.parent.composer.add_sub(vk=delegate_vk, filter=delegate_delegate) # Sub to witnesses for witness_vk in VKBook.get_witnesses(): self.parent.composer.add_sub(vk=witness_vk, filter=witness_delegate) # Pub on our own url self.parent.composer.add_pub(ip=self.parent.ip) # Add router socket self.parent.composer.add_router(ip=self.parent.ip) # Add dealer and sub socket for Masternodes for mn_vk in VKBook.get_masternodes(): self.parent.composer.add_dealer(vk=mn_vk) self.parent.composer.add_sub(vk=mn_vk, filter=masternode_delegate) # Sleep for a bit while the daemon sets up these sockets TODO find a more reactive solution time.sleep(20) # Once done with boot state, transition to catchup self.parent.transition(DelegateCatchupState)
def discover_network(self): self.ips = self.loop.run_until_complete(self.discover(self.mode)) if len(self.ips) == 0: self.ips[self.host_ip] = int(time.time()) mn_list = VKBook.get_masternodes() ip_list = list(self.ips.keys()) if self.network.ironhouse.vk not in mn_list: if len(ip_list) == 1: return False return True
def _fetch_tx_for_current_block(self): """ Fetches the transactions for the current block being updated """ assert self.current_block, "_fetch_tx_for_current_block called but self.current_block not set!" request = TransactionRequest.create(self.current_block.merkle_leaves) self.parent.composer.send_request_msg(message=request, vk=VKBook.get_masternodes()[0]) self.current_request = request
def validate_sig(self, sig: MerkleSignature) -> bool: assert self.merkle is not None, "Cannot validate signature without our merkle set" self.log.debugv("Validating signature: {}".format(sig)) # Verify sender's vk exists in the state if sig.sender not in VKBook.get_delegates(): self.log.warning("Received merkle sig from sender {} who was not registered nodes {}" .format(sig.sender, VKBook.get_delegates())) return False # Verify we haven't received this signature already if sig in self.signatures: self.log.warning("Already received a signature from sender {}".format(sig.sender)) return False # Below is just for debugging, so we can see if a signature cannot be verified if not sig.verify(self.merkle.root): self.log.warning("Delegate could not verify signature! Different Merkle trees.\nSig: {}".format(sig)) return sig.verify(self.merkle.root)
def enter(self, prev_state): # Sub to Masternodes for mn_vk in VKBook.get_masternodes(): self.log.debug("Subscribes to MN with vk: {}".format(mn_vk)) self.parent.composer.add_sub(filter=WITNESS_MASTERNODE_FILTER, vk=mn_vk, port=MN_TX_PUB_PORT) # Create publisher socket self.parent.composer.add_pub(ip=self.parent.ip) # Once done setting up sockets, transition to RunState self.parent.transition(WitnessRunState)
def _check_ready(self): """ Checks if the system is 'ready' (as described in the MNStagingState docstring). If all conditions are met, this function will transition to MNRunState. """ # TODO for dev we require all delegates online. IRL a 2/3 majority should suffice # majority = VKBook.get_delegate_majority() majority = len(VKBook.get_delegates()) num_ready = len(self.ready_delegates) if num_ready >= majority: self.log.important( "{}/{} Delegates are at the latest blockchain state! MN exiting StagingState." "\n(Ready Delegates = {})".format(num_ready, len(VKBook.get_delegates()), self.ready_delegates)) self.parent.transition(MNRunState) return else: self.log.notice( "Only {} of {} required delegate majority ready. MN remaining in StagingState" .format(num_ready, majority))
def enter_any(self, prev_state): # Add publisher socket for sending NewBlockNotifications to delegates self.parent.composer.add_pub(ip=self.parent.ip, port=MN_NEW_BLOCK_PUB_PORT) # Add router socket self.parent.composer.add_router(ip=self.parent.ip) # Add dealer sockets to TESTNET_DELEGATES, for purposes of requesting block data for vk in VKBook.get_delegates(): self.parent.composer.add_dealer(vk=vk) # Once done booting, transition to staging self.parent.transition(MNStagingState)
def check_majority(self): self.log.debug("delegate has {} signatures out of {} total TESTNET_DELEGATES" .format(len(self.signatures), self.NUM_DELEGATES)) if len(self.signatures) >= MAJORITY and not self.in_consensus: self.log.important("Delegate in consensus!") self.in_consensus = True # Create BlockContender and send it to all Masternode(s) bc = BlockContender.create(signatures=self.signatures, merkle_leaves=self.merkle.leaves_as_hex, prev_block_hash=self.parent.current_hash) for mn_vk in VKBook.get_masternodes(): self.log.debug("Delegate sending block contender to masternode with VK {}".format(mn_vk)) self.parent.composer.send_request_msg(message=bc, vk=mn_vk)
def _request_update(self): """ Makes a BlockMetaDataRequest to a Masternode. This gives the delegate the block meta data for all new blocks that this delegate needs to fetch """ self.parent.current_hash = BlockStorageDriver.get_latest_block_hash() self.log.notice( "Requesting updates from Masternode with current block hash {}". format(self.parent.current_hash)) request = BlockMetaDataRequest.create( current_block_hash=self.parent.current_hash) self.parent.composer.send_request_msg(message=request, vk=VKBook.get_masternodes()[0], timeout=BLOCK_REQ_TIMEOUT)
def enter_any(self, prev_state): self.log.debug("MN IP: {}".format(self.parent.ip)) # Add publisher socket self.parent.composer.add_pub(ip=self.parent.ip) # Add router socket self.parent.composer.add_router(ip=self.parent.ip) # Add dealer sockets to delegates, for purposes of requesting block data for vk in VKBook.get_delegates(): self.parent.composer.add_dealer(vk=vk) # Once done booting, transition to run self.parent.transition(MNRunState)
def check_majority(self): self.log.debug( "delegate has {} signatures out of {} total delegates".format( len(self.signatures), self.NUM_DELEGATES)) if len(self.signatures) >= majority: self.log.important("Delegate in consensus!") self.in_consensus = True # DEBUG LINE -- todo remove later # self.log.notice("Delegate creating contender with merk leaves {}".format(self.merkle.leaves_as_hex)) # Create BlockContender and send it to all Masternode(s) bc = BlockContender.create(signatures=self.signatures, merkle_leaves=self.merkle.leaves_as_hex) for mn_vk in VKBook.get_masternodes(): self.parent.composer.send_request_msg(message=bc, vk=mn_vk)
async def coro(): node = None if vk in VKBook.get_all(): try: node, cached = await asyncio.wait_for( cls.dht.network.lookup_ip(vk), timeout) except: log.notice('Did not find an ip for VK {}'.format(vk)) if node: cls.event_sock.send_json({ 'event': 'got_ip', 'event_id': event_id, 'public_key': node.public_key.decode(), 'ip': node.ip, 'vk': vk }) else: cls.event_sock.send_json({ 'event': 'not_found', 'event_id': event_id })
def handle_blockmeta_request(self, request: BlockMetaDataRequest, envelope: Envelope): vk = envelope.seal.verifying_key assert vk in VKBook.get_delegates( ), "Got BlockMetaDataRequest from VK {} not in delegate VKBook!".format( vk) self.log.notice( "Masternode received BlockMetaDataRequest from delegate {}\n...request={}" .format(vk, request)) # Get a list of block hashes up until this most recent block # TODO get_child_block_hashes return an error/assertion/something if block cannot be found child_hashes = BlockStorageDriver.get_child_block_hashes( request.current_block_hash) self.log.debugv( "Got descendant block hashes {} for block hash {}".format( child_hashes, request.current_block_hash)) # If this hash could not be found or if it was the latest hash, no need to lookup any blocks if not child_hashes: self.log.debug( "Requested block hash {} is already up to date".format( request.current_block_hash)) reply = BlockMetaDataReply.create(block_metas=None) return reply # Build a BlockMetaData object for each descendant block block_metas = [] for block_hash in child_hashes: block_data = BlockStorageDriver.get_block(hash=block_hash, include_number=False) meta = BlockMetaData.create(**block_data) block_metas.append(meta) reply = BlockMetaDataReply.create(block_metas=block_metas) return reply
def auth_validate(vk): return vk in VKBook.get_all()
def validate(self): assert self.masternode_vk in VKBook.get_masternodes(), 'Not a masternode VK'