Add ONS tests

This commit is contained in:
Jason Rhinelander 2023-05-01 20:59:21 -03:00
parent 67e1e6b364
commit 219bdab285
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
2 changed files with 519 additions and 0 deletions

449
tests/ledger/test_ons.py Normal file
View File

@ -0,0 +1,449 @@
import pytest
from functools import partial
from utils import *
from expected import *
import daemons
ONS_BASE_FEE = 7
def test_ons_buy(net, mike, hal, ledger):
mike.transfer(hal, coins(10))
net.mine()
assert hal.balances(refresh=True) == coins(10, 10)
store_fee = [StoreFee() for _ in range(3)]
run_with_interactions(
ledger,
partial(
hal.buy_ons,
"session",
"testsession",
"05ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
backup_owner="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee[0], fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
ExactScreen(["Processing ONS"]),
)
mike.transfer(hal, coins(10))
net.mine()
assert hal.balances(refresh=True) == balance(20 - store_fee[0].fee)
run_with_interactions(
ledger,
partial(hal.buy_ons, "wallet", "testwallet", mike.address()),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee[1], fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
mike.transfer(hal, coins(50))
net.mine()
assert hal.balances(refresh=True) == balance(70 - store_fee[0].fee - store_fee[1].fee)
run_with_interactions(
ledger,
partial(
hal.buy_ons,
"lokinet_10y",
"test.loki",
"yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({6*ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee[2], fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
net.mine()
assert hal.balances(refresh=True) == balance(70 - sum(s.fee for s in store_fee))
assert hal.get_ons() == [
{
"type": "lokinet",
"name": "test.loki",
"hashed": "onTp6G7+2UEwBMEPjK149gY5phWt6SbhgkQYD5DBMXU=",
"value": "yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
"owner": hal.address(),
},
{
"type": "session",
"name": "testsession",
"hashed": "IcWqJAa2t5u4WMgDu6c6O1GvbI80r/GLUCVBZ8P/UlQ=",
"value": "05ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"owner": hal.address(),
"backup_owner": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
},
{
"type": "wallet",
"name": "testwallet",
"hashed": "bFhh6FtiV16PT3twIllC8zyxU3E2sS0AilOkcv69WB8=",
"value": mike.address(),
"owner": hal.address(),
},
]
def test_ons_update(net, mike, hal, ledger):
mike.buy_ons(
"session",
"testsession",
"05ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
backup_owner=hal.address(),
)
mike.buy_ons("wallet", "testwallet", mike.address(), backup_owner=hal.address())
mike.transfer(hal, coins(ONS_BASE_FEE + 1))
for _ in range(5):
mike.refresh()
mike.transfer(hal, coins(1))
net.mine(3)
net.mine(6)
mike.buy_ons(
"lokinet_10y",
"test.loki",
"yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
backup_owner=hal.address(),
)
net.mine(1)
hal.refresh()
run_with_interactions(
ledger,
partial(
hal.buy_ons,
"session",
"another",
"05aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
),
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", rf"^{ONS_BASE_FEE}\.\d{{1,9}}$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
net.mine(1)
# ONS has a bug where you can't *clear* a backup owner, nor can you set both owner and
# backup_owner to yourself, so we stuff in this dummy backup_owner in lieu of being able to
# clear it:
no_backup = "0000000000000000000000000000000000000000000000000000000000000000"
run_with_interactions(
ledger,
partial(
hal.update_ons,
"session",
"testsession",
value="05eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
owner=hal.address(),
backup_owner=no_backup,
),
ExactScreen(["Confirm Oxen", "Name Service TX"]),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", r"^0\.\d{1,9}$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
run_with_interactions(
ledger,
partial(
hal.update_ons,
"wallet",
"testwallet",
value=hal.address(),
owner=hal.address(),
backup_owner=no_backup,
),
ExactScreen(["Confirm Oxen", "Name Service TX"]),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", r"^0\.\d{1,9}$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
run_with_interactions(
ledger,
partial(
hal.update_ons,
"lokinet",
"test.loki",
value="444444444444444444444444444444444444444444444444444o.loki",
),
ExactScreen(["Confirm Oxen", "Name Service TX"]),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", r"^0\.\d{1,9}$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
run_with_interactions(
ledger,
partial(
hal.update_ons,
"session",
"another",
value="051234123412341234123412341234123412341234123412341234123412341234",
backup_owner="2222333322223333222233332222333322223333222233332222333322223333",
),
ExactScreen(["Confirm Oxen", "Name Service TX"]),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", r"^0\.\d{1,9}$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
net.mine(1)
hal.refresh()
assert hal.get_ons() == [
{
"type": "lokinet",
"name": "test.loki",
"hashed": "onTp6G7+2UEwBMEPjK149gY5phWt6SbhgkQYD5DBMXU=",
"value": "444444444444444444444444444444444444444444444444444o.loki",
"owner": mike.address(),
"backup_owner": hal.address(),
},
{
"type": "session",
"name": "another",
"hashed": "ZvuFxErXKyzGIPhiXjlxOLADdwaG/APS6AH+Qq4Bw0o=",
"value": "051234123412341234123412341234123412341234123412341234123412341234",
"owner": hal.address(),
"backup_owner": "2222333322223333222233332222333322223333222233332222333322223333",
},
{
"type": "session",
"name": "testsession",
"hashed": "IcWqJAa2t5u4WMgDu6c6O1GvbI80r/GLUCVBZ8P/UlQ=",
"value": "05eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"owner": hal.address(),
},
{
"type": "wallet",
"name": "testwallet",
"hashed": "bFhh6FtiV16PT3twIllC8zyxU3E2sS0AilOkcv69WB8=",
"value": hal.address(),
"owner": hal.address(),
},
]
def test_ons_renew(net, mike, hal, ledger):
for _ in range(5):
mike.transfer(hal, coins(50))
net.mine(1)
net.mine(9)
bal = 250
assert hal.balances(refresh=True) == balance(bal)
store_fee = StoreFee()
run_with_interactions(
ledger,
partial(
hal.buy_ons,
"lokinet_2y",
"test.loki",
"yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({2*ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee, fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
bal -= store_fee.fee
net.mine(1)
reg_height = net.nodes[0].height() - 1
# On regtest our 1/2/5/10-year expiries become 2/4/10/20 *blocks* for expiry testing purposes
exp_height = reg_height + 4
assert hal.get_ons(include_height=True) == [
{
"type": "lokinet",
"name": "test.loki",
"hashed": "onTp6G7+2UEwBMEPjK149gY5phWt6SbhgkQYD5DBMXU=",
"value": "yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
"owner": hal.address(),
"update_height": reg_height,
"expiration_height": exp_height,
}
]
run_with_interactions(
ledger,
partial(hal.renew_ons, "lokinet_5y", "test.loki"),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({4*ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee, fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
bal -= store_fee.fee
net.mine(1)
hal.refresh()
run_with_interactions(
ledger,
partial(hal.renew_ons, "lokinet", "test.loki"),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee, fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
bal -= store_fee.fee
net.mine(2)
assert hal.get_ons(include_height=True) == [
{
"type": "lokinet",
"name": "test.loki",
"hashed": "onTp6G7+2UEwBMEPjK149gY5phWt6SbhgkQYD5DBMXU=",
"value": "yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
"owner": hal.address(),
"update_height": reg_height + 2,
"expiration_height": exp_height + 10 + 2,
}
]
run_with_interactions(
ledger,
partial(hal.renew_ons, "lokinet_10y", "test.loki"),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({6*ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee, fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Processing ONS"]),
)
net.mine(10)
bal -= store_fee.fee
assert hal.balances(refresh=True) == balance(bal)
assert hal.get_ons(include_height=True) == [
{
"type": "lokinet",
"name": "test.loki",
"hashed": "onTp6G7+2UEwBMEPjK149gY5phWt6SbhgkQYD5DBMXU=",
"value": "yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
"owner": hal.address(),
"update_height": reg_height + 4,
"expiration_height": exp_height + 10 + 2 + 20,
}
]
def test_ons_reject(net, mike, hal, ledger):
mike.transfer(hal, coins(100))
net.mine(10)
assert hal.balances(refresh=True) == balance(100)
with pytest.raises(RuntimeError, match=r'.*Fee denied on device\.$'):
run_with_interactions(
ledger,
partial(
hal.buy_ons,
"lokinet_10y",
"test.loki",
"yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
),
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", rf"^({6*ONS_BASE_FEE}\.\d{{1,9}})$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.both,
)
store_fee = StoreFee()
run_with_interactions(
ledger,
partial(
hal.buy_ons,
"lokinet_10y",
"test.loki",
"yoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyoyo.loki",
),
ExactScreen(["Processing ONS"]),
MatchScreen(
[r"^Confirm ONS Fee$", rf"^({6*ONS_BASE_FEE}\.\d{{1,9}})$"], store_fee, fail_index=1
),
Do.right,
ExactScreen(["Accept"]),
Do.both,
)
net.mine(10)
hal.refresh()
with pytest.raises(RuntimeError, match=r'.*Fee denied on device\.$'):
run_with_interactions(
ledger,
partial(hal.renew_ons, "lokinet_5y", "test.loki"),
ExactScreen(["Processing ONS"]),
MatchScreen([r"^Confirm ONS Fee$", rf"^({4*ONS_BASE_FEE}\.\d{{1,9}})$"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.both,
)
assert hal.balances(refresh=True) == balance(100 - store_fee.fee)
net.mine(1)
assert hal.balances(refresh=True) == balance(100 - store_fee.fee)

View File

@ -479,3 +479,73 @@ class Wallet(RPCDaemon):
raise RuntimeError(f"Failed to submit unstake: {r['error']['message']}")
if not r["result"]["unlocked"]:
raise RuntimeError(f"Failed to submit unstake: {r['result']['msg']}")
def buy_ons(self, onstype, name, value, *, owner=None, backup_owner=None):
if onstype not in (
"session",
"wallet",
"lokinet",
"lokinet_2y",
"lokinet_5y",
"lokinet_10y",
):
raise ValueError(f"Invalid ONS type '{onstype}'")
params = {
"type": onstype,
"owner": self.address() if owner is None else owner,
"name": name,
"value": value,
}
if backup_owner:
params["backup_owner"] = backup_owner
r = self.json_rpc("ons_buy_mapping", params).json()
if "error" in r:
raise RuntimeError(f"Failed to buy ONS: {r['error']['message']}")
return r
def renew_ons(self, onstype, name):
if onstype not in ("lokinet", "lokinet_2y", "lokinet_5y", "lokinet_10y"):
raise ValueError(f"Invalid ONS renewal type '{onstype}'")
r = self.json_rpc("ons_renew_mapping", {"type": onstype, "name": name}).json()
if "error" in r:
raise RuntimeError(f"Failed to buy ONS: {r['error']['message']}")
return r
def update_ons(self, onstype, name, *, value=None, owner=None, backup_owner=None):
if onstype not in ("session", "wallet", "lokinet"):
raise ValueError(f"Invalid ONS update type '{onstype}'")
params = {"type": onstype, "name": name}
if value is not None:
params["value"] = value
if owner is not None:
params["owner"] = owner
if backup_owner is not None:
params["backup_owner"] = backup_owner
r = self.json_rpc("ons_update_mapping", params).json()
if "error" in r:
raise RuntimeError(f"Failed to buy ONS: {r['error']['message']}")
return r
def get_ons(self, *, include_txid=False, include_encrypted=False, include_height=False):
r = self.json_rpc("ons_known_names", {"decrypt": True}).json()
if "error" in r:
raise RuntimeError(f"Failed to buy ONS: {r['error']['message']}")
names = sorted(r["result"]["known_names"], key=lambda x: (x["type"], x["name"]))
if not include_txid:
for n in names:
del n["txid"]
if not include_encrypted:
for n in names:
del n["encrypted_value"]
if not include_height:
for n in names:
del n["update_height"]
n.pop("expiration_height", None)
return names