def get_context(self): context = super().get_context() context.AMOUNT = 10000 context.COMMISSION = 100 context.swap_id = generate_random_key() context.swap_address = AtomicSwapHandler().make_address_from_data( context.swap_id) context.secret_key = "039eaa877ff63694f8f09c8034403f8b5165a7418812a642396d5d539f90b170" context.secret_lock = "b605112c2d7489034bbd7beab083fb65ba02af787786bb5e3d99bb26709f4f68" context.now = datetime.datetime.now() context.created_at = int(context.now.timestamp()) context.email_address = "" context.sender_address_non_local = "" swap_info = AtomicSwapInfo() swap_info.swap_id = context.swap_id swap_info.state = AtomicSwapInfo.OPENED swap_info.is_initiator = False swap_info.amount = context.AMOUNT swap_info.created_at = context.created_at swap_info.email_address_encrypted_optional = context.email_address swap_info.sender_address = self.account_address1 swap_info.sender_address_non_local = context.sender_address_non_local swap_info.receiver_address = self.account_address2 swap_info.secret_lock = context.secret_lock context.swap_info = swap_info return context
def test_close_atomic_swap_before_approve(): """ Case: close swap before it is approved. Expect: invalid transaction error is raised with transaction cannot be closed before it is approved error message. """ 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), ) existing_swap_info_to_close = AtomicSwapInfo() existing_swap_info_to_close.swap_id = SWAP_ID existing_swap_info_to_close.state = AtomicSwapInfo.OPENED existing_swap_info_to_close.secret_lock = SECRET_LOCK existing_swap_info_to_close.is_initiator = True serialized_existing_swap_info_to_lock = existing_swap_info_to_close.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_existing_swap_info_to_lock, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert 'Transaction cannot be closed before it\'s approved.' == str( error.value)
def test_approve_atomic_swap_without_secret_lock_state(): """ Case: approve atomic swap without secret lock state. Expect: invalid transaction error is raised with swap identifier is already closed error message. """ atomic_swap_approve_payload = AtomicSwapApprovePayload(swap_id=SWAP_ID, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.APPROVE transaction_payload.data = atomic_swap_approve_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), ) 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.sender_address = BOT_ADDRESS swap_info.secret_lock = SECRET_LOCK swap_info.receiver_address = ALICE_ADDRESS swap_info.is_initiator = True serialized_swap_info = swap_info.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_swap_info, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'Swap identifier {SWAP_ID} is already closed.' == str(error.value)
def test_set_lock_to_atomic_swap_with_set_lock(): """ Case: set secret lock to atomic swap with already set secret lock. Expect: invalid transaction error is raised with secret lock is already added error message. """ atomic_swap_init_payload = AtomicSwapSetSecretLockPayload( swap_id=SWAP_ID, secret_lock=SECRET_LOCK, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.SET_SECRET_LOCK 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), ) already_set_lock_swap_info = AtomicSwapInfo() already_set_lock_swap_info.swap_id = SWAP_ID already_set_lock_swap_info.state = AtomicSwapInfo.OPENED already_set_lock_swap_info.secret_lock = SECRET_LOCK serialized_already_set_lock_swap_info = already_set_lock_swap_info.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_already_set_lock_swap_info, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'Secret lock is already added for {SWAP_ID}.' == str(error.value)
def test_atomic_swap_init_with_empty_proto(): """ Case: send empty proto for init Expect: invalid transaction error """ inputs = outputs = [ ADDRESS_TO_GET_SWAP_COMMISSION_AMOUNT_BY, BLOCK_INFO_CONFIG_ADDRESS, BLOCK_INFO_ADDRESS, BOT_ADDRESS, ZERO_ADDRESS, ADDRESS_TO_STORE_SWAP_INFO_BY, ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY, ] atomic_swap_init_payload = AtomicSwapInitPayload() 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), ) mock_context = StubContext(inputs=inputs, outputs=outputs, initial_state={}) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert proto_error_msg( AtomicSwapInitPayload, { 'receiver_address': ['Missed address'], 'sender_address_non_local': ['This field is required.'], 'amount': ['This field is required.'], 'swap_id': ['Missed swap_id'], 'created_at': ['This field is required.'], } ) == str(error.value)
def test_close_already_closed_atomic_swap(): """ Case: close already closed atomic swap. Expect: invalid transaction error is raised with already operation with closed or expired swap error message. """ 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), ) already_closed_swap_info = AtomicSwapInfo() already_closed_swap_info.swap_id = SWAP_ID already_closed_swap_info.state = AtomicSwapInfo.CLOSED serialized_already_closed_swap_info = already_closed_swap_info.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_already_closed_swap_info, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'No operations can be done upon the swap: {SWAP_ID} as it is already closed or expired.' == str( error.value)
def test_atomic_swap_init_swap_no_account_in_state(): """ Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens from non-existent bot address. 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), ) 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, 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_expire_atomic_swap_by_not_swap_owner(): """ Case: to expire atomic swap by signer address isn't specified in atomic swap sender address. Expect: invalid transaction error is raised with signer is not the one who opened the swap. error message. """ atomic_swap_close_payload = AtomicSwapExpirePayload(swap_id=SWAP_ID, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.EXPIRE 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), ) existing_swap_info_to_expire = AtomicSwapInfo() existing_swap_info_to_expire.swap_id = SWAP_ID existing_swap_info_to_expire.state = AtomicSwapInfo.OPENED existing_swap_info_to_expire.sender_address = RANDOM_ADDRESS serialized_existing_swap_info_to_expire = existing_swap_info_to_expire.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_existing_swap_info_to_expire, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'Signer is not the one who opened the swap.' == str(error.value)
def test_atomic_swap_init_swap_receiver_address_invalid_type(): """ Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens with invalid Alice node address. Expect: invalid transaction error is raised with atomic swap id has already been taken error message. """ invalid_receiver_address = '112934y*(J#QJ3UH*PD(:9B&TYDB*I0b0a8edc4104ef28093ee30' atomic_swap_init_payload = AtomicSwapInitPayload( receiver_address=invalid_receiver_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), ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG, BLOCK_INFO_ADDRESS: SERIALIZED_BLOCK_INFO, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert proto_error_msg( AtomicSwapInitPayload, {'receiver_address': ['Address is not of a blockchain token type.']} ) == str(error.value)
def test_atomic_swap_init_swap_no_block_info(): """ Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens when no needed block information. Expect: invalid transaction error is raised with nlock config not found 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), ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'Block {block_info_config.latest_block + 1} not found.' == str(error.value)
def test_close_not_initialized_atomic_swap(): """ Case: close not initialized atomic swap. Expect: invalid transaction error is raised with atomic swap was not initiated error message. """ 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), ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={}) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'Atomic swap was not initiated for identifier {SWAP_ID}!' == str( error.value)
def test_set_lock_with_empty_proto(): """ Case: send empty proto for set lock Expect: invalid transaction error """ atomic_swap_init_payload = AtomicSwapSetSecretLockPayload() transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.SET_SECRET_LOCK 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), ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={}) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert proto_error_msg( AtomicSwapSetSecretLockPayload, { 'swap_id': ['Missed swap_id'], 'secret_lock': ['This field is required.'], }) == str(error.value)
# limitations under the License. # ------------------------------------------------------------------------ # pylint: disable=invalid-name import argparse from sawtooth_sdk.processor.core import TransactionProcessor from remme.tp.atomic_swap import AtomicSwapHandler from remme.tp.pub_key import PubKeyHandler from remme.tp.account import AccountHandler from remme.shared.logging_setup import setup_logging from remme.settings.default import load_toml_with_defaults TP_HANDLERS = [AccountHandler(), PubKeyHandler(), AtomicSwapHandler()] if __name__ == '__main__': config = load_toml_with_defaults( '/config/remme-client-config.toml')['remme']['client'] parser = argparse.ArgumentParser(description='Transaction processor.') parser.add_argument('-v', '--verbosity', type=int, default=2) args = parser.parse_args() setup_logging('remme-tp', args.verbosity) processor = TransactionProcessor( url=f'tcp://{ config["validator_ip"] }:{ config["validator_port"] }') for handler in TP_HANDLERS: processor.add_handler(handler) try:
BOT_ETHEREUM_ADDRESS = '0xe6ca0e7c974f06471759e9a05d18b538c5ced11e' BOT_PRIVATE_KEY = '1cb15ecfe1b3dc02df0003ac396037f85b98cf9f99b0beae000dc5e9e8b6dab4' BOT_PUBLIC_KEY = '03ecc5cb4094eb05319be6c7a63ebf17133d4ffaea48cdcfd1d5fc79dac7db7b6b' BOT_ADDRESS = '112007b9433e1da5c624ff926477141abedfd57585a36590b0a8edc4104ef28093ee30' ALICE_ETHEREUM_ADDRESS = '0x8dfe0f55a1cf9b22b8c85a9ff7a85a28a3879f71' ALICE_ADDRESS = '112007db8a00c010402e2e3a7d03491323e761e0ea612481c518605648ceeb5ed454f7' ALICE_EMAIL_ADDRESS_ENCRYPTED_BY_INITIATOR = '0x6f4d5666332f5a575a714d4245624455612f2b4345424f704b4256704f5' BOT_IT_IS_INITIATOR_MARK = '' SWAP_ID = '033102e41346242476b15a3a7966eb5249271025fc7fb0b37ed3fdb4bcce3884' ADDRESS_TO_GET_SWAP_COMMISSION_AMOUNT_BY = _make_settings_key(SETTINGS_SWAP_COMMISSION) ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY = _make_settings_key(SETTINGS_KEY_ZERO_ADDRESS_OWNERS) ADDRESS_TO_STORE_SWAP_INFO_BY = BasicHandler( name=AtomicSwapHandler().family_name, versions=AtomicSwapHandler()._family_versions[0] ).make_address_from_data(data=SWAP_ID) TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS = { 'family_name': AtomicSwapHandler().family_name, 'family_version': AtomicSwapHandler()._family_versions[0], } RANDOM_NODE_PUBLIC_KEY = '039d6881f0a71d05659e1f40b443684b93c7b7c504ea23ea8949ef5216a2236940' RANDOM_PUBLIC_KEY = '8c87d914a6cfeaf027413760ad359b5a56bfe0eda504d879b21872c7dc5b911c' CURRENT_TIMESTAMP = int(datetime.datetime.now().timestamp()) BLOCK_INFO_CONFIG_ADDRESS = CONFIG_ADDRESS BLOCK_INFO_ADDRESS = BlockInfoClient.create_block_address(1000)
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_approve_atomic_swap(): """ Case: approve atomic swap. Expect: atomic swap state is changed to approved. """ atomic_swap_init_payload = AtomicSwapApprovePayload(swap_id=SWAP_ID, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.APPROVE 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), ) existing_swap_info = AtomicSwapInfo() existing_swap_info.swap_id = SWAP_ID existing_swap_info.state = AtomicSwapInfo.SECRET_LOCK_PROVIDED existing_swap_info.sender_address = BOT_ADDRESS existing_swap_info.secret_lock = SECRET_LOCK existing_swap_info.is_initiator = True serialized_existing_swap_info = existing_swap_info.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_existing_swap_info, }) expected_swap_info = AtomicSwapInfo() expected_swap_info.swap_id = SWAP_ID expected_swap_info.state = AtomicSwapInfo.APPROVED expected_swap_info.sender_address = BOT_ADDRESS expected_swap_info.secret_lock = SECRET_LOCK expected_swap_info.is_initiator = True serialized_expected_swap_info = expected_swap_info.SerializeToString() expected_state = { 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]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
# pylint: disable=invalid-name import argparse from sawtooth_sdk.processor.core import TransactionProcessor from remme.tp.atomic_swap import AtomicSwapHandler from remme.tp.pub_key import PubKeyHandler from remme.tp.account import AccountHandler from remme.shared.logging_setup import setup_logging from remme.settings.default import load_toml_with_defaults TP_HANDLERS = { handler._family_name: handler for handler in (AccountHandler(), PubKeyHandler(), AtomicSwapHandler()) } if __name__ == '__main__': config = load_toml_with_defaults( '/config/remme-client-config.toml')['remme']['client'] parser = argparse.ArgumentParser(description='Transaction processor.') parser.add_argument('-v', '--verbosity', type=int, default=2) args = parser.parse_args() setup_logging('remme-tp', args.verbosity) processor = TransactionProcessor( url=f'tcp://{ config["validator_ip"] }:{ config["validator_port"] }') for handler in TP_HANDLERS.values(): processor.add_handler(handler)
BOT_PRIVATE_KEY = '1cb15ecfe1b3dc02df0003ac396037f85b98cf9f99b0beae000dc5e9e8b6dab4' BOT_PUBLIC_KEY = '03ecc5cb4094eb05319be6c7a63ebf17133d4ffaea48cdcfd1d5fc79dac7db7b6b' ALICE_PRIVATE_KEY = '8c87d914a6cfeaf027413760ad359b5a56bfe0eda504d879b21872c7dc5b911c' ALICE_PUBLIC_KEY = '02feb988591c78e58e57cdce5a314bd04798971227fcc2316907355392a2c99c25' ALICE_ADDRESS = '112007db8a00c010402e2e3a7d03491323e761e0ea612481c518605648ceeb5ed454f7' SECRET_KEY = '3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16' SECRET_LOCK = web3_hash(SECRET_KEY) SWAP_ID = '033102e41346242476b15a3a7966eb5249271025fc7fb0b37ed3fdb4bcce3884' ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY = _make_settings_key( SETTINGS_KEY_ZERO_ADDRESS_OWNERS) ADDRESS_TO_STORE_SWAP_INFO_BY = BasicHandler( name=AtomicSwapHandler().family_name, versions=AtomicSwapHandler()._family_versions[0]).make_address_from_data( data=SWAP_ID) TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS = { 'family_name': AtomicSwapHandler().family_name, 'family_version': AtomicSwapHandler()._family_versions[0], } CURRENT_TIMESTAMP = int(datetime.datetime.now().timestamp()) RANDOM_NODE_PUBLIC_KEY = '039d6881f0a71d05659e1f40b443684b93c7b7c504ea23ea8949ef5216a2236940' RANDOM_PUBLIC_KEY = '8c87d914a6cfeaf027413760ad359b5a56bfe0eda504d879b21872c7dc5b911c' RANDOM_ADDRESS = '1120077212221be0a8723c9d9070a047f0623e2933b30666a251523b071735573a099c' BLOCK_INFO_CONFIG_ADDRESS = CONFIG_ADDRESS
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ------------------------------------------------------------------------ import argparse from sawtooth_sdk.processor.core import TransactionProcessor from remme.tp.atomic_swap import AtomicSwapHandler from remme.tp.pub_key import PubKeyHandler from remme.tp.account import AccountHandler from remme.shared.logging import setup_logging from remme.settings.default import load_toml_with_defaults TP_HANDLERS = [AccountHandler(), PubKeyHandler(), AtomicSwapHandler()] if __name__ == '__main__': config = load_toml_with_defaults( '/config/remme-client-config.toml')['remme']['client'] parser = argparse.ArgumentParser(description='Transaction processor.') parser.add_argument('-v', '--verbosity', type=int, default=2) parser.add_argument('--account', action='store_true') parser.add_argument('--atomic-swap', action='store_true') parser.add_argument('--pubkey', action='store_true') args = parser.parse_args() setup_logging('remme', args.verbosity) processor = TransactionProcessor( url=f'tcp://{ config["validator_ip"] }:{ config["validator_port"] }')
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_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
def test_expire_atomic_swap_before_invalid_withdrawal_by_bot(): """ Case: to expire atomic swap by bot if 48 hasn't been passed from atomic swap initialization timestamp. Expect: invalid transaction error is raised with signer is not the one who opened the swap. error message. """ atomic_swap_close_payload = AtomicSwapExpirePayload(swap_id=SWAP_ID, ) transaction_payload = TransactionPayload() transaction_payload.method = AtomicSwapMethod.EXPIRE 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), ) existing_swap_info_to_expire = AtomicSwapInfo() existing_swap_info_to_expire.swap_id = SWAP_ID existing_swap_info_to_expire.state = AtomicSwapInfo.OPENED existing_swap_info_to_expire.sender_address = BOT_ADDRESS existing_swap_info_to_expire.created_at = CURRENT_TIMESTAMP existing_swap_info_to_expire.is_initiator = True serialized_existing_swap_info_to_expire = existing_swap_info_to_expire.SerializeToString( ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_existing_swap_info_to_expire, BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG, BLOCK_INFO_ADDRESS: SERIALIZED_BLOCK_INFO, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert f'Swap initiator needs to wait 24 hours since timestamp {CURRENT_TIMESTAMP} to withdraw.' == \ str(error.value)
def test_atomic_swap_init_already_taken_id(): """ Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens with already existing swap id. Expect: invalid transaction error is raised with atomic swap id has already been taken 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), ) 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 serialized_swap_info = swap_info.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_swap_info, }) with pytest.raises(InvalidTransaction) as error: AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context) assert 'Atomic swap ID has already been taken, please use a different one.' == str(error.value)