def get_updated_account_states_for_coin_transfer( signed_change_request: CoinTransferSignedChangeRequest, blockchain: BlockchainBase) -> dict[str, AccountState]: updated_account_states: dict[str, AccountState] = {} sent_amount = 0 for transaction in signed_change_request.message.txs: recipient = transaction.recipient amount = transaction.amount account_state = updated_account_states.get(recipient) if account_state is None: account_state = AccountState( balance=blockchain.get_account_current_balance(recipient)) updated_account_states[recipient] = account_state assert account_state.balance is not None account_state.balance += amount sent_amount += amount assert sent_amount > 0 coin_sender = signed_change_request.signer sender_balance = blockchain.get_account_current_balance(coin_sender) assert sender_balance > 0 assert sender_balance >= sent_amount updated_account_states[coin_sender] = AccountState( balance=sender_balance - sent_amount, balance_lock=make_balance_lock(signed_change_request)) return updated_account_states
def yield_forced_blockchain(class_, class_kwargs=None): blockchain_settings = {'class': class_, 'kwargs': class_kwargs or {}} BlockchainBase.clear_instance_cache() with override_settings(BLOCKCHAIN=blockchain_settings): blockchain = BlockchainBase.get_instance() yield blockchain BlockchainBase.clear_instance_cache()
def retrieve(self, request, pk=None): # TODO(dmu) MEDIUM: There is a room for performance optimization use something like `?fields=` to # retrieval of unneeded fields using get_account_balance() and get_account_balance_lock() directly. # Also see `drf-flex-fields` and `django-restql`. assert pk is not None blockchain = BlockchainBase.get_instance() serializer = AccountBalanceSerializer(blockchain.get_account_state(pk)) return Response(serializer.data)
def test_make_blockchain_state_from_account_root_file( sample_account_root_file_dict): BlockchainBase.clear_instance_cache() with tempfile.NamedTemporaryFile('w') as fp: json.dump(sample_account_root_file_dict, fp) fp.flush() make_blockchain_state_from_account_root_file(fp.name) blockchain = BlockchainBase.get_instance() blockchain_state = blockchain.get_last_blockchain_state() for key, value in sample_account_root_file_dict.items(): account_state = blockchain_state.get_account_state(key) assert account_state.balance == value['balance'] assert account_state.get_balance_lock(key) == value['balance_lock'] if value['balance_lock'] == key: assert account_state.balance_lock is None assert account_state.node is None
def handle(self, *args, **options): blockchain = BlockchainBase.get_instance() if blockchain.is_empty(): blockchain_genesis_state_source = options[ 'blockchain_genesis_state_source'] logger.info('Empty blockchain detected: initializing with %s', blockchain_genesis_state_source) initialize_blockchain( blockchain_genesis_state_source, failover_source=options[ 'failover_blockchain_genesis_state_source'])
def large_blockchain(treasury_account_key_pair): blockchain = BlockchainBase.get_instance() accounts = blockchain.get_first_blockchain_state().account_states assert len(accounts) == 1 treasury_account, account_state = list(accounts.items())[0] assert treasury_account_key_pair.public == treasury_account assert account_state.balance > 10000000000 # tons of money present add_blocks_to_blockchain(blockchain, 100, treasury_account_key_pair.private) yield blockchain
def get_latest_blockchain_state_meta_by_node_identifier( self, blockchain: BlockchainBase, node_identifier: hexstr) -> Optional[dict]: node = blockchain.get_node_by_identifier(node_identifier) if node is None: return None network_addresses = node.network_addresses if not network_addresses: return None return self.get_latest_blockchain_state_meta_by_network_addresses( network_addresses)
def handle(self, *args, **options): blockchain = BlockchainBase.get_instance() if not blockchain.is_empty() and options['force']: logger.info('Clearing existing blockchain') blockchain.clear() if not blockchain.is_empty(): logger.info('Blockchain is already initialized') return sources = options['sources'] has_added = add_blockchain_state_from_sources(blockchain, sources) if not has_added: logger.error('Was unable to get blockchain source from %s', sources)
def retrieve(self, request, pk: str = None): assert pk is not None blockchain = BlockchainBase.get_instance() node_id = hexstr(pk.lower()) if node_id == PRIMARY_VALIDATOR_NODE_ID: node = blockchain.get_primary_validator() elif node_id == SELF_NODE_ID: node = blockchain.get_node_by_identifier( identifier=get_node_identifier()) else: node = blockchain.get_node_by_identifier(identifier=node_id) if node is None: raise NotFound(detail='Node not found') serializer = self.serializer_class(node) return Response(serializer.data)
def test_can_force_memory_blockchain(): assert isinstance(BlockchainBase.get_instance(), MemoryBlockchain)
def write_default_blockchain(blockchain_state): blockchain = BlockchainBase.get_instance() blockchain.add_blockchain_state(blockchain_state)
def generate_blockchain(blockchain: BlockchainBase, size, add_blockchain_genesis_state=True, validate=True, treasury_account_key_pair=None): treasury_account_key_pair = treasury_account_key_pair or generate_key_pair( ) treasury_account = treasury_account_key_pair.public logger.info('Using treasury account: %s', treasury_account_key_pair) if add_blockchain_genesis_state and blockchain.get_blockchain_states_count( ) == 0: blockchain_genesis_state = BlockchainState( account_states={ treasury_account: AccountState(balance=281474976710656, balance_lock=treasury_account) }) blockchain.add_blockchain_state(blockchain_genesis_state) primary_validator = PrimaryValidator(identifier=get_node_identifier(), fee_amount=4, network_addresses=[]) pv_fee = primary_validator.fee_amount preferred_node = RegularNode(identifier=generate_key_pair().public, fee_amount=1, network_addresses=[]) node_fee = preferred_node.fee_amount balances = get_initial_balances(blockchain) accounts = list(balances) assert len(balances) == 1 assert treasury_account in balances assert balances[treasury_account] >= MAX_AMOUNT account_private_keys = { treasury_account: treasury_account_key_pair.private } sender_candidates = {treasury_account} min_sender_amount = MAX_AMOUNT + pv_fee + node_fee for _ in tqdm(range(size)): amount = random.randint(1, MAX_AMOUNT) # TODO(dmu) MEDIUM: Improve performance at tuple(sender_candidates) sender = random.choice(tuple(sender_candidates)) sender_private_key = account_private_keys[sender] recipient, recipient_private_key = pick_recipient(accounts, exclude=(sender, )) if recipient_private_key: # We got new recipient accounts.append(recipient) account_private_keys[recipient] = recipient_private_key signed_change_request = CoinTransferSignedChangeRequest.from_main_transaction( blockchain=blockchain, recipient=recipient, amount=amount, signing_key=sender_private_key, primary_validator=primary_validator, node=preferred_node) sender_new_balance = balances[sender] - (amount + pv_fee + node_fee) balances[sender] = sender_new_balance if sender_new_balance < min_sender_amount: sender_candidates.discard(sender) recipient_new_balance = balances.get(recipient, 0) + amount balances[recipient] = recipient_new_balance if recipient_new_balance >= min_sender_amount: sender_candidates.add(recipient) blockchain.add_block_from_signed_change_request(signed_change_request, validate=validate)
def blockchain_base(blockchain_genesis_state): blockchain = BlockchainBase() with patch.object(blockchain, 'yield_blockchain_states', get_generator([blockchain_genesis_state])): yield blockchain
def handle(self, *args, **options): BlockchainBase.get_instance().clear()
def handle(self, *args, **options): BlockchainBase.get_instance() raise NotImplementedError( 'Blockchain has nodes workflow is not implemented yet')