feat: add settlement contract boundary

This commit is contained in:
Dobromir Popov
2026-06-29 02:46:25 +03:00
parent 8900990193
commit e24c2e3cea
7 changed files with 637 additions and 5 deletions

View File

@@ -9,6 +9,7 @@ import urllib.request
from meshnet_gateway.server import GatewayServer
from meshnet_node.server import StubNodeServer
from meshnet_contracts import LocalSolanaContracts
from meshnet_tracker.server import TrackerServer
@@ -237,6 +238,150 @@ def test_tracker_registration_rejects_invalid_payload():
tracker.stop()
def test_tracker_excludes_banned_wallets_from_routes():
"""Tracker refuses route candidates whose wallet is banned on-chain."""
contracts = LocalSolanaContracts()
contracts.registry.submit_stake("wallet-a", 1_000)
contracts.registry.submit_stake("wallet-b", 1_000)
contracts.registry.ban_wallet("wallet-b")
tracker = TrackerServer(contracts=contracts, minimum_stake=100)
tracker_port = tracker.start()
try:
_post_json(
f"http://127.0.0.1:{tracker_port}/v1/nodes/register",
{"endpoint": "http://127.0.0.1:9001", "shard_start": 0, "shard_end": 15,
"hardware_profile": {}, "wallet_address": "wallet-a", "score": 1.0},
)
_post_json(
f"http://127.0.0.1:{tracker_port}/v1/nodes/register",
{"endpoint": "http://127.0.0.1:9002", "shard_start": 16, "shard_end": 31,
"hardware_profile": {}, "wallet_address": "wallet-b", "score": 1.0},
)
try:
_get_json(f"http://127.0.0.1:{tracker_port}/v1/route?model=stub-model")
raise AssertionError("Expected 503 when only banned wallet covers a layer")
except urllib.error.HTTPError as exc:
assert exc.code == 503
body = json.loads(exc.read())
assert "layer 16" in body["error"]
finally:
tracker.stop()
def test_gateway_routes_even_when_compute_node_has_low_stake():
"""Routing is not based on a compute node's token balance."""
contracts = LocalSolanaContracts()
contracts.registry.submit_stake("wallet-a", 1_000)
contracts.registry.submit_stake("wallet-b", 5)
tracker = TrackerServer()
tracker_port = tracker.start()
tracker_url = f"http://127.0.0.1:{tracker_port}"
node_a = StubNodeServer(shard_start=0, shard_end=15, is_last_shard=False)
port_a = node_a.start()
node_b = StubNodeServer(shard_start=16, shard_end=31, is_last_shard=True)
port_b = node_b.start()
_post_json(
f"{tracker_url}/v1/nodes/register",
{"endpoint": f"http://127.0.0.1:{port_a}", "shard_start": 0, "shard_end": 15,
"hardware_profile": {}, "wallet_address": "wallet-a", "score": 1.0},
)
_post_json(
f"{tracker_url}/v1/nodes/register",
{"endpoint": f"http://127.0.0.1:{port_b}", "shard_start": 16, "shard_end": 31,
"hardware_profile": {}, "wallet_address": "wallet-b", "score": 1.0},
)
gateway = GatewayServer(
tracker_url=tracker_url,
contracts=contracts,
minimum_stake=100,
)
gateway_port = gateway.start()
try:
payload = json.dumps({
"model": "stub-model",
"messages": [{"role": "user", "content": "hello"}],
}).encode()
req = urllib.request.Request(
f"http://127.0.0.1:{gateway_port}/v1/chat/completions",
data=payload,
headers={"Content-Type": "application/json", "Authorization": "Bearer api-key-a"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
assert resp.status == 200
assert node_b.received_activations
finally:
gateway.stop()
node_a.stop()
node_b.stop()
tracker.stop()
def test_gateway_records_compute_attribution_after_inference_session():
"""Gateway records layer and token attribution for every routed node."""
contracts = LocalSolanaContracts()
contracts.registry.submit_stake("wallet-a", 1_000)
contracts.registry.submit_stake("wallet-b", 1_000)
contracts.payment.fund_api_key("api-key-a", lamports=10_000)
tracker = TrackerServer(contracts=contracts, minimum_stake=100)
tracker_port = tracker.start()
tracker_url = f"http://127.0.0.1:{tracker_port}"
node_a = StubNodeServer(shard_start=0, shard_end=15, is_last_shard=False)
port_a = node_a.start()
node_b = StubNodeServer(shard_start=16, shard_end=31, is_last_shard=True)
port_b = node_b.start()
_post_json(
f"{tracker_url}/v1/nodes/register",
{"endpoint": f"http://127.0.0.1:{port_a}", "shard_start": 0, "shard_end": 15,
"hardware_profile": {}, "wallet_address": "wallet-a", "score": 1.0},
)
_post_json(
f"{tracker_url}/v1/nodes/register",
{"endpoint": f"http://127.0.0.1:{port_b}", "shard_start": 16, "shard_end": 31,
"hardware_profile": {}, "wallet_address": "wallet-b", "score": 1.0},
)
gateway = GatewayServer(
tracker_url=tracker_url,
contracts=contracts,
minimum_stake=100,
)
gateway_port = gateway.start()
try:
payload = json.dumps({
"model": "stub-model",
"messages": [{"role": "user", "content": "hello"}],
}).encode()
req = urllib.request.Request(
f"http://127.0.0.1:{gateway_port}/v1/chat/completions",
data=payload,
headers={"Content-Type": "application/json", "Authorization": "Bearer api-key-a"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
assert resp.status == 200
records = contracts.payment.list_attributions()
assert [(r.api_key, r.node_wallet, r.layer_start, r.layer_end, r.tokens) for r in records] == [
("api-key-a", "wallet-a", 0, 15, 1),
("api-key-a", "wallet-b", 16, 31, 1),
]
finally:
gateway.stop()
node_a.stop()
node_b.stop()
tracker.stop()
def test_gateway_returns_json_503_when_tracker_unavailable():
"""Tracker-backed gateway failures are reported as JSON HTTP errors."""
gateway = GatewayServer(tracker_url="http://127.0.0.1:9")