Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Atomic Swap public key #20

Merged
merged 6 commits into from
May 2, 2019
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,23 @@ $ remme account transfer-tokens \
}
```

### Atomic Swap

Get public key of atomic swap — ``remme atomic-swap get-public-key``:

| Arguments | Type | Required | Description |
| :-------: | :----: | :------: | ------------------------------- |
| node-url | String | No | Node URL to apply a command to. |

```bash
$ remme atomic-swap get-public-key --node-url=node-6-testnet.remme.io
{
"result": {
"public_key": "03738df3f4ac3621ba8e89413d3ff4ad036c3a0a4dbb164b695885aab6aab614ad"
}
}
```

### Node

Get node configurations — ``remme node get-configs``:
Expand Down
Empty file added cli/atomic_swap/__init__.py
Empty file.
56 changes: 56 additions & 0 deletions cli/atomic_swap/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""
Provide implementation of the command line interface's atomic swap commands.
"""
import sys

import click
from remme import Remme

from cli.atomic_swap.forms import GetPublicKeyForm
from cli.atomic_swap.service import AtomicSwap
from cli.constants import (
FAILED_EXIT_FROM_COMMAND_CODE,
NODE_URL_ARGUMENT_HELP_MESSAGE,
)
from cli.utils import (
default_node_url,
print_errors,
print_result,
)


@click.group('atomic-swap', chain=True)
def atomic_swap_commands():
"""
Provide commands for working with atomic swap.
"""
pass


@click.option('--node-url', type=str, required=False, help=NODE_URL_ARGUMENT_HELP_MESSAGE, default=default_node_url())
@atomic_swap_commands.command('get-public-key')
def get_public_key(node_url):
"""
Get public key of atomic swap.
"""
arguments, errors = GetPublicKeyForm().load({
'node_url': node_url,
})

if errors:
print_errors(errors=errors)
sys.exit(FAILED_EXIT_FROM_COMMAND_CODE)

node_url = arguments.get('node_url')

remme = Remme(network_config={
'node_address': str(node_url) + ':8080',
})

result, errors = AtomicSwap(service=remme).get_public_key()

if errors is not None:
print_errors(errors=errors)
sys.exit(FAILED_EXIT_FROM_COMMAND_CODE)

print_result(result=result)
14 changes: 14 additions & 0 deletions cli/atomic_swap/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""
Provide forms for command line interface's atomic swap commands.
"""
from marshmallow import Schema

from cli.generic.forms.fields import NodeURLField


class GetPublicKeyForm(Schema):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetPublicKeyForm > GetAtomicSwapPublicKeyForm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""
Get public key of the atomic swap form.
"""

node_url = NodeURLField(allow_none=True, required=False)
3 changes: 3 additions & 0 deletions cli/atomic_swap/help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Provide help messages for command line interface's atomic swap commands.
"""
15 changes: 15 additions & 0 deletions cli/atomic_swap/interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Provide implementation of the atomic swap interfaces.
"""


class AtomicSwapInterface:
"""
Implements atomic swap interface.
"""

def get_public_key(self):
"""
Get public key of atomic swap.
"""
pass
40 changes: 40 additions & 0 deletions cli/atomic_swap/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
Provide implementation of the atomic swap.
"""
import asyncio

from accessify import implements

from cli.atomic_swap.interfaces import AtomicSwapInterface

loop = asyncio.get_event_loop()


@implements(AtomicSwapInterface)
class AtomicSwap:
"""
Implements atomic swap.
"""

def __init__(self, service):
"""
Constructor.

Arguments:
service: object to interact with Remme core API.
"""
self.service = service

def get_public_key(self):
"""
Get public key of atomic swap.
"""
try:
public_key = loop.run_until_complete(self.service.swap.get_public_key())

except Exception as error:
return None, str(error)

return {
'public_key': public_key,
}, None
3 changes: 3 additions & 0 deletions cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
ADDRESS_REGEXP = r'^[0-9a-f]{70}$'
BATCH_ID_REGEXP = r'^[0-9a-f]{128}$'
PRIVATE_KEY_REGEXP = r'^[a-f0-9]{64}$'
PUBLIC_KEY_REGEXP = r'^[0-9a-f]{66}$'
HEADER_SIGNATURE_REGEXP = r'^[0-9a-f]{128}$'
DOMAIN_NAME_REGEXP = r'(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]'

Expand All @@ -16,7 +17,9 @@
CLI_CONFIG_FILE_NAME = 'remme-core-cli'

NODE_IP_ADDRESS_FOR_TESTING = '159.89.104.9'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LATEST_RELEASE_NODE_IP_ADDRESS_FOR_TESTING = '165.22.75.163'
RELEASE_0_9_0_ALPHA_NODE_ADDRESS = '165.227.169.119'
NODE_27_IN_TESTNET_ADDRESS = 'node-27-testnet.remme.io'

PRIVATE_KEY_FOR_TESTING = 'b03e31d2f310305eab249133b53b5fb3270090fc1692c9b022b81c6b9bb6029b'
2 changes: 2 additions & 0 deletions cli/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import click

from cli.account.cli import account_commands
from cli.atomic_swap.cli import atomic_swap_commands
from cli.node.cli import node_commands
from cli.public_key.cli import public_key_commands

Expand All @@ -19,5 +20,6 @@ def cli():


cli.add_command(account_commands)
cli.add_command(atomic_swap_commands)
cli.add_command(node_commands)
cli.add_command(public_key_commands)
Empty file added tests/atomic_swap/__init__.py
Empty file.
164 changes: 164 additions & 0 deletions tests/atomic_swap/test_get_public_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
Provide tests for command line interface's get public key of the atomic swap commands.
"""
import json
import re

from click.testing import CliRunner

from cli.constants import (
FAILED_EXIT_FROM_COMMAND_CODE,
NODE_27_IN_TESTNET_ADDRESS,
PASSED_EXIT_FROM_COMMAND_CODE,
PUBLIC_KEY_REGEXP,
)
from cli.entrypoint import cli
from cli.utils import dict_to_pretty_json


def test_get_public_key():
"""
Case: get the public key of atomic swap.
Expect: public key is returned.
"""
runner = CliRunner()
result = runner.invoke(cli, [
'atomic-swap',
'get-public-key',
'--node-url',
NODE_27_IN_TESTNET_ADDRESS,
])

public_key = json.loads(result.output).get('result').get('public_key')

assert PASSED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert re.match(pattern=PUBLIC_KEY_REGEXP, string=public_key) is not None


def test_get_public_key_without_node_url(mocker):
"""
Case: get the public key of atomic swap without passing node URL.
Expect: public key is returned from node on localhost.
"""
public_key = '03738df3f4ac3621ba8e89413d3ff4ad036c3a0a4dbb164b695885aab6aab614ad'
mock_swap_get_public_key = mocker.patch('cli.node.service.loop.run_until_complete')
mock_swap_get_public_key.return_value = public_key

runner = CliRunner()
result = runner.invoke(cli, [
'atomic-swap',
'get-public-key',
])

expected_result = {
'result': {
'public_key': public_key,
},
}

assert PASSED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert expected_result == json.loads(result.output)


def test_get_public_key_invalid_node_url():
"""
Case: get the public key of atomic swap by passing invalid node URL.
Expect: the following node URL is invalid error message.
"""
invalid_node_url = 'domainwithoutextention'

runner = CliRunner()
result = runner.invoke(cli, [
'atomic-swap',
'get-public-key',
'--node-url',
invalid_node_url,
])

expected_error = {
'errors': {
'node_url': [
f'The following node URL `{invalid_node_url}` is invalid.',
],
},
}

assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert dict_to_pretty_json(expected_error) in result.output


def test_get_public_key_node_url_with_http():
"""
Case: get the public key of atomic swap by passing node URL with explicit HTTP protocol.
Expect: the following node URL contains protocol error message.
"""
node_url_with_http_protocol = 'http://masternode.com'

runner = CliRunner()
result = runner.invoke(cli, [
'atomic-swap',
'get-public-key',
'--node-url',
node_url_with_http_protocol,
])

expected_error = {
'errors': {
'node_url': [
f'Pass the following node URL `{node_url_with_http_protocol}` without protocol (http, https, etc.).',
],
},
}

assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert dict_to_pretty_json(expected_error) in result.output


def test_get_public_key_node_url_with_https():
"""
Case: get the public key of atomic swap by passing node URL with explicit HTTPS protocol.
Expect: the following node URL contains protocol error message.
"""
node_url_with_https_protocol = 'https://masternode.com'

runner = CliRunner()
result = runner.invoke(cli, [
'atomic-swap',
'get-public-key',
'--node-url',
node_url_with_https_protocol,
])

expected_error = {
'errors': {
'node_url': [
f'Pass the following node URL `{node_url_with_https_protocol}` without protocol (http, https, etc.).',
],
},
}

assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert dict_to_pretty_json(expected_error) in result.output


def test_get_public_key_non_existing_node_url():
"""
Case: get the public key of atomic swap by passing non existing node URL.
Expect: check if node running at URL error message.
"""
non_existing_node_url = 'non-existing-node.com'

runner = CliRunner()
result = runner.invoke(cli, [
'atomic-swap',
'get-public-key',
'--node-url',
non_existing_node_url,
])

expected_error = {
'errors': f'Please check if your node running at http://{non_existing_node_url}:8080.',
}

assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert dict_to_pretty_json(expected_error) in result.output
8 changes: 4 additions & 4 deletions tests/node/test_get_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

from cli.constants import (
FAILED_EXIT_FROM_COMMAND_CODE,
NODE_27_IN_TESTNET_ADDRESS,
PASSED_EXIT_FROM_COMMAND_CODE,
RELEASE_0_9_0_ALPHA_NODE_ADDRESS,
)
from cli.entrypoint import cli
from cli.utils import dict_to_pretty_json
Expand All @@ -24,14 +24,14 @@ def test_get_node_configs():
'node',
'get-configs',
'--node-url',
RELEASE_0_9_0_ALPHA_NODE_ADDRESS,
NODE_27_IN_TESTNET_ADDRESS,
])

expected_node_configurations = {
'result': {
'configurations': {
'node_address': '116829f18683f6c30146559c9cb8d5d302545019ff00f2ab72500df99bceb7b81a1dad',
'node_public_key': '0350e9cf23966ad404dc56438fd01ec11a913446cfd7c4fb8d95586a58718431e7',
'node_address': '116829d8293c29cbced8aa4dba6ed29d979c2af6784d8aa9b4120d6c141c0153da7733',
'node_public_key': '03d4613540ce29cd1f5f28ea9169a5cb5853bd53dede635903af9383bc9ffaf079',
},
},
}
Expand Down