def test_generate_block(): signing_key, account_number = create_account() encoded_account_number = encode_verify_key(verify_key=account_number) transactions = [ { 'amount': 1, 'recipient': random_encoded_account_number(), }, { 'amount': 1, 'recipient': random_encoded_account_number(), }, { 'amount': 5, 'recipient': random_encoded_account_number(), } ] block = generate_block( account_number=account_number, balance_lock=encoded_account_number, signing_key=signing_key, transactions=transactions ) assert block['account_number'] == encoded_account_number assert block['message']['balance_key'] == encoded_account_number assert len(block['message']['txs']) == 3 assert len(block['signature']) == SIGNATURE_LENGTH
def send_signed_block(*, block, ip_address, port, protocol, url_path): """ Sign block and send to recipient """ network_signing_key = get_environment_variable('NETWORK_SIGNING_KEY') signing_key = SigningKey(network_signing_key, encoder=HexEncoder) node_identifier = get_verify_key(signing_key=signing_key) node_identifier = encode_verify_key(verify_key=node_identifier) message = sort_and_encode(block) signed_block = { 'block': block, 'node_identifier': node_identifier, 'signature': generate_signature(message=message, signing_key=signing_key) } node_address = format_address(ip_address=ip_address, port=port, protocol=protocol) url = f'{node_address}{url_path}' try: post(url=url, body=signed_block) except Exception as e: logger.exception(e)
def generate_signed_message(*, account_number, message, signing_key): block = { 'account_number': encode_verify_key(verify_key=account_number), 'message': message, 'signature': signing_key.sign(message.encode('utf-8')).signature.hex() } return block
def test_generate_block(): signing_key, account_number = create_account() encoded_account_number = encode_verify_key(verify_key=account_number) transactions = [{ 'amount': 1, 'recipient': random_encoded_account_number(), }, { 'amount': 1, 'recipient': random_encoded_account_number(), }, { 'amount': 5, 'recipient': random_encoded_account_number(), }] block = generate_block(account_number=account_number, balance_lock=encoded_account_number, signing_key=signing_key, transactions=transactions) assert block['account_number'] == encoded_account_number assert block['message']['balance_key'] == encoded_account_number assert len(block['message']['txs']) == 3 assert len(block['signature']) == SIGNATURE_LENGTH # Verify that signature is valid and the message has not been modified verify_signature(message=sort_and_encode(block['message']), signature=block['signature'], verify_key=block['account_number'])
def send_signed_block(*, block, ip_address, port, protocol, url_path): """ Sign block and send to recipient """ signing_key = get_signing_key() node_identifier = get_verify_key(signing_key=signing_key) node_identifier = encode_verify_key(verify_key=node_identifier) message = sort_and_encode(block) signed_block = { 'block': block, 'node_identifier': node_identifier, 'signature': generate_signature(message=message, signing_key=signing_key) } node_address = format_address(ip_address=ip_address, port=port, protocol=protocol) url = f'{node_address}{url_path}' try: post(url=url, body=signed_block) except Exception as e: request_new_primary_validator() logger.exception(e)
def test_network_block_serializer(): signing_key, account_number = create_account() encoded_account_number = encode_verify_key(verify_key=account_number) transactions = [{ 'amount': 1, 'fee': BANK, 'recipient': random_encoded_account_number(), }, { 'amount': 1, 'fee': PRIMARY_VALIDATOR, 'recipient': random_encoded_account_number(), }, { 'amount': 5, 'memo': 'Hello there I am 123 years old', 'recipient': random_encoded_account_number(), }] block = generate_block(account_number=account_number, balance_lock=encoded_account_number, signing_key=signing_key, transactions=transactions) serializer = NetworkBlockSerializer(data=block) assert serializer.is_valid()
def test_generate_block(): signing_key, account_number = create_account() encoded_account_number = encode_verify_key(verify_key=account_number) transactions = [{ 'amount': 1, 'fee': BANK, 'recipient': random_encoded_account_number(), }, { 'amount': 1, 'fee': PRIMARY_VALIDATOR, 'recipient': random_encoded_account_number(), }, { 'amount': 5, 'memo': 'Hello there I am 123 years old', 'recipient': random_encoded_account_number(), }] block = generate_block(account_number=account_number, balance_lock=encoded_account_number, signing_key=signing_key, transactions=transactions) assert block['account_number'] == encoded_account_number assert block['message']['balance_key'] == encoded_account_number assert len(block['message']['txs']) == 3 assert len(block['signature']) == SIGNATURE_LENGTH
def generate_signed_request(*, data, nid_signing_key): """Generate and return signed request""" node_identifier = get_verify_key(signing_key=nid_signing_key) signature = generate_signature( message=sort_and_encode(data), signing_key=nid_signing_key ) return { 'message': data, 'node_identifier': encode_verify_key(verify_key=node_identifier), 'signature': signature }
def run(): """ Create new account and save signing key """ file_path = os.path.join(SIGNING_KEY_DIR, 'cv_nid') create_account_and_save_signing_key_file(file=file_path) signing_key = read_signing_key_file(file_path) verify_key = get_verify_key(signing_key=signing_key) verify_key = encode_verify_key(verify_key=verify_key) print(f'verify_key: {verify_key}')
def signed_block(block_data, bank_signing_key): yield { 'block': block_data, 'node_identifier': encode_verify_key(verify_key=get_verify_key( signing_key=bank_signing_key, ), ), 'signature': generate_signature( message=sort_and_encode(block_data), signing_key=bank_signing_key, ), }
def block_data(account_data, encoded_account_number, random_encoded_account_number): signing_key, account_number = create_account() yield generate_block(account_number=account_number, balance_lock=encode_verify_key( verify_key=account_number, ), signing_key=signing_key, transactions=[{ 'amount': 1, 'recipient': random_encoded_account_number }])
def generate_block(*, account_number, balance_lock, signing_key, transactions): """Generate block""" message = { 'balance_key': balance_lock, 'txs': sorted(transactions, key=itemgetter('recipient')) } signature = generate_signature(message=sort_and_encode(message), signing_key=signing_key) block = { 'account_number': encode_verify_key(verify_key=account_number), 'message': message, 'signature': signature } return block
def run(send_to_pv=False): """ Create block used for: - POST /bank_blocks - Bank > PV """ treasury_signing_key = read_signing_key_file( os.path.join(SIGNING_KEY_DIR, 'treasury')) account_number = get_verify_key(signing_key=treasury_signing_key) balance_lock = get_account_balance_lock( account_number=TREASURY_ACCOUNT_NUMBER, live_pv=True) transactions = [{ 'amount': BANK_TX_FEE, 'recipient': BANK_ACCOUNT_NUMBER, }, { 'amount': PV_TX_FEE, 'recipient': PV_ACCOUNT_NUMBER, }, { 'amount': 1.0, 'recipient': BUCKY_ACCOUNT_NUMBER, }] block = generate_block(account_number=account_number, balance_lock=balance_lock, signing_key=treasury_signing_key, transactions=transactions) bank_nid_sk = read_signing_key_file( os.path.join(SIGNING_KEY_DIR, 'bank_nid')) bank_nid = get_verify_key(signing_key=bank_nid_sk) bank_nid = encode_verify_key(verify_key=bank_nid) message = sort_and_encode(block) signed_block = { 'block': block, 'node_identifier': bank_nid, 'signature': generate_signature(message=message, signing_key=bank_nid_sk) } write_json(os.path.join(BLOCKS_DIR, 'bank-blocks-request.json'), signed_block) if send_to_pv: send_request_to_pv(signed_block)
def block_data(account_data, encoded_account_number, random_encoded_account_number): signing_key, account_number = create_account() yield generate_block( account_number=account_number, balance_lock=encode_verify_key( verify_key=account_number, ), signing_key=signing_key, transactions=[ { 'amount': 4, 'fee': PRIMARY_VALIDATOR, 'recipient': 'ad1f8845c6a1abb6011a2a434a079a087c460657aad54329a84b406dce8bf314' }, { 'amount': 1, 'recipient': random_encoded_account_number } ] )
def test_post(self): """ Create block """ signing_key, account_number = create_account() encoded_account_number = encode_verify_key(verify_key=account_number) Account.objects.create(account_number=encoded_account_number, trust=50) self_configuration = get_self_configuration( exception_class=RuntimeError) primary_validator = self_configuration.primary_validator block = generate_block( account_number=account_number, balance_lock=encoded_account_number, signing_key=signing_key, transactions=[{ 'amount': float(self_configuration.default_transaction_fee), 'recipient': self_configuration.account_number }, { 'amount': float(primary_validator.default_transaction_fee), 'recipient': primary_validator.account_number }, { 'amount': self.fake.pyfloat(min_value=1, max_value=100, positive=True, right_digits=4), 'recipient': random_account_number() }]) self.validate_post('/blocks', block, status.HTTP_201_CREATED)
def random_encoded_account_number(): signing_key, account_number = create_account() return encode_verify_key(verify_key=account_number)
def encoded_account_number(account_number): yield encode_verify_key(verify_key=account_number)
def faucet_view(request): form = FaucetForm() if request.method == 'POST': form = FaucetForm(request.POST) if form.is_valid(): # form data url_str = form.cleaned_data['url'] amount = form.cleaned_data['amount'] platform = get_platform(url_str) if platform: post = platform.process(url_str, amount) if post: receiver_account_number = post.get_account_number() post_id = post.get_id() platform = post.get_platform() user_id = post.get_user() bank_config = SelfConfiguration.objects.first() pv_config = bank_config.primary_validator signing_key = get_signing_key() sender_account_number = encode_verify_key( verify_key=signing_key.verify_key) account = validate_post_exists(receiver_account_number, post_id) faucet_model = validate_expiry(account, user_id) if account and not faucet_model: response = requests.get( (f'{pv_config.protocol}://{pv_config.ip_address}' f':{pv_config.port}' f'/accounts/' f'{sender_account_number}/balance_lock')) if response.status_code == 200: balance_lock = response.json().get('balance_lock') if not balance_lock: balance_lock = bank_config.node_identifier faucet_model, created = ( FaucetModel.objects.update_or_create( account=account, social_user_id=user_id, social_type=platform, defaults={ 'next_valid_access_time': (timezone.now() + timedelta(hours=amount.delay)) })) post_model, created = PostModel.objects.get_or_create( post_id=post_id, reward=amount, social_user=faucet_model) transactions = [{ 'amount': amount.coins, 'recipient': receiver_account_number, 'memo': "Thank you for using TNBExplorer testnet" }, { 'amount': bank_config.default_transaction_fee, 'recipient': bank_config.account_number, 'fee': "BANK" }, { 'amount': pv_config.default_transaction_fee, 'recipient': pv_config.account_number, 'fee': "PRIMARY_VALIDATOR" }] block = generate_block( account_number=signing_key.verify_key, balance_lock=balance_lock, signing_key=signing_key, transactions=transactions) serializer = BlockSerializerCreate( data=block, context={'request': request}, ) serializer.is_valid(raise_exception=True) block = serializer.save() messages.success(request, ( f'SUCCESS! {amount.coins} faucet funds' f' transferred to {receiver_account_number}.')) form = FaucetForm() else: messages.error( request, 'Unable to obtain TNB account details!') else: form = FaucetForm() if faucet_model: duration = (faucet_model.next_valid_access_time - timezone.now()) totsec = duration.total_seconds() h = int(totsec // 3600) m = int((totsec % 3600) // 60) sec = round((totsec % 3600) % 60) messages.error( request, ('Slow down! Try again after (' f'{h} hours {m} mins and {sec} secs' ') till cooldown period expires.')) else: messages.error(request, ('Same post cannot be used again! ' ' Try again with a new one :P')) else: messages.error( request, ('Failed to extract information!' ' Make sure post is public,' ' contains #TNBFaucet and your account number')) else: messages.error(request, 'Only facebook and twitter URL allowed!') else: messages.error(request, 'Form invalid! Please provide correct details!') context = {'form': form} return render(request, 'index.html', context)
def post(self, request, format=None): serializer = FormSerializer(data=request.data, context={"request": request}) if serializer.is_valid(raise_exception=True): try: amount = FaucetOption.objects.get( pk=serializer.data['faucet_option_id']) url_str = serializer.data['url'] platform = get_platform(url_str) if platform: post = platform.process(url_str, amount) if post: receiver_account_number = post.get_account_number() post_id = post.get_id() platform = post.get_platform() user_id = post.get_user() bank_config = SelfConfiguration.objects.first() pv_config = bank_config.primary_validator signing_key = get_signing_key() sender_account_number = encode_verify_key( verify_key=signing_key.verify_key) account = validate_post_exists(receiver_account_number, post_id) faucet_model = validate_expiry(account, user_id) if account and not faucet_model: response = requests.get(( f'{pv_config.protocol}://{pv_config.ip_address}' f':{pv_config.port}' f'/accounts/' f'{sender_account_number}/balance_lock')) if response.status_code == 200: balance_lock = response.json().get( 'balance_lock') if not balance_lock: balance_lock = bank_config.node_identifier faucet_model, created = ( FaucetModel.objects.update_or_create( account=account, social_user_id=user_id, social_type=platform, defaults={ 'next_valid_access_time': (timezone.now() + timedelta(hours=amount.delay)) })) post_model, created = PostModel.objects.get_or_create( post_id=post_id, reward=amount, social_user=faucet_model) transactions = [{ 'amount': amount.coins, 'recipient': receiver_account_number, 'memo': "Thank you for using TNBExplorer testnet" }, { 'amount': bank_config.default_transaction_fee, 'recipient': bank_config.account_number, 'fee': "BANK" }, { 'amount': pv_config.default_transaction_fee, 'recipient': pv_config.account_number, 'fee': "PRIMARY_VALIDATOR" }] block = generate_block( account_number=signing_key.verify_key, balance_lock=balance_lock, signing_key=signing_key, transactions=transactions) serializer = BlockSerializerCreate( data=block, context={'request': request}, ) serializer.is_valid(raise_exception=True) block = serializer.save() return Response( success_response(( f'SUCCESS! {amount.coins} faucet funds' f' transferred to {receiver_account_number}.' ))) else: return Response(error_response( 'Unable to obtain TNB account details!'), status=status. HTTP_500_INTERNAL_SERVER_ERROR) else: if faucet_model: duration = ( faucet_model.next_valid_access_time - timezone.now()) totsec = duration.total_seconds() h = int(totsec // 3600) m = int((totsec % 3600) // 60) sec = round((totsec % 3600) % 60) return Response( error_response( ('Slow down! Try again after (' f'{h} hours {m} mins and {sec} secs' ') till cooldown period expires.')), status=status.HTTP_429_TOO_MANY_REQUESTS) else: return Response( error_response( ('Same post cannot be used again! ' ' Try again with a new one :P')), status=status.HTTP_400_BAD_REQUEST) else: return Response(error_response( ('Failed to extract information!' ' Make sure post is public,' ' contains #TNBFaucet and your account number')), status=status.HTTP_400_BAD_REQUEST) else: return Response(error_response( 'Only facebook and twitter URL allowed!'), status=status.HTTP_400_BAD_REQUEST) except FaucetOption.DoesNotExist: return Response(error_response('bad request format/data'), status=status.HTTP_400_BAD_REQUEST) else: return Response(error_response('bad request format/data'), status=status.HTTP_400_BAD_REQUEST)
def random_encoded_account_number(): _, account_number = create_account() yield encode_verify_key(verify_key=account_number)