def validate_identifier(self): validate_not_empty(f'{self.humanized_class_name} identifier', self.identifier) validate_type(f'{self.humanized_class_name} identifier', self.identifier, str) validate_hexadecimal(f'{self.humanized_class_name} identifier', self.identifier)
def validate_timestamp(self, blockchain): timestamp = self.timestamp validate_not_none(f'{self.humanized_class_name} timestamp', timestamp) validate_type(f'{self.humanized_class_name} timestamp', timestamp, datetime) validate_is_none(f'{self.humanized_class_name} timestamp timezone', timestamp.tzinfo) block_number = self.block_number assert block_number is not None if block_number > 0: prev_block_number = block_number - 1 prev_block = blockchain.get_block_by_number(prev_block_number) if prev_block is None: logger.debug('Partial blockchain detected') blockchain_state = blockchain.get_closest_blockchain_state_snapshot( block_number) validate_not_none('Closest blockchain state', blockchain_state) if blockchain_state.is_initial(): raise ValidationError( 'Unexpected initial account root file found') validate_exact_value('Blockchain state last block number', blockchain_state.last_block_number, prev_block_number) assert blockchain_state.last_block_timestamp min_timestamp = blockchain_state.last_block_timestamp else: min_timestamp = prev_block.message.timestamp validate_gt_value(f'{self.humanized_class_name} timestamp', timestamp, min_timestamp)
def validate_fee_amount(self): validate_not_none(f'{self.humanized_class_name} fee_amount', self.fee_amount) validate_type(f'{self.humanized_class_name} fee_amount', self.fee_amount, int) validate_gte_value(f'{self.humanized_class_name} fee_amount', self.fee_amount, 0)
def deserialize_from_dict(cls, dict_, complain_excessive_keys=True, exclude=()): dict_ = dict_.copy() message_dict = dict_.pop('message', None) validate_not_none(f'{cls.humanized_class_name} message', message_dict) validate_type(f'{cls.humanized_class_name} message', message_dict, dict) signed_change_request_dict = message_dict.get('signed_change_request') validate_not_none(f'{cls.humanized_class_name} message.signed_change_request', signed_change_request_dict) validate_type(f'{cls.humanized_class_name} message.signed_change_request', signed_change_request_dict, dict) instance_block_type = message_dict.get('block_type') validate_not_none(f'{cls.humanized_class_name} message.block_type', instance_block_type) validate_in( f'{cls.humanized_class_name} message.block_type', instance_block_type, SIGNED_CHANGE_REQUEST_TYPE_MAP ) signed_change_request_class = SIGNED_CHANGE_REQUEST_TYPE_MAP[instance_block_type] signed_change_request_obj = signed_change_request_class.deserialize_from_dict(signed_change_request_dict) message_obj = BlockMessage.deserialize_from_dict( message_dict, override={'signed_change_request': signed_change_request_obj} ) return super().deserialize_from_dict( dict_, complain_excessive_keys=complain_excessive_keys, override={'message': message_obj} )
def validate_next_block_identifier(self, is_initial): if is_initial: validate_is_none( f'Initial {self.humanized_class_name} next_block_identifier', self.next_block_identifier) else: validate_type(f'{self.humanized_class_name} next_block_identifier', self.next_block_identifier, str)
def validate_block_number(self): block_number = self.block_number validate_not_none(f'{self.humanized_class_name} block_number', block_number) validate_type(f'{self.humanized_class_name} block_number', block_number, int) validate_gte_value(f'{self.humanized_class_name} block_number', block_number, 0)
def validate_transactions(self): txs = self.txs validate_type(f'{self.humanized_class_name} txs', txs, list) validate_not_empty(f'{self.humanized_class_name} txs', txs) for tx in self.txs: with validates(f'Validating transaction {tx} on {self.get_humanized_class_name(False)} level'): validate_type(f'{self.humanized_class_name} txs', tx, CoinTransferTransaction) tx.validate()
def validate_last_block_number(self, is_initial): if is_initial: validate_is_none( f'Initial {self.humanized_class_name} last_block_number', self.last_block_number) else: validate_type(f'{self.humanized_class_name} last_block_number', self.last_block_number, int) validate_gte_value( f'{self.humanized_class_name} last_block_number', self.last_block_number, 0)
def validate_block_identifier(self, blockchain): block_identifier = self.block_identifier validate_not_none(f'{self.humanized_class_name} block_identifier', block_identifier) validate_type(f'{self.humanized_class_name} block_identifier', block_identifier, str) block_number = self.block_number assert block_number is not None expected_identifier = blockchain.get_expected_block_identifier( block_number) validate_exact_value(f'{self.humanized_class_name} block_identifier', block_identifier, expected_identifier)
def validate_last_block_timestamp(self, is_initial): timestamp = self.last_block_timestamp if is_initial: validate_is_none( f'Initial {self.humanized_class_name} last_block_timestamp', timestamp) else: validate_not_none( f'{self.humanized_class_name} last_block_timestamp', timestamp) validate_type(f'{self.humanized_class_name} last_block_timestamp', timestamp, datetime) validate_is_none( f'{self.humanized_class_name} last_block_timestamp timezone', timestamp.tzinfo)
def validate(self): amount = self.amount validate_not_empty(f'{self.humanized_class_name} recipient', self.recipient) validate_type(f'{self.humanized_class_name} amount', amount, int) validate_gte_value(f'{self.humanized_class_name} amount', amount, 1) validate_in(f'{self.humanized_class_name} is_fee', self.is_fee, (True, False, None)) with validates('memo'): max_len = settings.MEMO_MAX_LENGTH if self.memo and len(self.memo) > max_len: raise ValidationError( f'{self.humanized_class_name} memo must be less than {max_len} characters' )
def validate_updated_account_balance_lock(self, *, account_number, account_state, is_sender=False): subject = ( f'{self.humanized_class_name_lowered} {"sender" if is_sender else "recipient"} account ' f'{account_number} balance_lock') balance_lock = account_state.balance_lock if is_sender: validate_not_empty(subject, balance_lock) validate_type(subject, balance_lock, str) from ..algorithms.updated_account_states.coin_transfer import make_balance_lock validate_exact_value(subject, balance_lock, make_balance_lock(self.signed_change_request)) else: validate_empty(subject, balance_lock)
def validate_updated_account_states(self, blockchain): updated_account_states = self.updated_account_states humanized_class_name = self.humanized_class_name_lowered validate_not_empty(f'{humanized_class_name} updated_account_states', updated_account_states) from .signed_change_request import CoinTransferSignedChangeRequest if isinstance(self.signed_change_request, CoinTransferSignedChangeRequest): validate_min_item_count( f'{humanized_class_name} updated_account_states', updated_account_states, 2) signer = self.signed_change_request.signer sender_account_state = self.updated_account_states.get(signer) validate_not_empty( f'{humanized_class_name} updated_account_states.{signer}', sender_account_state) for account_number, account_state in updated_account_states.items( ): with validates( f'{humanized_class_name} account {account_number} updated state' ): account_subject = f'{humanized_class_name} updated_account_states key (account number)' validate_not_empty(account_subject, account_number) validate_type(account_subject, account_number, str) account_state.validate() is_sender = account_number == signer self.validate_updated_account_balance_lock( account_number=account_number, account_state=account_state, is_sender=is_sender) self.validate_updated_account_balance( account_number=account_number, account_state=account_state, blockchain=blockchain, is_sender=is_sender)
def validate_balance(self): validate_type(f'{self.humanized_class_name_lowered} balance', self.balance, int) validate_min_value(f'{self.humanized_class_name_lowered} balance', self.balance, 0)
def validate_fee_account(self): if self.fee_account is not None: validate_type(f'{self.humanized_class_name} fee_account', self.fee_account, str) validate_hexadecimal(f'{self.humanized_class_name} fee_account', self.fee_account)
def validate_signer(self): signer = self.signer validate_not_empty('Signer', signer) validate_type('Signer', signer, str) return signer
def validate_signature(self): verify_key = self.validate_signer() signature = self.signature validate_not_empty('Signature', signature) validate_type('Signature', signature, str) self.message.validate_signature(verify_key, self.signature)
def validate_accounts(self): for account, balance in self.account_states.items(): with validates(f'blockchain state account {account}'): validate_type(f'{self.humanized_class_name} account', account, str) balance.validate()
def validate_balance_lock(self): validate_not_empty(f'{self.humanized_class_name_lowered} balance_lock', self.balance_lock) validate_type(f'{self.humanized_class_name_lowered} balance_lock', self.balance_lock, str)