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

Add more integration tests #947

Merged
merged 7 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[flake8]
max-line-length = 88
extend-ignore = E501
exclude = ./*migrations*.py
exclude = ./*migrations*.py,./api/nick_generator/nick_generator.py
75 changes: 0 additions & 75 deletions .github/workflows/codeql-client.yml

This file was deleted.

74 changes: 0 additions & 74 deletions .github/workflows/codeql-coordinator.yml

This file was deleted.

1 change: 0 additions & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ jobs:
- name: Patch Dockerfile and .env-sample
run: |
sed -i "1s/FROM python:.*/FROM python:${{ matrix.python-tag }}/" Dockerfile
sed -i '/RUN pip install --no-cache-dir -r requirements.txt/a COPY requirements_dev.txt .\nRUN pip install --no-cache-dir -r requirements_dev.txt' Dockerfile
sed -i "s/^LNVENDOR=.*/LNVENDOR='${{ matrix.ln-vendor }}'/" .env-sample

- uses: satackey/[email protected]
Expand Down
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
FROM python:3.11.6-slim-bookworm
ARG DEBIAN_FRONTEND=noninteractive
ARG DEVELOPMENT=False

RUN mkdir -p /usr/src/robosats
WORKDIR /usr/src/robosats
Expand All @@ -17,6 +18,11 @@ RUN python -m pip install --upgrade pip
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY requirements_dev.txt ./
RUN if [ "$DEVELOPMENT" = "true" ]; then \
pip install --no-cache-dir -r requirements_dev.txt; \
fi

# copy current dir's content to container's WORKDIR root i.e. all the contents of the robosats app
COPY . .

Expand Down
8 changes: 8 additions & 0 deletions api/lightning/cln.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ def get_info(cls):
except Exception as e:
print(f"Cannot get CLN node id: {e}")

@classmethod
def newaddress(cls):
"""Only used on tests to fund the regtest node"""
nodestub = node_pb2_grpc.NodeStub(cls.node_channel)
request = node_pb2.NewaddrRequest()
response = nodestub.NewAddr(request)
return response.bech32

@classmethod
def decode_payreq(cls, invoice):
"""Decodes a lightning payment request (invoice)"""
Expand Down
3 changes: 2 additions & 1 deletion api/lightning/lnd.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@ def estimate_fee(cls, amount_sats, target_conf=2, min_confs=1):
lightningstub = lightning_pb2_grpc.LightningStub(cls.channel)
request = lightning_pb2.GetInfoRequest()
response = lightningstub.GetInfo(request)
log("lightning_pb2_grpc.GetInfo", request, response)

if response.testnet:
dummy_address = "tb1qehyqhruxwl2p5pt52k6nxj4v8wwc3f3pg7377x"
elif response.chains[0].network == "regtest":
dummy_address = "bcrt1q3w8xja7knmycsglnxg2xzjq8uv9u7jdwau25nl"
else:
dummy_address = "bc1qgxwaqe4m9mypd7ltww53yv3lyxhcfnhzzvy5j3"
# We assume segwit. Use hardcoded address as shortcut so there is no need of user inputs yet.
Expand Down
10 changes: 7 additions & 3 deletions api/logics.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,9 @@ def payout_amount(cls, order, user):
return True, context

context["swap_allowed"] = True
context["suggested_mining_fee_rate"] = order.payout_tx.suggested_mining_fee_rate
context["suggested_mining_fee_rate"] = float(
order.payout_tx.suggested_mining_fee_rate
)
context["swap_fee_rate"] = order.payout_tx.swap_fee_rate

return True, context
Expand Down Expand Up @@ -1915,7 +1917,9 @@ def summarize_trade(cls, order, user):
else:
summary["received_sats"] = order.payout.num_satoshis
summary["payment_hash"] = order.payout.payment_hash
summary["preimage"] = order.payout.preimage
summary["preimage"] = (
order.payout.preimage if order.payout.preimage else "processing"
)
summary["trade_fee_sats"] = round(
order.last_satoshis
- summary["received_sats"]
Expand Down Expand Up @@ -1959,7 +1963,7 @@ def summarize_trade(cls, order, user):
order.save(update_fields=["contract_finalization_time"])
platform_summary["contract_total_time"] = (
order.contract_finalization_time - order.last_satoshis_time
)
).total_seconds()
if not order.is_swap:
platform_summary["routing_budget_sats"] = order.payout.routing_budget_sats
platform_summary["trade_revenue_sats"] = int(
Expand Down
2 changes: 0 additions & 2 deletions api/nick_generator/nick_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ def compute_pool_size_loss(self, max_length=22, max_iter=1_000_000, num_runs=500

attempts = []
for i in range(num_runs):

string = str(random.uniform(0, 1_000_000))
hash = hashlib.sha256(str.encode(string)).hexdigest()

Expand All @@ -179,7 +178,6 @@ def compute_pool_size_loss(self, max_length=22, max_iter=1_000_000, num_runs=500


if __name__ == "__main__":

# Just for code timming
t0 = time.time()

Expand Down
46 changes: 39 additions & 7 deletions api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,24 @@ class Meta:

# Only used in oas_schemas
class SummarySerializer(serializers.Serializer):
sent_fiat = serializers.IntegerField(
sent_fiat = serializers.FloatField(
required=False, help_text="same as `amount` (only for buyer)"
)
received_fiat = serializers.FloatField(
required=False, help_text="same as `amount` (only for seller)"
)
sent_sats = serializers.IntegerField(
required=False, help_text="The total sats you sent (only for seller)"
)
received_sats = serializers.IntegerField(
required=False, help_text="same as `trade_satoshis` (only for buyer)"
)
is_swap = serializers.BooleanField(
required=False, help_text="True if the payout was on-chain (only for buyer)"
)
is_buyer = serializers.BooleanField(
required=False, help_text="True if the robot is the order buyer"
)
received_onchain_sats = serializers.IntegerField(
required=False,
help_text="The on-chain sats received (only for buyer and if `is_swap` is `true`)",
Expand All @@ -109,15 +118,26 @@ class SummarySerializer(serializers.Serializer):
required=False,
help_text="same as `swap_fee_rate` (only for buyer and if `is_swap` is `true`",
)
sent_sats = serializers.IntegerField(
required=False, help_text="The total sats you sent (only for seller)"
bond_size_sats = serializers.IntegerField(
required=False, help_text="The amount of Satoshis at stake"
)
received_fiat = serializers.IntegerField(
required=False, help_text="same as `amount` (only for seller)"
bond_size_percent = serializers.FloatField(
required=False, help_text="The relative size of Satoshis at stake"
)
trade_fee_sats = serializers.IntegerField(
required=False,
help_text="Exchange fees in sats (Does not include swap fee and miner fee)",
help_text="Exchange fees in sats (does not include swap fee and miner fee)",
)
trade_fee_percent = serializers.FloatField(
required=False,
help_text="Exchange fees in percent (does not include swap fee and miner fee)",
)
payment_hash = serializers.CharField(
required=False, help_text="The payment_hash of the payout invoice"
)
preimage = serializers.CharField(
required=False,
help_text="The preimage of the payout invoice (proof of payment)",
)


Expand All @@ -138,6 +158,13 @@ class PlatformSummarySerializer(serializers.Serializer):
trade_revenue_sats = serializers.IntegerField(
required=False, help_text="The sats the exchange earned from the trade"
)
routing_budget_sats = serializers.FloatField(
required=False, help_text="The budget allocated for routing costs in Satoshis"
)
contract_exchange_rate = serializers.FloatField(
required=False,
help_text="The exchange rate applied to this contract. Taken from externals APIs exactly when the taker bond was locked.",
)


# Only used in oas_schemas
Expand Down Expand Up @@ -271,7 +298,7 @@ class OrderDetailSerializer(serializers.ModelSerializer):
swap_failure_reason = serializers.CharField(
required=False, help_text="Reason for why on-chain swap is not available"
)
suggested_mining_fee_rate = serializers.IntegerField(
suggested_mining_fee_rate = serializers.FloatField(
required=False, help_text="fee in sats/vbyte for the on-chain swap"
)
swap_fee_rate = serializers.FloatField(
Expand Down Expand Up @@ -350,6 +377,10 @@ class OrderDetailSerializer(serializers.ModelSerializer):
required=False,
help_text="The network eg. 'testnet', 'mainnet'. Only if status = `14` (Successful Trade) and is_buyer = `true`",
)
chat_last_index = serializers.IntegerField(
required=False,
help_text="The index of the last message sent in the trade chatroom",
)

class Meta:
model = Order
Expand Down Expand Up @@ -431,6 +462,7 @@ class Meta:
"network",
"latitude",
"longitude",
"chat_last_index",
)


Expand Down
4 changes: 2 additions & 2 deletions api/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ def test_weighted_median(self):

def test_validate_pgp_keys(self):
# Example test client generated GPG keys
client_pub_key = r"-----BEGIN PGP PUBLIC KEY BLOCK-----\\xjMEZTWJ1xYJKwYBBAHaRw8BAQdAsfdKb90BurKniu+pBPBDHCkzg08S51W0\mUR0SKqLmdjNTFJvYm9TYXRzIElEIDU1MmRkMWE2NjFhN2FjYTRhNDFmODg5\MTBmZjM0YWMzYjFhYzgwYmI3Nzk0ZWQ5ZmQ1NWQ4Yjc2Yjk3YWFkOTfCjAQQ\FgoAPgWCZTWJ1wQLCQcICZA3N7au4gi/zgMVCAoEFgACAQIZAQKbAwIeARYh\BO5iBLnj0J/E6sntEDc3tq7iCL/OAADkVwEA/tBt9FPqrxLHOPFtyUypppr0\/t6vrl3RrLzCLqqE1nUA/0fmhir2F88KcsxmCJwADo/FglwXGFkjrV4sP6Fj\YBEBzjgEZTWJ1xIKKwYBBAGXVQEFAQEHQCyUIe3sQTaYa/IFNKGNmXz/+hrH\ukcot4TOvi2bD9p8AwEIB8J4BBgWCAAqBYJlNYnXCZA3N7au4gi/zgKbDBYh\BO5iBLnj0J/E6sntEDc3tq7iCL/OAACaFAD7BG3E7TkUoWKtJe5OPzTwX+bM\Xy7hbPSQw0zM9Re8KP0BAIeTG8d280dTK63h/seQAKeMj0zf7AYXr0CscvS7\f38D\=h03E\-----END PGP PUBLIC KEY BLOCK-----"
client_enc_priv_key = r"-----BEGIN PGP PRIVATE KEY BLOCK-----\\xYYEZTWJ1xYJKwYBBAHaRw8BAQdAsfdKb90BurKniu+pBPBDHCkzg08S51W0\mUR0SKqLmdj+CQMICrS3TNCA/LHgxckC+iTUMxkqQJ9GpXWCDacx1rBQCztu\PDgUHNvWdcvW1wWVxU/aJaQLqBTtRVYkJTz332jrKvsSl/LnrfwmUfKgN4nG\Oc1MUm9ib1NhdHMgSUQgNTUyZGQxYTY2MWE3YWNhNGE0MWY4ODkxMGZmMzRh\YzNiMWFjODBiYjc3OTRlZDlmZDU1ZDhiNzZiOTdhYWQ5N8KMBBAWCgA+BYJl\NYnXBAsJBwgJkDc3tq7iCL/OAxUICgQWAAIBAhkBApsDAh4BFiEE7mIEuePQ\n8Tqye0QNze2ruIIv84AAORXAQD+0G30U+qvEsc48W3JTKmmmvT+3q+uXdGs\vMIuqoTWdQD/R+aGKvYXzwpyzGYInAAOj8WCXBcYWSOtXiw/oWNgEQHHiwRl\NYnXEgorBgEEAZdVAQUBAQdALJQh7exBNphr8gU0oY2ZfP/6Gse6Ryi3hM6+\LZsP2nwDAQgH/gkDCPPoYWyzm4mT4N/TDBF11GVq0xSEEcubFqjArFKyibRy\TDnB8+o8BlkRuGClcfRyKkR5/Rp1v5B0n1BuMsc8nY4Yg4BJv4KhsPfXRp4m\31zCeAQYFggAKgWCZTWJ1wmQNze2ruIIv84CmwwWIQTuYgS549CfxOrJ7RA3\N7au4gi/zgAAmhQA+wRtxO05FKFirSXuTj808F/mzF8u4Wz0kMNMzPUXvCj9\AQCHkxvHdvNHUyut4f7HkACnjI9M3+wGF69ArHL0u39/Aw==\=1hCT\-----END PGP PRIVATE KEY BLOCK-----"
client_pub_key = r"-----BEGIN PGP PUBLIC KEY BLOCK-----\\mDMEZVO9bxYJKwYBBAHaRw8BAQdAVyePBQK63FB2r5ZpIqO998WaqZjmro+LFNH+\sw2raQC0TFJvYm9TYXRzIElEIGVkN2QzYjJiMmU1ODlhYjI2NzIwNjA1ZTc0MTRh\YjRmYmNhMjFjYjRiMzFlNWI0ZTYyYTZmYTUxYzI0YTllYWKIjAQQFgoAPgWCZVO9\bwQLCQcICZAuNFtLSY2XJAMVCAoEFgACAQIZAQKbAwIeARYhBDIhViOFpzWovPuw\vC40W0tJjZckAACTeAEA+AdXmA8p6I+FFqXaFVRh5JRa5ZoO4xhGb+QY00kgZisB\AJee8XdW6FHBj2J3b4M9AYqufdpvuj+lLmaVAshN9U4MuDgEZVO9bxIKKwYBBAGX\VQEFAQEHQORkbvSesg9oJeCRKigTNdQ5tkgmVGXfdz/+vwBIl3E3AwEIB4h4BBgW\CAAqBYJlU71vCZAuNFtLSY2XJAKbDBYhBDIhViOFpzWovPuwvC40W0tJjZckAABZ\1AD/RIJM/WNb28pYqtq4XmeOaqLCrbQs2ua8mXpGBZSl8E0BALWSlbHICYTNy9L6\KV0a5pXbxcXpzejcjpJmVwzuWz8P\=32+r\-----END PGP PUBLIC KEY BLOCK-----"
client_enc_priv_key = r"-----BEGIN PGP PRIVATE KEY BLOCK-----\\xYYEZVO9bxYJKwYBBAHaRw8BAQdAVyePBQK63FB2r5ZpIqO998WaqZjmro+L\FNH+sw2raQD+CQMIHkZZZnDa6d/gHioGTKf6JevirkCBWwz8tFLGFs5DFwjD\tI4ew9CJd09AUxfMq2WvTilhMNrdw2nmqtmAoaIyIo43azVT1VQoxSDnWxFv\Tc1MUm9ib1NhdHMgSUQgZWQ3ZDNiMmIyZTU4OWFiMjY3MjA2MDVlNzQxNGFi\NGZiY2EyMWNiNGIzMWU1YjRlNjJhNmZhNTFjMjRhOWVhYsKMBBAWCgA+BYJl\U71vBAsJBwgJkC40W0tJjZckAxUICgQWAAIBAhkBApsDAh4BFiEEMiFWI4Wn\Nai8+7C8LjRbS0mNlyQAAJN4AQD4B1eYDynoj4UWpdoVVGHklFrlmg7jGEZv\5BjTSSBmKwEAl57xd1boUcGPYndvgz0Biq592m+6P6UuZpUCyE31TgzHiwRl\U71vEgorBgEEAZdVAQUBAQdA5GRu9J6yD2gl4JEqKBM11Dm2SCZUZd93P/6/\AEiXcTcDAQgH/gkDCGSRul0JyboW4JZSQVlHNVlx2mrfE1gRTh2R5hJWU9Kg\aw2gET8OwWDYU4F8wKTo/s7BGn+HN4jrZeLw1k/etKUKLzuPC06KUXhj3rMF\Ti3CeAQYFggAKgWCZVO9bwmQLjRbS0mNlyQCmwwWIQQyIVYjhac1qLz7sLwu\NFtLSY2XJAAAWdQA/0SCTP1jW9vKWKrauF5njmqiwq20LNrmvJl6RgWUpfBN\AQC1kpWxyAmEzcvS+ildGuaV28XF6c3o3I6SZlcM7ls/Dw==\=YAfZ\-----END PGP PRIVATE KEY BLOCK-----"

# Example valid formatted GPG keys
with open("tests/robots/1/pub_key", "r") as file:
Expand Down
2 changes: 1 addition & 1 deletion api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ def get(self, request, format=None):
Order.Status.FAI,
]:
data["public_duration"] = order.public_duration
data["bond_size"] = order.bond_size
data["bond_size"] = str(order.bond_size)

# Adds trade summary
if order.status in [Order.Status.SUC, Order.Status.PAY, Order.Status.FAI]:
Expand Down
3 changes: 3 additions & 0 deletions control/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ def get_ln_remote_unsettled():
def __str__(self):
return f"Balance at {self.time.strftime('%d/%m/%Y %H:%M:%S')}"

class Meta:
get_latest_by = "time"


class Dispute(models.Model):
pass
Loading
Loading