def test_account_handler_apply(): """ Case: send transaction request, to send tokens to address, to the account handler. Expect: addresses data, stored in state, are changed according to transfer amount. """ expected_account_from_balance = ACCOUNT_FROM_BALANCE - TOKENS_AMOUNT_TO_SEND expected_account_to_balance = ACCOUNT_TO_BALANCE + TOKENS_AMOUNT_TO_SEND account_protobuf = Account() account_protobuf.balance = expected_account_from_balance expected_serialized_account_from_balance = account_protobuf.SerializeToString() account_protobuf.balance = expected_account_to_balance expected_serialized_account_to_balance = account_protobuf.SerializeToString() expected_state = { ACCOUNT_ADDRESS_FROM: expected_serialized_account_from_balance, ACCOUNT_ADDRESS_TO: expected_serialized_account_to_balance, } transfer_payload = TransferPayload() transfer_payload.address_to = ACCOUNT_ADDRESS_TO transfer_payload.value = TOKENS_AMOUNT_TO_SEND transaction_payload = TransactionPayload() transaction_payload.method = AccountMethod.TRANSFER transaction_payload.data = transfer_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = TransactionHeader( signer_public_key=RANDOM_NODE_PUBLIC_KEY, family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_name'), family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_version'), inputs=INPUTS, outputs=OUTPUTS, dependencies=[], payload_sha512=hash512(data=serialized_transaction_payload), batcher_public_key=RANDOM_NODE_PUBLIC_KEY, nonce=time.time().hex().encode(), ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=ACCOUNT_FROM_PRIVATE_KEY).sign(serialized_header), ) mock_context = create_context(account_from_balance=ACCOUNT_FROM_BALANCE, account_to_balance=ACCOUNT_TO_BALANCE) AccountHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ACCOUNT_ADDRESS_TO, ACCOUNT_ADDRESS_FROM]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_store_public_key_for_other_no_payer_account(): """ Case: send transaction request, to store certificate public key for other, when payer account does not exist. Expect: invalid transaction error is raised with not enough transferable balance error message. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) owner_account = Account() owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) serialized_owner_account = owner_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ OWNER_ADDRESS: serialized_owner_account, ZERO_ADDRESS: serialized_zero_account, }) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'Not enough transferable balance. Sender\'s current balance: 0.' == str(error.value)
def create_context(account_from_balance, account_to_balance): """ Create stub context with initial data. Stub context is an interface around Sawtooth state, consider as database. State is key-value storage that contains address with its data (i.e. account balance). References: - https://github.com/Remmeauth/remme-core/blob/dev/testing/mocks/stub.py """ account_protobuf = Account() account_protobuf.balance = account_from_balance serialized_account_from_balance = account_protobuf.SerializeToString() account_protobuf.balance = account_to_balance serialized_account_to_balance = account_protobuf.SerializeToString() initial_state = { ACCOUNT_ADDRESS_FROM: serialized_account_from_balance, ACCOUNT_ADDRESS_TO: serialized_account_to_balance, } return StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state=initial_state)
def test_public_key_handler_non_existing_sender_account(): """ Case: send transaction request, to store certificate public key, from non-existing account. Expect: invalid transaction error is raised with not enough transferable balance error message. """ new_public_key_payload = generate_rsa_payload() transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE transaction_payload.data = new_public_key_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header(serialized_transaction_payload, INPUTS, OUTPUTS) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer( private_key=SENDER_PRIVATE_KEY).sign(serialized_header), ) zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ZERO_ADDRESS: serialized_zero_account, }) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'Not enough transferable balance. Sender\'s current balance: 0.' == str( error.value)
def test_expire_atomic_swap(): """ Case: to expire atomic swap. Expect: increase bot address balance by swap amount. Leave commission on zero address. """ atomic_swap_expire_payload = AtomicSwapExpirePayload(swap_id=SWAP_ID, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.EXPIRE transaction_payload.data = atomic_swap_expire_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = TransactionHeader( signer_public_key=BOT_PUBLIC_KEY, family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get( 'family_name'), family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get( 'family_version'), inputs=INPUTS, outputs=OUTPUTS, dependencies=[], payload_sha512=hash512(data=serialized_transaction_payload), batcher_public_key=RANDOM_NODE_PUBLIC_KEY, nonce=time.time().hex().encode(), ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer( private_key=BOT_PRIVATE_KEY).sign(serialized_header), ) bot_account = Account() bot_account.balance = 4700 serialized_bot_account = bot_account.SerializeToString() genesis_members_setting = Setting() genesis_members_setting.entries.add(key=SETTINGS_KEY_ZERO_ADDRESS_OWNERS, value=f'{BOT_PUBLIC_KEY},') serialized_genesis_members_setting = genesis_members_setting.SerializeToString( ) existing_swap_info = AtomicSwapInfo() existing_swap_info.swap_id = SWAP_ID existing_swap_info.state = AtomicSwapInfo.OPENED existing_swap_info.amount = TOKENS_AMOUNT_TO_SWAP existing_swap_info.created_at = CURRENT_TIMESTAMP // 2 existing_swap_info.sender_address = BOT_ADDRESS existing_swap_info.receiver_address = ALICE_ADDRESS existing_swap_info.is_initiator = True serialized_existing_swap_info = existing_swap_info.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG, BLOCK_INFO_ADDRESS: SERIALIZED_BLOCK_INFO, BOT_ADDRESS: serialized_bot_account, ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_existing_swap_info, ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY: serialized_genesis_members_setting, }) expected_bot_account = Account() expected_bot_account.balance = 4700 + TOKENS_AMOUNT_TO_SWAP serialized_expected_bot_account = expected_bot_account.SerializeToString() expected_swap_info = AtomicSwapInfo() expected_swap_info.swap_id = SWAP_ID expected_swap_info.state = AtomicSwapInfo.EXPIRED expected_swap_info.amount = TOKENS_AMOUNT_TO_SWAP expected_swap_info.created_at = CURRENT_TIMESTAMP // 2 expected_swap_info.sender_address = BOT_ADDRESS expected_swap_info.receiver_address = ALICE_ADDRESS expected_swap_info.is_initiator = True serialized_expected_swap_info = expected_swap_info.SerializeToString() expected_state = { BOT_ADDRESS: serialized_expected_bot_account, ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_expected_swap_info, } AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ ADDRESS_TO_STORE_SWAP_INFO_BY, BOT_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_public_key_handler_rsa_store(): """ Case: send transaction request to store certificate public key. Expect: public key information is stored to blockchain linked to owner address. Owner paid tokens for storing. """ new_public_key_payload = generate_rsa_payload() transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE transaction_payload.data = new_public_key_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header(serialized_transaction_payload, INPUTS, OUTPUTS) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer( private_key=SENDER_PRIVATE_KEY).sign(serialized_header), ) sender_account = Account() sender_account.balance = SENDER_INITIAL_BALANCE sender_account.pub_keys.append(RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY) serialized_sender_account = sender_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ SENDER_ADDRESS: serialized_sender_account, ZERO_ADDRESS: serialized_zero_account, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = SENDER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString( ) expected_sender_account = Account() expected_sender_account.balance = SENDER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE expected_sender_account.pub_keys.append( RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY) expected_sender_account.pub_keys.append( ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY) expected_serialized_sender_account = expected_sender_account.SerializeToString( ) expected_zero_account = Account() expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE expected_serialized_zero_account = expected_zero_account.SerializeToString( ) expected_state = { SENDER_ADDRESS: expected_serialized_sender_account, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ SENDER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_public_key_handler_store_sender_is_node(): """ Case: send transaction request, to store certificate public key, when sender is node (same addresses). Expect: public key information is stored to blockchain linked to owner address. Owner hasn't paid for storing. """ new_public_key_payload = generate_rsa_payload() transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE transaction_payload.data = new_public_key_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header(serialized_transaction_payload, INPUTS, OUTPUTS) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer( private_key=SENDER_PRIVATE_KEY).sign(serialized_header), ) sender_account = Account() sender_account.pub_keys.append(RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY) serialized_sender_account = sender_account.SerializeToString() zero_account = Account() serialized_zero_account = zero_account.SerializeToString() is_economy_enabled_setting = Setting() is_economy_enabled_setting.entries.add(key='remme.economy_enabled', value='false') serialized_is_economy_enabled_setting = is_economy_enabled_setting.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ SENDER_ADDRESS: serialized_sender_account, IS_NODE_ECONOMY_ENABLED_ADDRESS: serialized_is_economy_enabled_setting, ZERO_ADDRESS: serialized_zero_account, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = SENDER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString( ) expected_sender_account = Account() expected_sender_account.pub_keys.append( RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY) expected_sender_account.pub_keys.append( ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY) expected_serialized_sender_account = expected_sender_account.SerializeToString( ) expected_zero_account = Account() expected_serialized_zero_account = expected_zero_account.SerializeToString( ) expected_state = { SENDER_ADDRESS: expected_serialized_sender_account, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ SENDER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_account_handler_genesis_apply(): """ Case: send transaction request, to send tokens from genesis address, to the account handler. Expect: """ account = Account() account.balance = TOKENS_AMOUNT_TO_SUPPLY expected_serialized_account_to_balance = account.SerializeToString() genesis_payload = GenesisPayload() genesis_payload.total_supply = TOKENS_AMOUNT_TO_SUPPLY transaction_payload = TransactionPayload() transaction_payload.method = AccountMethod.GENESIS transaction_payload.data = genesis_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = TransactionHeader( signer_public_key=NODE_PUBLIC_KEY, family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get( 'family_name'), family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get( 'family_version'), inputs=INPUTS, outputs=OUTPUTS, dependencies=[], payload_sha512=hash512(data=serialized_transaction_payload), batcher_public_key=NODE_PUBLIC_KEY, nonce=time.time().hex().encode(), ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer( private_key=NODE_PRIVATE_KEY).sign(serialized_header), ) genesis_status = GenesisStatus() genesis_status.status = True expected_state = { GENESIS_ADDRESS: genesis_status.SerializeToString(), ACCOUNT_ADDRESS_TO: expected_serialized_account_to_balance, } mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={}) AccountHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state( addresses=[GENESIS_ADDRESS, ACCOUNT_ADDRESS_TO]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_close_atomic_swap(): """ Case: close atomic swap. Expect: increase Alice account address by swap amount. """ atomic_swap_close_payload = AtomicSwapClosePayload( swap_id=SWAP_ID, secret_key=SECRET_KEY, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.CLOSE transaction_payload.data = atomic_swap_close_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = TransactionHeader( signer_public_key=BOT_PUBLIC_KEY, family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get( 'family_name'), family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get( 'family_version'), inputs=INPUTS, outputs=OUTPUTS, dependencies=[], payload_sha512=hash512(data=serialized_transaction_payload), batcher_public_key=RANDOM_NODE_PUBLIC_KEY, nonce=time.time().hex().encode(), ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer( private_key=BOT_PRIVATE_KEY).sign(serialized_header), ) alice_account = Account() alice_account.balance = 0 serialized_alice_account = alice_account.SerializeToString() existing_swap_info_to_close = AtomicSwapInfo() existing_swap_info_to_close.swap_id = SWAP_ID existing_swap_info_to_close.amount = 200 existing_swap_info_to_close.state = AtomicSwapInfo.APPROVED existing_swap_info_to_close.secret_lock = SECRET_LOCK existing_swap_info_to_close.is_initiator = True existing_swap_info_to_close.sender_address = BOT_ADDRESS existing_swap_info_to_close.receiver_address = ALICE_ADDRESS serialized_existing_swap_info_to_lock = existing_swap_info_to_close.SerializeToString( ) genesis_members_setting = Setting() genesis_members_setting.entries.add(key=SETTINGS_KEY_ZERO_ADDRESS_OWNERS, value=f'{BOT_PUBLIC_KEY},') serialized_genesis_members_setting = genesis_members_setting.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY: serialized_genesis_members_setting, ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_existing_swap_info_to_lock, ALICE_ADDRESS: serialized_alice_account, }) expected_alice_account = Account() expected_alice_account.balance = TOKENS_AMOUNT_TO_SWAP serialized_expected_alice_account = expected_alice_account.SerializeToString( ) expected_closed_swap_info = AtomicSwapInfo() expected_closed_swap_info.swap_id = SWAP_ID expected_closed_swap_info.amount = 200 expected_closed_swap_info.state = AtomicSwapInfo.CLOSED expected_closed_swap_info.secret_lock = SECRET_LOCK expected_closed_swap_info.secret_key = SECRET_KEY expected_closed_swap_info.is_initiator = True expected_closed_swap_info.sender_address = BOT_ADDRESS expected_closed_swap_info.receiver_address = ALICE_ADDRESS serialized_expected_closed_swap_info = expected_closed_swap_info.SerializeToString( ) expected_state = { ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_expected_closed_swap_info, ALICE_ADDRESS: serialized_expected_alice_account, } AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state( addresses=[ADDRESS_TO_STORE_SWAP_INFO_BY, ALICE_ADDRESS]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_store_public_key_for_other_economy_is_not_enabled(): """ Case: send transaction request, to store certificate public key for other, when economy isn't enabled. Expect: public key information is stored to blockchain linked to owner address. Owner hasn't paid for storing. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) payer_account = Account() payer_account.balance = PAYER_INITIAL_BALANCE serialized_payer_account = payer_account.SerializeToString() owner_account = Account() owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) serialized_owner_account = owner_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() is_economy_enabled_setting = Setting() is_economy_enabled_setting.entries.add(key='remme.economy_enabled', value='false') serialized_is_economy_enabled_setting = is_economy_enabled_setting.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ OWNER_ADDRESS: serialized_owner_account, PAYER_ADDRESS: serialized_payer_account, ZERO_ADDRESS: serialized_zero_account, IS_NODE_ECONOMY_ENABLED_ADDRESS: serialized_is_economy_enabled_setting, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = OWNER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString() expected_payer_account = Account() expected_payer_account.balance = PAYER_INITIAL_BALANCE serialized_expected_payer_account = expected_payer_account.SerializeToString() expected_owner_account = Account() expected_owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) expected_owner_account.pub_keys.append(ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY) serialized_expected_owner_account = expected_owner_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = 0 expected_serialized_zero_account = expected_zero_account.SerializeToString() expected_state = { OWNER_ADDRESS: serialized_expected_owner_account, PAYER_ADDRESS: serialized_expected_payer_account, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_store_rsa_public_key_no_owner_account(): """ Case: send transaction request, to store certificate public key (RSA) for other, when owner account does not exist. Expect: public key information is stored to blockchain linked to the newly created owner account's address. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) payer_account = Account() payer_account.balance = PAYER_INITIAL_BALANCE serialized_payer_account = payer_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ PAYER_ADDRESS: serialized_payer_account, ZERO_ADDRESS: serialized_zero_account, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = OWNER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString() expected_payer_account = Account() expected_payer_account.balance = PAYER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE serialized_expected_payer_account = expected_payer_account.SerializeToString() expected_owner_account = Account() expected_owner_account.pub_keys.append(ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY) serialized_expected_owner_account = expected_owner_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE expected_serialized_zero_account = expected_zero_account.SerializeToString() expected_state = { OWNER_ADDRESS: serialized_expected_owner_account, PAYER_ADDRESS: serialized_expected_payer_account, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_store_ecdsa_public_key(): """ Case: send transaction request to store certificate public key (ECDSA) for other. Expect: public key information is stored to blockchain linked to owner address. Transaction sender paid for storing. """ inputs = outputs = [ ADDRESS_FROM_ECDSA_PUBLIC_KEY, OWNER_ADDRESS, PAYER_ADDRESS, ZERO_ADDRESS, IS_NODE_ECONOMY_ENABLED_ADDRESS, ] new_public_key_payload = generate_ecdsa_payload(key=ECDSA_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, inputs, outputs, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) payer_account = Account() payer_account.balance = PAYER_INITIAL_BALANCE serialized_payer_account = payer_account.SerializeToString() owner_account = Account() owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) serialized_owner_account = owner_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=inputs, outputs=outputs, initial_state={ OWNER_ADDRESS: serialized_owner_account, PAYER_ADDRESS: serialized_payer_account, ZERO_ADDRESS: serialized_zero_account, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = OWNER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString() expected_payer_account = Account() expected_payer_account.balance = PAYER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE serialized_expected_payer_account = expected_payer_account.SerializeToString() expected_owner_account = Account() expected_owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) expected_owner_account.pub_keys.append(ADDRESS_FROM_ECDSA_PUBLIC_KEY) serialized_expected_owner_account = expected_owner_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE expected_serialized_zero_account = expected_zero_account.SerializeToString() expected_state = { OWNER_ADDRESS: serialized_expected_owner_account, PAYER_ADDRESS: serialized_expected_payer_account, ADDRESS_FROM_ECDSA_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_ECDSA_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_atomic_swap_init_swap_not_enough_balance(): """ Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens with not enough bot address balance. Expect: invalid transaction error is raised with not enough balance error message. """ atomic_swap_init_payload = AtomicSwapInitPayload( receiver_address=ALICE_ADDRESS, sender_address_non_local=BOT_ETHEREUM_ADDRESS, amount=TOKENS_AMOUNT_TO_SWAP, swap_id=SWAP_ID, secret_lock_by_solicitor=BOT_IT_IS_INITIATOR_MARK, email_address_encrypted_by_initiator=ALICE_EMAIL_ADDRESS_ENCRYPTED_BY_INITIATOR, created_at=CURRENT_TIMESTAMP, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.INIT transaction_payload.data = atomic_swap_init_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = TransactionHeader( signer_public_key=BOT_PUBLIC_KEY, family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_name'), family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_version'), inputs=INPUTS, outputs=OUTPUTS, dependencies=[], payload_sha512=hash512(data=serialized_transaction_payload), batcher_public_key=RANDOM_NODE_PUBLIC_KEY, nonce=time.time().hex().encode(), ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=BOT_PRIVATE_KEY).sign(serialized_header), ) bot_account = Account() bot_account.balance = 0 serialized_bot_account_balance = bot_account.SerializeToString() swap_commission_setting = Setting() swap_commission_setting.entries.add(key=SETTINGS_SWAP_COMMISSION, value=str(SWAP_COMMISSION_AMOUNT)) serialized_swap_commission_setting = swap_commission_setting.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG, BLOCK_INFO_ADDRESS: SERIALIZED_BLOCK_INFO, BOT_ADDRESS: serialized_bot_account_balance, ADDRESS_TO_GET_SWAP_COMMISSION_AMOUNT_BY: serialized_swap_commission_setting, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) total_amount = TOKENS_AMOUNT_TO_SWAP + SWAP_COMMISSION_AMOUNT assert f'Not enough balance to perform the transaction in the amount (with a commission) {total_amount}.' \ == str(error.value)
def test_atomic_swap_init(): """ Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens. Expect: bot sends commission to the zero account address, swap amount is decreased from bot account. """ atomic_swap_init_payload = AtomicSwapInitPayload( receiver_address=ALICE_ADDRESS, sender_address_non_local=BOT_ETHEREUM_ADDRESS, amount=TOKENS_AMOUNT_TO_SWAP, swap_id=SWAP_ID, secret_lock_by_solicitor=BOT_IT_IS_INITIATOR_MARK, email_address_encrypted_by_initiator=ALICE_EMAIL_ADDRESS_ENCRYPTED_BY_INITIATOR, created_at=CURRENT_TIMESTAMP, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.INIT transaction_payload.data = atomic_swap_init_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = TransactionHeader( signer_public_key=BOT_PUBLIC_KEY, family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_name'), family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_version'), inputs=INPUTS, outputs=OUTPUTS, dependencies=[], payload_sha512=hash512(data=serialized_transaction_payload), batcher_public_key=RANDOM_NODE_PUBLIC_KEY, nonce=time.time().hex().encode(), ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=BOT_PRIVATE_KEY).sign(serialized_header), ) bot_account = Account() bot_account.balance = 5000 serialized_bot_account = bot_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() swap_commission_setting = Setting() swap_commission_setting.entries.add(key=SETTINGS_SWAP_COMMISSION, value=str(SWAP_COMMISSION_AMOUNT)) serialized_swap_commission_setting = swap_commission_setting.SerializeToString() genesis_members_setting = Setting() genesis_members_setting.entries.add(key=SETTINGS_KEY_ZERO_ADDRESS_OWNERS, value=f'{BOT_PUBLIC_KEY},') serialized_genesis_members_setting = genesis_members_setting.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG, BLOCK_INFO_ADDRESS: SERIALIZED_BLOCK_INFO, BOT_ADDRESS: serialized_bot_account, ZERO_ADDRESS: serialized_zero_account, ADDRESS_TO_GET_SWAP_COMMISSION_AMOUNT_BY: serialized_swap_commission_setting, ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY: serialized_genesis_members_setting, }) swap_info = AtomicSwapInfo() swap_info.swap_id = SWAP_ID swap_info.state = AtomicSwapInfo.OPENED swap_info.amount = TOKENS_AMOUNT_TO_SWAP swap_info.created_at = CURRENT_TIMESTAMP swap_info.email_address_encrypted_optional = ALICE_EMAIL_ADDRESS_ENCRYPTED_BY_INITIATOR swap_info.sender_address = BOT_ADDRESS swap_info.sender_address_non_local = BOT_ETHEREUM_ADDRESS swap_info.receiver_address = ALICE_ADDRESS swap_info.is_initiator = True serialized_swap_info = swap_info.SerializeToString() expected_bot_account = Account() expected_bot_account.balance = 5000 - TOKENS_AMOUNT_TO_SWAP - SWAP_COMMISSION_AMOUNT serialized_expected_bot_account = expected_bot_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = SWAP_COMMISSION_AMOUNT serialized_expected_zero_account = expected_zero_account.SerializeToString() expected_state = { BOT_ADDRESS: serialized_expected_bot_account, ZERO_ADDRESS: serialized_expected_zero_account, ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_swap_info, } AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ ADDRESS_TO_STORE_SWAP_INFO_BY, BOT_ADDRESS, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict