first commit to cleaning up nym-api tests

This commit is contained in:
benedettadavico
2025-03-24 19:00:12 +01:00
parent edfe29b738
commit 080d75204e
39 changed files with 690 additions and 13298 deletions
@@ -0,0 +1,45 @@
name: Integration Tests
on:
pull_request:
paths:
- "nym-api/**"
- "tests/**"
workflow_dispatch:
jobs:
integration-tests:
runs-on: ubuntu-latest
env:
API_BASE_URL: http://localhost:8000
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev
- name: Build nym-api
run: cargo build --package nym-api
- name: Launch nym-api in background
run: |
./target/debug/nym-api &
- name: Wait for nym-api to become ready
run: |
for i in {1..20}; do
curl -sSf http://localhost:8000/v1/status/config-score-details && break
echo "Waiting for nym-api to start..."
sleep 2
done
- name: Run integration tests
run: cargo test --test public_api_tests -- --nocapture
+1 -1
View File
@@ -169,7 +169,7 @@ generate-typescript:
yarn types:lint:fix
run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa
cargo test --test public-api-tests
# Build debian package, and update PPA
deb-cli: build-nym-cli
-7
View File
@@ -1,7 +0,0 @@
.vscode
node_modules
build
coverage
dist
.cache
jest.config.js
-32
View File
@@ -1,32 +0,0 @@
{
"root": true,
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"rules": {
"import/extensions": "off",
"no-console": ["warn", { "allow": ["warn", "error"] }],
"import/prefer-default-export": "off",
"prettier/prettier": ["error"]
},
"overrides": [
{
"files": ["**/*.ts", "**/*.tsx"],
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["error"]
}
}
]
}
-6
View File
@@ -1,6 +0,0 @@
node_modules
dist
coverage/
.DS_Store
.idea/
junit.xml
@@ -1,29 +0,0 @@
import ContractCache from "../../src/endpoints/CirculatingSupply";
let contract: ContractCache;
describe("Get circulating supply", (): void => {
beforeAll(async (): Promise<void> => {
contract = new ContractCache();
});
it("Get circulating supply amounts", async (): Promise<void> => {
const response = await contract.getCirculatingSupply();
const totalsupply: number = +response.total_supply.amount;
const mixmining: number = +response.mixmining_reserve.amount;
const vest: number = +response.vesting_tokens.amount;
const circsupply: number = +response.circulating_supply.amount;
expect(typeof response.vesting_tokens.amount).toBe("string");
expect(totalsupply - mixmining - vest).toStrictEqual(circsupply);
});
it("Get total supply value", async (): Promise<void> => {
const response = await contract.getTotalSupplyValue();
expect(response).toStrictEqual(1000000000);
});
it("Get circulating supply value", async (): Promise<void> => {
const response = await contract.getCirculatingSupplyValue();
expect(typeof response).toBe("number");
});
});
@@ -1,34 +0,0 @@
import ContractCache from "../../src/endpoints/ContractCache";
let contract: ContractCache;
describe("Get epoch info", (): void => {
beforeAll(async (): Promise<void> => {
contract = new ContractCache();
});
it("Get epoch reward params", async (): Promise<void> => {
const response = await contract.getEpochRewardParams();
expect(typeof response.interval.reward_pool).toBe("string");
expect(typeof response.interval.staking_supply_scale_factor).toBe("string");
expect(typeof response.interval.staking_supply).toBe("string");
expect(typeof response.interval.epoch_reward_budget).toBe("string");
expect(typeof response.interval.stake_saturation_point).toBe("string");
expect(typeof response.interval.sybil_resistance).toBe("string");
expect(typeof response.interval.active_set_work_factor).toBe("string");
expect(typeof response.interval.interval_pool_emission).toBe("string");
expect(typeof response.active_set_size).toBe("number");
expect(typeof response.rewarded_set_size).toBe("number");
});
it("Get current epoch", async (): Promise<void> => {
const response = await contract.getCurrentEpoch();
expect(typeof response.id).toBe("number");
expect(typeof response.epochs_in_interval).toBe("number");
expect(typeof response.current_epoch_id).toBe("number");
expect(typeof response.current_epoch_start).toBe("string");
expect(typeof response.epoch_length.secs).toBe("number");
expect(typeof response.epoch_length.nanos).toBe("number");
expect(typeof response.total_elapsed_epochs).toBe("number");
});
});
@@ -1,49 +0,0 @@
import ContractCache from "../../../src/endpoints/ContractCache";
let contract: ContractCache;
describe("Get gateway data", (): void => {
beforeAll(async (): Promise<void> => {
contract = new ContractCache();
});
it("Get all gateways", async (): Promise<void> => {
const response = await contract.getGateways();
response.forEach((gateway) => {
//overview
expect(typeof gateway.owner).toBe("string");
expect(typeof gateway.block_height).toBe("number");
if (gateway.proxy === null) {
return true;
} else {
expect(typeof gateway.proxy).toBe("string");
}
//pledge_amount
expect(typeof gateway.pledge_amount.denom).toBe("string");
expect(typeof gateway.pledge_amount.amount).toBe("string");
//gateway
expect(typeof gateway.gateway.host).toBe("string");
expect(typeof gateway.gateway.mix_port).toBe("number");
expect(typeof gateway.gateway.clients_port).toBe("number");
expect(typeof gateway.gateway.location).toBe("string");
expect(typeof gateway.gateway.sphinx_key).toBe("string");
expect(typeof gateway.gateway.identity_key).toBe("string");
expect(typeof gateway.gateway.version).toBe("string");
});
});
it("Get blacklisted gateways", async (): Promise<void> => {
const response = await contract.getBlacklistedGateways();
if (response === null) {
// no blacklisted gateways returns an empty array
expect(response).toBeNull();
} else {
response.forEach(function (value) {
expect(typeof value).toBe("string");
});
}
});
});
@@ -1,248 +0,0 @@
import ContractCache from "../../../src/endpoints/ContractCache";
import ConfigHandler from "../../../../../common/api-test-utils/config/configHandler"
let contract: ContractCache;
let config: ConfigHandler;
describe("Get mixnode data", (): void => {
beforeAll(async (): Promise<void> => {
contract = new ContractCache();
config = ConfigHandler.getInstance();
});
it("Get all mixnodes", async (): Promise<void> => {
const response = await contract.getMixnodes();
response.forEach((mixnode) => {
//bond information overview
expect(typeof mixnode.bond_information.mix_id).toBe("number");
expect(typeof mixnode.bond_information.owner).toBe("string");
expect(typeof mixnode.bond_information.original_pledge.amount).toBe(
"string"
);
expect(typeof mixnode.bond_information.original_pledge.denom).toBe(
"string"
);
expect(typeof mixnode.bond_information.layer).toBe("number");
expect(typeof mixnode.bond_information.bonding_height).toBe("number");
expect(typeof mixnode.bond_information.is_unbonding).toBe("boolean");
if (mixnode.bond_information.proxy === null) {
return true;
} else {
expect(typeof mixnode.bond_information.proxy).toBe("string");
}
//mixnode
expect(typeof mixnode.bond_information.mix_node.host).toBe("string");
expect(mixnode.bond_information.mix_node.http_api_port).toStrictEqual(
8000
);
expect(typeof mixnode.bond_information.mix_node.verloc_port).toBe(
"number"
);
expect(typeof mixnode.bond_information.mix_node.mix_port).toBe("number");
expect(mixnode.bond_information.mix_node.mix_port).toStrictEqual(1789);
expect(typeof mixnode.bond_information.mix_node.verloc_port).toBe(
"number"
);
const identitykey = mixnode.bond_information.mix_node.identity_key;
if (typeof identitykey === "string") {
if (identitykey.length === 43) {
return true;
} else expect(identitykey).toHaveLength(44);
}
const sphinx = mixnode.bond_information.mix_node.sphinx_key;
if (typeof sphinx === "string") {
if (sphinx.length === 43) {
return true;
} else expect(sphinx).toHaveLength(44);
}
//rewarding details
expect(
typeof mixnode.rewarding_details.cost_params.profit_margin_percent
).toBe("string");
expect(
typeof mixnode.rewarding_details.cost_params.interval_operating_cost
.denom
).toBe("string");
expect(
typeof mixnode.rewarding_details.cost_params.interval_operating_cost
.amount
).toBe("string");
expect(typeof mixnode.rewarding_details.operator).toBe("string");
expect(typeof mixnode.rewarding_details.delegates).toBe("string");
expect(typeof mixnode.rewarding_details.total_unit_reward).toBe("string");
expect(typeof mixnode.rewarding_details.unit_delegation).toBe("string");
expect(typeof mixnode.rewarding_details.last_rewarded_epoch).toBe(
"number"
);
expect(typeof mixnode.rewarding_details.unique_delegations).toBe(
"number"
);
});
});
it("Get all mixnodes detailed", async (): Promise<void> => {
const response = await contract.getMixnodesDetailed();
response.forEach((mixnode) => {
// overview details
expect(typeof mixnode.estimated_delegators_apy).toBe("string");
expect(typeof mixnode.estimated_operator_apy).toBe("string");
expect(typeof mixnode.performance).toBe("string");
expect(typeof mixnode.uncapped_stake_saturation).toBe("string");
expect(typeof mixnode.stake_saturation).toBe("string");
// TODO why family is tempermental
// expect(typeof mixnode.family).toBe("string");
//mixnode details bond info
expect(typeof mixnode.mixnode_details.bond_information.mix_id).toBe(
"number"
);
expect(typeof mixnode.mixnode_details.bond_information.owner).toBe(
"string"
);
expect(
typeof mixnode.mixnode_details.bond_information.original_pledge.amount
).toBe("string");
expect(
typeof mixnode.mixnode_details.bond_information.original_pledge.denom
).toBe("string");
expect(typeof mixnode.mixnode_details.bond_information.layer).toBe(
"number"
);
expect(
typeof mixnode.mixnode_details.bond_information.bonding_height
).toBe("number");
expect(typeof mixnode.mixnode_details.bond_information.is_unbonding).toBe(
"boolean"
);
if (mixnode.mixnode_details.bond_information.proxy === null) {
return true;
} else {
expect(typeof mixnode.mixnode_details.bond_information.proxy).toBe(
"string"
);
}
//mixnode
expect(
typeof mixnode.mixnode_details.bond_information.mix_node.host
).toBe("string");
expect(
mixnode.mixnode_details.bond_information.mix_node.http_api_port
).toStrictEqual(8000);
expect(
typeof mixnode.mixnode_details.bond_information.mix_node.verloc_port
).toBe("number");
expect(
typeof mixnode.mixnode_details.bond_information.mix_node.mix_port
).toBe("number");
expect(
mixnode.mixnode_details.bond_information.mix_node.mix_port
).toStrictEqual(1789);
expect(
typeof mixnode.mixnode_details.bond_information.mix_node.verloc_port
).toBe("number");
const identitykey2 =
mixnode.mixnode_details.bond_information.mix_node.identity_key;
if (typeof identitykey2 === "string") {
if (identitykey2.length === 43) {
return true;
} else expect(identitykey2).toHaveLength(44);
}
const sphinx2 =
mixnode.mixnode_details.bond_information.mix_node.sphinx_key;
if (typeof sphinx2 === "string") {
if (sphinx2.length === 43) {
return true;
} else expect(sphinx2).toHaveLength(44);
}
//mixnode rewarding info
expect(
typeof mixnode.mixnode_details.rewarding_details.cost_params
.profit_margin_percent
).toBe("string");
expect(
typeof mixnode.mixnode_details.rewarding_details.cost_params
.interval_operating_cost.denom
).toBe("string");
expect(
typeof mixnode.mixnode_details.rewarding_details.cost_params
.interval_operating_cost.amount
).toBe("string");
expect(typeof mixnode.mixnode_details.rewarding_details.operator).toBe(
"string"
);
expect(typeof mixnode.mixnode_details.rewarding_details.delegates).toBe(
"string"
);
expect(
typeof mixnode.mixnode_details.rewarding_details.total_unit_reward
).toBe("string");
expect(
typeof mixnode.mixnode_details.rewarding_details.unit_delegation
).toBe("string");
expect(
typeof mixnode.mixnode_details.rewarding_details.last_rewarded_epoch
).toBe("number");
expect(
typeof mixnode.mixnode_details.rewarding_details.unique_delegations
).toBe("number");
});
});
it("Get active mixnodes", async (): Promise<void> => {
const response = await contract.getActiveMixnodes();
response.forEach(function (mixnode) {
expect(
mixnode.rewarding_details.cost_params.profit_margin_percent
).toBeTruthy();
expect(typeof mixnode.bond_information.layer).toBe("number");
});
});
it("Get active mixnodes detailed", async (): Promise<void> => {
const response = await contract.getActiveMixnodesDetailed();
response.forEach(function (mixnode) {
expect(
mixnode.mixnode_details.rewarding_details.cost_params
.profit_margin_percent
).toBeTruthy();
});
});
it("Get rewarded mixnodes", async (): Promise<void> => {
const response = await contract.getRewardedMixnodes();
response.forEach(function (mixnode) {
expect(mixnode.rewarding_details.last_rewarded_epoch).toBeTruthy();
});
});
it("Get rewarded mixnodes detailed", async (): Promise<void> => {
const response = await contract.getRewardedMixnodesDetailed();
response.forEach(function (mixnode) {
expect(
mixnode.mixnode_details.rewarding_details.last_rewarded_epoch
).toBeTruthy();
});
});
it("Get blacklisted mixnodes", async (): Promise<void> => {
const response = await contract.getBlacklistedMixnodes();
if (response === null) {
// no blacklisted mixnodes returns an empty array
expect(response).toBeNull();
} else {
response.forEach(function (value) {
expect(typeof value).toBe("number");
});
}
});
});
@@ -1,38 +0,0 @@
import ContractCache from "../../src/endpoints/ContractCache";
let contract: ContractCache;
describe("Get service provider info", (): void => {
beforeAll(async (): Promise<void> => {
contract = new ContractCache();
});
it("Get service providers", async (): Promise<void> => {
const response = await contract.getServiceProviders();
if ("[service_id]" in response) {
response.services.forEach((x) => {
expect(typeof x.service.nym_address.address).toBe("string");
expect(typeof x.service.service_type).toBe("string");
expect(typeof x.service.block_height).toBe("number");
expect(typeof x.service.announcer).toBe("string");
expect(typeof x.service.deposit.amount).toBe("string");
expect(typeof x.service.deposit.denom).toBe("string");
});
} else if ("[ ]" in response) {
return;
}
});
it("Get Nym address names", async (): Promise<void> => {
const response = await contract.getNymAddressNames();
if ("[id]" in response) {
response.names.forEach((x) => {
expect(typeof x.name.name).toBe("string");
expect(typeof x.name.address.gateway_id).toBe("string");
expect(typeof x.id).toBe("number");
});
} else if ("[ ]" in response) {
return;
}
});
});
@@ -1,47 +0,0 @@
import NetworkTypes from "../../src/endpoints/Network";
let contract: NetworkTypes;
describe("Get network and contract details", (): void => {
beforeAll(async (): Promise<void> => {
contract = new NetworkTypes();
});
it("Get network details", async (): Promise<void> => {
const response = await contract.getNetworkDetails();
expect(typeof response.network.network_name).toBe("string");
});
it("Get nym contract info", async (): Promise<void> => {
const response = await contract.getNymContractInfo();
for (const key in response) {
if (response.hasOwnProperty(key)) {
const additionalProp = response[key];
expect(typeof additionalProp.address).toBe("string");
if ("build_timestamp" in response) {
expect(typeof additionalProp.details.contract).toBe("string");
expect(typeof additionalProp.details.version).toBe("string");
}
else if (additionalProp.details === null) {
expect(additionalProp.details).toBeNull();
}
}
}
});
it("Get nym contract info detailed", async (): Promise<void> => {
const response = await contract.getNymContractDetailedInfo();
for (const key in response) {
if (response.hasOwnProperty(key)) {
const additionalProp = response[key];
expect(typeof additionalProp.address).toBe("string");
if ("build_timestamp" in response) {
expect(typeof additionalProp.details.build_timestamp).toBe("string");
expect(typeof additionalProp.details.rustc_version).toBe("string");
}
else if (additionalProp.details === null) {
expect(additionalProp.details).toBeNull();
}
}
}
});
});
@@ -1,80 +0,0 @@
import Status from "../../src/endpoints/Status";
import ConfigHandler from "../../../../common/api-test-utils/config/configHandler"
let status: Status;
let config: ConfigHandler;
describe("Get gateway data", (): void => {
beforeAll(async (): Promise<void> => {
status = new Status();
config = ConfigHandler.getInstance();
});
it("Get all gateways detailed", async (): Promise<void> => {
const response = await status.getDetailedGateways();
response.forEach((x) => {
expect(typeof x.gateway_bond.owner).toBe("string");
expect(typeof x.performance).toBe("string");
expect(typeof x.node_performance.last_24h).toBe("string");
});
});
it("Get all gateways unfiltered", async (): Promise<void> => {
const response = await status.getUnfilteredGateways();
response.forEach((x) => {
expect(typeof x.gateway_bond.owner).toBe("string");
expect(typeof x.performance).toBe("string");
expect(typeof x.node_performance.last_24h).toBe("string");
});
});
it("Get a gateway history", async (): Promise<void> => {
const identity_key = config.environmentConfig.gateway_identity;
const response = await status.getGatewayHistory(identity_key);
if ("identity" in response) {
response.history.forEach((x) => {
expect(typeof x.date).toBe("string");
expect(typeof x.uptime).toBe("number");
});
expect(identity_key).toStrictEqual(response.identity);
expect(typeof response.owner).toBe("string");
} else if ("message" in response) {
expect(response.message).toContain(
"could not find uptime history associated with gateway"
);
}
});
it("Get gateway core status count", async (): Promise<void> => {
const identity_key = config.environmentConfig.gateway_identity;
const response = await status.getGatewayCoreCount(identity_key);
expect(identity_key).toStrictEqual(response.identity);
expect(typeof response.count).toBe("number");
});
it("Get gateway average uptime", async (): Promise<void> => {
const identity_key = config.environmentConfig.gateway_identity;
const response = await status.getGatewayAverageUptime(identity_key);
if ("identity" in response) {
expect(identity_key).toStrictEqual(response.identity);
expect(typeof response.avg_uptime).toBe("number");
} else if ("message" in response) {
expect(response.message).toContain("gateway bond not found");
}
});
it("Get a gateway status report", async (): Promise<void> => {
const identity_key = config.environmentConfig.gateway_identity;
const response = await status.getGatewayStatusReport(identity_key);
if ("identity" in response) {
expect(identity_key).toStrictEqual(response.identity);
expect(typeof response.owner).toBe("string");
expect(typeof response.most_recent).toBe("number");
expect(typeof response.last_hour).toBe("number");
expect(typeof response.last_day).toBe("number");
} else if ("message" in response) {
expect(response.message).toContain("gateway bond not found");
}
});
});
@@ -1,165 +0,0 @@
import Status from "../../src/endpoints/Status";
import ConfigHandler from "../../../../common/api-test-utils/config/configHandler";
let status: Status;
let config: ConfigHandler;
describe("Get mixnode data", (): void => {
beforeAll(async (): Promise<void> => {
status = new Status();
config = ConfigHandler.getInstance();
});
it("Get a mixnode report", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeStatusReport(identity_key);
if ("mix_id" in response) {
expect(typeof response.last_day).toBe("number");
expect(typeof response.owner).toBe("string");
} else if ("message" in response) {
expect(response.message).toContain("mixnode bond not found");
}
});
it("Get a mixnode stake saturation", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeStakeSaturation(identity_key);
if ("saturation" in response) {
expect(typeof response.as_at).toBe("number");
expect(typeof response.saturation).toBe("string");
expect(typeof response.uncapped_saturation).toBe("string");
} else if ("message" in response) {
expect(response.message).toContain("mixnode bond not found");
}
});
it("Get a mixnode average uptime", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeAverageUptime(identity_key);
if ("mix_id" in response) {
expect(identity_key).toStrictEqual(response.mix_id);
expect(typeof response.avg_uptime).toBe("number");
} else if ("message" in response) {
expect(response.message).toContain("mixnode bond not found");
}
});
it("Get a mixnode history", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeHistory(identity_key);
if ("mix_id" in response) {
response.history.forEach((x) => {
expect(typeof x.date).toBe("string");
expect(typeof x.uptime).toBe("number");
});
expect(identity_key).toStrictEqual(response.mix_id);
expect(typeof response.owner).toBe("string");
} else if ("message" in response) {
expect(response.message).toContain(
"could not find uptime history associated with mixnode"
);
}
});
it("Get a mixnode core count", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeCoreCount(identity_key);
expect(identity_key).toStrictEqual(response.mix_id);
expect(typeof response.count).toBe("number");
});
it("Get a mixnode reward estimation", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeRewardComputation(identity_key);
if ("estimation" in response) {
expect(response.reward_params.interval.sybil_resistance).toStrictEqual(
"0.3"
);
expect(response.reward_params.active_set_size).toStrictEqual(240);
expect(typeof response.reward_params.interval.reward_pool).toBe("string");
} else if ("message" in response) {
expect(response.message).toContain("mixnode bond not found");
}
});
it("Get a mixnode inclusion probability", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeInclusionProbability(identity_key);
if ("mix_id" in response) {
expect(typeof response.in_active).toBe("string");
} else if ("message" in response) {
expect(response.message).toContain("mixnode bond not found");
}
});
it("Get all mixnodes inclusion probabilities", async (): Promise<void> => {
const response = await status.getAllMixnodeInclusionProbability();
response.inclusion_probabilities.forEach((x) => {
expect(typeof x.mix_id).toBe("number");
expect(typeof x.in_active).toBe("number");
});
expect(typeof response.delta_max).toBe("number");
});
it("Get all mixnodes", async (): Promise<void> => {
const response = await status.getDetailedMixnodes();
response.forEach((x) => {
expect(typeof x.stake_saturation).toBe("string");
});
});
it("Get all mixnodes unfiltered", async (): Promise<void> => {
const response = await status.getUnfilteredMixnodes();
response.forEach((x) => {
expect(typeof x.stake_saturation).toBe("string");
expect(
typeof x.mixnode_details.rewarding_details.last_rewarded_epoch
).toBe("number");
});
});
it("Get a mixnode status", async (): Promise<void> => {
const identity_key = config.environmentConfig.mix_id;
const response = await status.getMixnodeStatus(identity_key);
const unfiltered_mixnodes_response = await status.getUnfilteredMixnodes();
const mixnode = unfiltered_mixnodes_response.find(
(x) => x.mixnode_details.bond_information.mix_id === identity_key
);
if (mixnode) {
expect(response.status).toStrictEqual("active");
} else {
expect(response.status).toStrictEqual("not_found");
}
}, 7000);
it("Get all rewarded mixnodes", async (): Promise<void> => {
const response = await status.getDetailedRewardedMixnodes();
response.forEach((x) => {
expect(
typeof x.mixnode_details.rewarding_details.last_rewarded_epoch
).toBe("number");
});
});
it("Get all active mixnodes", async (): Promise<void> => {
const response = await status.getDetailedActiveMixnodes();
response.forEach((x) => {
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
});
});
describe("Compute mixnode reward estimation", (): void => {
beforeAll(async (): Promise<void> => {
status = new Status();
config = ConfigHandler.getInstance();
});
// TODO - this test needs fixing
it.skip("with correct data", async (): Promise<void> => {
const mix_id = config.environmentConfig.mix_id;
const response = await status.sendMixnodeRewardEstimatedComputation(
mix_id
);
expect(typeof response.estimation.delegates).toBe("string");
});
});
});
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
reporters: ["default", "jest-junit"],
collectCoverageFrom: ["src/**/*.ts"]
};
-8546
View File
File diff suppressed because it is too large Load Diff
-51
View File
@@ -1,51 +0,0 @@
{
"name": "validator-api-test-suite",
"version": "1.0.0",
"description": "a basic validator-api suite to test the validator-api",
"main": "dist/index.js",
"directories": {
"test": "test"
},
"scripts": {
"test:sandbox": "TEST_ENV=sandbox jest --forceExit --detectOpenHandles --passWithNoTests",
"test:prod": "TEST_ENV=prod jest --forceExit --detectOpenHandles --passWithNoTests",
"build": "tsc",
"lint": "eslint --ext .js,.ts,.tsx .",
"lint:fix": "eslint src --fix",
"cleanup": "rm -rf node_modules; rm -rf dist; yarn install"
},
"author": "Nymtech",
"license": "MIT",
"files": [
"dist"
],
"engines": {
"node": "18.1.0",
"npm": "8.x"
},
"dependencies": {
"axios": "^1.7.5",
"eslint": "^8.21.0",
"form-data": "4.0.0",
"json-stringify-safe": "5.0.1",
"tslog": "3.3.3",
"uuid": "8.3.2",
"yaml": "^2.2.2"
},
"devDependencies": {
"@types/jest": "28.1.6",
"@types/mocha": "^10.0.1",
"@typescript-eslint/eslint-plugin": "^5.12.1",
"@typescript-eslint/parser": "^5.33.0",
"axios-mock-adapter": "^1.20.0",
"eslint-config-prettier": "^8.4.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^28.1.3",
"jest-junit": "^14.0.0",
"prettier": "^2.8.7",
"process": "0.11.10",
"ts-jest": "28.0.7",
"typescript": "^4.7.4",
"uuidv4": "^6.2.12"
}
}
+23
View File
@@ -0,0 +1,23 @@
#[path = "public-api/api_status.rs"]
mod api_status;
#[path = "public-api/circulating_supply.rs"]
mod circulating_supply;
#[path = "public-api/contract_cache.rs"]
mod contract_cache;
#[path = "public-api/network.rs"]
mod network;
#[path = "public-api/nym_nodes.rs"]
mod nym_nodes;
#[path = "public-api/status.rs"]
mod status;
#[path = "public-api/unstable_nym_nodes.rs"]
mod unstable_nym_nodes;
#[path = "public-api/unstable_status.rs"]
mod unstable_status;
+39
View File
@@ -0,0 +1,39 @@
// tests/api_status.rs
use serde_json::Value;
use tokio;
mod utils;
use utils::{base_url, test_client};
#[tokio::test]
async fn test_health() {
let url = format!("{}/v1/api-status/health", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 2xx but got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
assert_eq!(json["status"], "up", "Expected status to be 'up'");
}
// #[tokio::test]
// async fn test_signer_information() {
// let url = format!("{}/v1/api-status/signer-information", base_url());
// let res = test_client().get(&url).send().await.unwrap();
// assert!(res.status().is_success());
// let json: Value = res.json().await.expect("Invalid JSON");
// assert!(json.get("signer_address").is_some(), "Missing 'signer_address'");
// // TODO add an OR for "this api does not expose zk-nym signing functionalities" when checkign the main api
// }
#[tokio::test]
async fn test_build_information() {
let url = format!("{}/v1/api-status/build-information", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.expect("Invalid JSON");
assert!(json.get("build_version").is_some(), "Missing 'build_version'");
}
@@ -0,0 +1,41 @@
mod utils;
use utils::{base_url, test_client};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_circulating_supply() {
let url = format!("{}/v1/circulating-supply", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON response");
assert!(json.get("circulating_supply").is_some(), "Missing 'circulating_supply' field");
}
#[tokio::test]
async fn test_get_circulating_supply_value() {
let url = format!("{}/v1/circulating-supply/circulating-supply-value", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
assert!(json.is_number(), "Expected a number for the circulating supply value");
let number = json.as_f64().unwrap();
assert!(number >= 0.0, "Circulating supply should be non-negative");
}
#[tokio::test]
async fn test_get_total_supply_value() {
let url = format!("{}/v1/circulating-supply/total-supply-value", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
assert!(json.is_number(), "Expected a number for total supply value");
let number = json.as_f64().unwrap();
assert!(number >= 0.0, "Total supply should be non-negative");
}
@@ -0,0 +1,32 @@
mod utils;
use utils::{base_url, test_client};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_current_epoch() {
let url = format!("{}/v1/epoch/current", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
assert!(json.get("id").is_some(), "Missing 'id'");
assert!(json.get("current_epoch_start").is_some(), "Missing 'current_epoch_start'");
assert!(json.get("total_elapsed_epochs").is_some(), "Missing 'total_elapsed_epochs'");
}
#[tokio::test]
async fn test_get_reward_params() {
let url = format!("{}/v1/epoch/reward_params", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
let interval = json.get("interval").expect("Missing 'interval' field");
assert!(interval.get("reward_pool").is_some(), "Missing 'interval.reward_pool'");
let rewarded_set = json.get("rewarded_set").expect("Missing 'rewarded_set' field");
assert!(rewarded_set.get("exit_gateways").is_some(), "Missing 'rewarded_set.exit_gateways'");
}
+73
View File
@@ -0,0 +1,73 @@
mod utils;
use utils::{base_url, test_client};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_chain_status() {
let url = format!("{}/v1/network/chain-status", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
let block_header = json
.get("status")
.and_then(|s| s.get("latest_block"))
.and_then(|b| b.get("block"))
.and_then(|b| b.get("header"))
.expect("Missing 'status.block.header'");
assert!(block_header.get("chain_id").is_some(), "Missing 'chain_id'");
assert!(block_header.get("height").is_some(), "Missing 'height'");
}
#[tokio::test]
async fn test_get_network_details() {
let url = format!("{}/v1/network/details", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
assert!(json.get("connected_nyxd").is_some(), "Missing 'connected_nyxd'");
let contracts = json
.get("network")
.and_then(|s| s.get("contracts"))
.expect("Missing 'contracts'");
assert!(contracts.get("mixnet_contract_address").is_some(), "Missing 'mixnet_contract_address'");
}
#[tokio::test]
async fn test_get_nym_contracts() {
let url = format!("{}/v1/network/nym-contracts", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
assert!(json.get("nym-mixnet-contract").is_some(), "Missing 'nym-mixnet-contract'");
assert!(json.get("nym-ecash-contract").is_some(), "Missing 'nym-ecash-contract'");
}
#[tokio::test]
async fn test_get_nym_contracts_detailed() {
let url = format!("{}/v1/network/nym-contracts-detailed", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.expect("Invalid JSON");
let mixnet_contract = json
.get("nym-mixnet-contract")
.and_then(|s| s.get("details"))
.expect("Missing details for mixnet contract");
assert!(mixnet_contract.get("commit_branch").is_some(), "Missing 'commit_branch'");
let mixnet_contract = json
.get("nym-ecash-contract")
.and_then(|s| s.get("details"))
.expect("Missing details for ecash contract");
assert!(mixnet_contract.get("commit_branch").is_some(), "Missing 'commit_branch'");
}
+130
View File
@@ -0,0 +1,130 @@
mod utils;
use utils::{base_url, test_client, get_any_node_id};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_bonded_nodes() {
let url = format!("{}/v1/nym-nodes/bonded", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let data = json.get("data").expect("Missing 'data' field");
assert!(data.is_array(), "Expected 'data' to be an array");
assert!(
data.as_array().unwrap().len() > 0,
"Expected at least one bonded node"
);
}
#[tokio::test]
async fn test_get_described_nodes() {
let url = format!("{}/v1/nym-nodes/described", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let data = json.get("data").expect("Missing 'data' field");
assert!(data.is_array(), "Expected 'data' to be an array");
assert!(
data.as_array().unwrap().len() > 0,
"Expected at least one node to appear"
);
}
// TODO enable this once noise is properly integrated?
// #[tokio::test]
// async fn test_get_noise() {
// let url = format!("{}/v1/nym-nodes/noise", base_url());
// let res = test_client().get(&url).send().await.unwrap();
// assert!(res.status().is_success());
// }
#[tokio::test]
async fn test_get_rewarded_set() {
let url = format!("{}/v1/nym-nodes/rewarded-set", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let exit_gateways = json.get("exit_gateways").expect("Missing 'exit_gateways' field");
assert!(exit_gateways.is_array(), "Expected 'exit_gateways' to be an array");
assert!(
exit_gateways.as_array().unwrap().len() > 0,
"We have no exit gateways!!"
);
}
#[tokio::test]
async fn test_get_annotation_for_node() {
let id = get_any_node_id().await;
println!("Using node_id: {}", id);
let url = format!("{}/v1/nym-nodes/annotation/{}", base_url(), id);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let annotation = json.get("annotation").expect("Missing 'annotation' field");
assert!(annotation.get("last_24h_performance").is_some(), "Missing 'last_24h_performance'");
}
// TODO add the date section here to the request too (1970-01-01 format)
// #[tokio::test]
// async fn test_get_historical_performance() {
// let id = get_any_node_id().await;
// let url = format!("{}/v1/nym-nodes/historical-performance/{}", base_url(), id);
// let res = test_client().get(&url).send().await.unwrap();
// assert!(res.status().is_success());
// }
#[tokio::test]
async fn test_get_performance_history() {
let id = get_any_node_id().await;
let url = format!("{}/v1/nym-nodes/performance-history/{}", base_url(), id);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let data = json
.get("history")
.and_then(|h| h.get("data"))
.expect("Missing 'history.data' field");
assert!(data.is_array(), "Expected 'history.data' to be an array");
assert!(
data.as_array().unwrap().len() > 0,
"Expected at least one performance history entry"
);
}
#[tokio::test]
async fn test_get_performance() {
let id = get_any_node_id().await;
let url = format!("{}/v1/nym-nodes/performance/{}", base_url(), id);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
assert!(json.get("node_id").is_some(), "Missing 'node_id'");
assert!(json.get("performance").is_some(), "Missing 'performance'");
}
#[tokio::test]
async fn test_get_uptime_history() {
let id = get_any_node_id().await;
let url = format!("{}/v1/nym-nodes/uptime-history/{}", base_url(), id);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let data = json
.get("history")
.and_then(|h| h.get("data"))
.expect("Missing 'history.data' field");
assert!(data.is_array(), "Expected 'history.data' to be an array");
assert!(
data.as_array().unwrap().len() > 0,
"Expected at least one performance history entry"
);
}
// TODO add the POST request test for `refresh-described`
+36
View File
@@ -0,0 +1,36 @@
mod utils;
use utils::{base_url, test_client};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_config_score_details() {
let url = format!("{}/v1/status/config-score-details", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success(), "Expected 200 OK, got {}", res.status());
let json: Value = res.json().await.unwrap();
let version_history = json
.get("version_history")
.and_then(|v| v.as_array())
.expect("Missing or invalid 'version_history' array");
assert!(!version_history.is_empty(), "'version_history' should not be empty");
let max_entry = version_history
.iter()
.max_by_key(|entry| entry.get("id").and_then(|id| id.as_u64()).unwrap_or(0))
.expect("Unable to find max id entry");
let semver = max_entry
.get("version_information")
.and_then(|v| v.get("semver"))
.and_then(|v| v.as_str());
assert!(semver.is_some(), "Missing 'semver' in highest id entry");
}
// TODO add the POST request tests for:
// submit-gateway-monitoring-results
// submit-node-monitoring-results
@@ -0,0 +1,101 @@
mod utils;
use utils::{base_url, test_client};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_skimmed_nodes_active() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/active", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let data = json.get("nodes").and_then(|r| r.get("data")).expect("Missing 'data' field");
assert!(data.is_array(), "Expected 'data' to be an array");
assert!(
data.as_array().unwrap().len() > 0,
"Expected at least one node to appear"
);
}
#[tokio::test]
async fn test_get_skimmed_active_mixnodes() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/mixnodes/active", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let current_epoch_id = json.get("status").and_then(|r| r.get("fresh")).and_then(|r| r.get("current_epoch_id")).expect("Missing 'current_epoch_id' field");
assert!(current_epoch_id.is_number(), "Expected 'current_epoch_id' to be an array");
assert!(json.get("refreshed_at").is_some(), "Missing 'refreshed_at'");
}
#[tokio::test]
async fn test_get_skimmed_all_mixnodes() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/mixnodes/all", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let current_epoch_id = json.get("status").and_then(|r| r.get("fresh")).and_then(|r| r.get("current_epoch_id")).expect("Missing 'current_epoch_id' field");
assert!(current_epoch_id.is_number(), "Expected 'current_epoch_id' to be an array");
assert!(json.get("refreshed_at").is_some(), "Missing 'refreshed_at'");
}
#[tokio::test]
async fn test_get_skimmed_active_exit_gateways() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/exit-gateways/active", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let current_epoch_id = json.get("status").and_then(|r| r.get("fresh")).and_then(|r| r.get("current_epoch_id")).expect("Missing 'current_epoch_id' field");
assert!(current_epoch_id.is_number(), "Expected 'current_epoch_id' to be an array");
assert!(json.get("refreshed_at").is_some(), "Missing 'refreshed_at'");
}
#[tokio::test]
async fn test_get_skimmed_all_exit_gateways() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/exit-gateways/all", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let current_epoch_id = json.get("status").and_then(|r| r.get("fresh")).and_then(|r| r.get("current_epoch_id")).expect("Missing 'current_epoch_id' field");
assert!(current_epoch_id.is_number(), "Expected 'current_epoch_id' to be an array");
assert!(json.get("refreshed_at").is_some(), "Missing 'refreshed_at'");
}
#[tokio::test]
async fn test_get_skimmed_active_entry_gateways() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/entry-gateways/active", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let current_epoch_id = json.get("status").and_then(|r| r.get("fresh")).and_then(|r| r.get("current_epoch_id")).expect("Missing 'current_epoch_id' field");
assert!(current_epoch_id.is_number(), "Expected 'current_epoch_id' to be an array");
assert!(json.get("refreshed_at").is_some(), "Missing 'refreshed_at'");
}
#[tokio::test]
async fn test_get_skimmed_all_entry_gateways() {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/entry-gateways/all", base_url());
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let current_epoch_id = json.get("status").and_then(|r| r.get("fresh")).and_then(|r| r.get("current_epoch_id")).expect("Missing 'current_epoch_id' field");
assert!(current_epoch_id.is_number(), "Expected 'current_epoch_id' to be an array");
assert!(json.get("refreshed_at").is_some(), "Missing 'refreshed_at'");
}
// Add the remining tests as the endpoints become active
@@ -0,0 +1,87 @@
mod utils;
use utils::{base_url, test_client, get_gateway_identity_key, get_mixnode_node_id};
use serde_json::Value;
use tokio;
#[tokio::test]
async fn test_get_gateway_unstable_test_results() {
let identity = get_gateway_identity_key().await;
print!("blaaaaaaa{}", identity);
let url = format!(
"{}/v1/status/gateways/unstable/{}/test-results",
base_url(),
identity
);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.expect("Invalid JSON");
let data_array = json
.get("data")
.and_then(|v| v.as_array())
.expect("Missing or invalid 'data' array");
assert!(!data_array.is_empty(), "'data' array is empty");
let gateway = data_array[0]
.get("test_routes")
.and_then(|r| r.get("gateway"))
.expect("Missing 'test_routes.gateway'");
assert!(gateway.get("node_id").is_some(), "Missing 'node_id' in gateway");
assert!(gateway.get("identity_key").is_some(), "Missing 'identity_key' in gateway");
}
#[tokio::test]
async fn test_get_mixnode_unstable_test_results() {
let mix_id = get_mixnode_node_id().await;
let url = format!(
"{}/v1/status/mixnodes/unstable/{}/test-results",
base_url(),
mix_id
);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.expect("Invalid JSON");
let data_array = json
.get("data")
.and_then(|v| v.as_array())
.expect("Missing or invalid 'data' array");
assert!(!data_array.is_empty(), "'data' array is empty");
let layer3 = data_array[0]
.get("test_routes")
.and_then(|r| r.get("layer3"))
.expect("Missing 'test_routes.layer3'");
assert!(layer3.get("node_id").is_some(), "Missing 'node_id' in layer3");
assert!(layer3.get("identity_key").is_some(), "Missing 'identity_key' in layer3");
}
#[tokio::test]
async fn test_get_latest_network_monitor_run_details() {
let url = format!(
"{}/v1/status/network-monitor/unstable/run/latest/details",
base_url()
);
let res = test_client().get(&url).send().await.unwrap();
assert!(res.status().is_success());
let json: Value = res.json().await.unwrap();
let monitor_run_id = json
.get("monitor_run_id")
.and_then(|v| v.as_number())
.expect("Missing or invalid 'monitor_run_id'");
let follow_up_url = format!(
"{}/v1/status/network-monitor/unstable/run/{}/details",
base_url(),
monitor_run_id
);
let follow_up_res = test_client().get(&follow_up_url).send().await.unwrap();
assert!(follow_up_res.status().is_success());
}
+82
View File
@@ -0,0 +1,82 @@
use reqwest::Client;
use serde_json::Value;
pub fn test_client() -> Client {
Client::new()
}
pub fn base_url() -> String {
std::env::var("API_BASE_URL").unwrap_or_else(|_| "https://sandbox-nym-api1.nymtech.net/api".into())
}
pub async fn get_any_node_id() -> String {
let url = format!("{}/v1/nym-nodes/bonded", base_url());
let res = test_client().get(&url).send().await.unwrap();
let json: Value = res.json().await.unwrap();
json.get("data")
.and_then(|list| list.as_array())
.and_then(|arr| arr.first())
.and_then(|node| node.get("bond_information"))
.and_then(|n| n.get("node_id"))
.and_then(|v| v.as_u64())
.map(|id| id.to_string())
.unwrap_or_else(|| "INVALID_ID".into())
.to_string()
}
pub async fn get_mixnode_node_id() -> u64 {
let url = format!("{}/v1/nym-nodes/described", base_url());
let res = test_client().get(&url).send().await.unwrap();
let json: Value = res.json().await.unwrap();
json.get("data")
.and_then(|v| v.as_array())
.expect("Expected 'data' to be an array")
.iter()
.find(|entry| {
entry
.get("description")
.and_then(|d| d.get("declared_role"))
.and_then(|r| r.get("mixnode"))
.and_then(|m| m.as_bool())
.map(|is_mixnode| is_mixnode)
.unwrap_or(true)
})
.and_then(|node| {
node.get("node_id")
.and_then(|v| v.as_u64())
})
.expect("Unable to find mixnode node id")
}
pub async fn get_gateway_identity_key() -> String {
let url = format!("{}/v1/nym-nodes/described", base_url());
let res = test_client().get(&url).send().await.unwrap();
let json: Value = res.json().await.unwrap();
json.get("data")
.and_then(|v| v.as_array())
.expect("Expected 'data' to be an array")
.iter()
.find(|entry| {
entry
.get("description")
.and_then(|d| d.get("declared_role"))
.and_then(|r| r.get("mixnode"))
.and_then(|m| m.as_bool())
.map(|is_mixnode| !is_mixnode) // we want gateways, not mixnodes
.unwrap_or(false)
})
.and_then(|node| {
node.get("description")
.and_then(|d| d.get("host_information"))
.and_then(|h| h.get("keys"))
.and_then(|k| k.get("ed25519"))
.and_then(|v| v.as_str())
})
.expect("Unable to find gateway identity key with mixnode = false")
.to_string()
}
@@ -1,29 +0,0 @@
import { Detailed } from "../types/CirculatingSupplyTypes";
import { APIClient } from "./abstracts/APIClient";
export default class ContractCache extends APIClient {
constructor() {
super("/");
}
public async getCirculatingSupply(): Promise<Detailed> {
const response = await this.restClient.sendGet({
route: `circulating-supply`,
});
return response.data;
}
public async getTotalSupplyValue(): Promise<number> {
const response = await this.restClient.sendGet({
route: `circulating-supply/total-supply-value`,
});
return response.data;
}
public async getCirculatingSupplyValue(): Promise<number> {
const response = await this.restClient.sendGet({
route: `circulating-supply/circulating-supply-value`,
});
return response.data;
}
}
@@ -1,108 +0,0 @@
import {
MixnodesDetailed,
AllGateways,
AllMixnodes,
EpochRewardParams,
CurrentEpoch,
ServiceProviders,
NymAddressNames,
} from "../types/ContractCacheTypes";
import { APIClient } from "./abstracts/APIClient";
export default class ContractCache extends APIClient {
constructor() {
super("/");
}
public async getMixnodes(): Promise<AllMixnodes[]> {
const response = await this.restClient.sendGet({
route: `mixnodes`,
});
return response.data;
}
public async getMixnodesDetailed(): Promise<MixnodesDetailed[]> {
const response = await this.restClient.sendGet({
route: `mixnodes/detailed`,
});
return response.data;
}
public async getGateways(): Promise<AllGateways[]> {
const response = await this.restClient.sendGet({
route: `gateways`,
});
return response.data;
}
public async getActiveMixnodes(): Promise<AllMixnodes[]> {
const response = await this.restClient.sendGet({
route: `mixnodes/active`,
});
return response.data;
}
public async getActiveMixnodesDetailed(): Promise<MixnodesDetailed[]> {
const response = await this.restClient.sendGet({
route: `mixnodes/active/detailed`,
});
return response.data;
}
public async getRewardedMixnodes(): Promise<AllMixnodes[]> {
const response = await this.restClient.sendGet({
route: `mixnodes/rewarded`,
});
return response.data;
}
public async getRewardedMixnodesDetailed(): Promise<MixnodesDetailed[]> {
const response = await this.restClient.sendGet({
route: `mixnodes/rewarded/detailed`,
});
return response.data;
}
public async getBlacklistedMixnodes(): Promise<[]> {
const response = await this.restClient.sendGet({
route: `mixnodes/blacklisted`,
});
return response.data;
}
public async getBlacklistedGateways(): Promise<[]> {
const response = await this.restClient.sendGet({
route: `gateways/blacklisted`,
});
return response.data;
}
public async getEpochRewardParams(): Promise<EpochRewardParams> {
const response = await this.restClient.sendGet({
route: `epoch/reward_params`,
});
return response.data;
}
public async getCurrentEpoch(): Promise<CurrentEpoch> {
const response = await this.restClient.sendGet({
route: `epoch/current`,
});
return response.data;
}
public async getServiceProviders(): Promise<ServiceProviders> {
const response = await this.restClient.sendGet({
route: `services`,
});
return response.data;
}
public async getNymAddressNames(): Promise<NymAddressNames> {
const response = await this.restClient.sendGet({
route: `names`,
});
return response.data;
}
}
-29
View File
@@ -1,29 +0,0 @@
import { NetworkDetails, NymContracts, NymContractsDetailed } from "../types/NetworkTypes";
import { APIClient } from "./abstracts/APIClient";
export default class NetworkTypes extends APIClient {
constructor() {
super("/");
}
public async getNetworkDetails(): Promise<NetworkDetails> {
const response = await this.restClient.sendGet({
route: `network/details`,
});
return response.data;
}
public async getNymContractInfo(): Promise<NymContracts> {
const response = await this.restClient.sendGet({
route: `network/nym-contracts`,
});
return response.data;
}
public async getNymContractDetailedInfo(): Promise<NymContractsDetailed> {
const response = await this.restClient.sendGet({
route: `network/nym-contracts-detailed`,
});
return response.data;
}
}
-217
View File
@@ -1,217 +0,0 @@
import {
ActiveStatus,
AvgUptime,
CoreCount,
DetailedGateway,
DetailedMixnodes,
GatewayUptimeResponse,
InclusionProbabilities,
InclusionProbability,
NodeHistory,
ErrorMsg,
Report,
RewardEstimation,
StakeSaturation,
} from "../types/StatusInterfaces";
import { APIClient } from "./abstracts/APIClient";
export default class Status extends APIClient {
constructor() {
super("/status");
}
// GATEWAYS
public async getDetailedGateways(): Promise<DetailedGateway[]> {
const response = await this.restClient.sendGet({
route: `/gateways/detailed`,
});
return response.data;
}
public async getUnfilteredGateways(): Promise<DetailedGateway[]> {
const response = await this.restClient.sendGet({
route: `/gateways/detailed-unfiltered`,
});
return response.data;
}
public async getGatewayStatusReport(
identity_key: string
): Promise<Report | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/gateway/${identity_key}/report`,
});
return response.data;
}
public async getGatewayHistory(
identity_key: string
): Promise<NodeHistory | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/gateway/${identity_key}/history`,
});
return response.data;
}
public async getGatewayCoreCount(identity_key: string): Promise<CoreCount> {
const response = await this.restClient.sendGet({
route: `/gateway/${identity_key}/core-status-count`,
});
return response.data;
}
public async getGatewayAverageUptime(
identity_key: string
): Promise<GatewayUptimeResponse | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/gateway/${identity_key}/avg_uptime`,
});
return response.data;
}
// MIXNODES
public async getMixnodeStatusReport(
mix_id: number
): Promise<Report | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/report`,
});
return response.data;
}
public async getMixnodeStakeSaturation(
mix_id: number
): Promise<StakeSaturation | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/stake-saturation`,
});
return response.data;
}
public async getMixnodeCoreCount(mix_id: number): Promise<CoreCount> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/core-status-count`,
});
return response.data;
}
public async getMixnodeRewardComputation(
mix_id: number
): Promise<RewardEstimation | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/reward-estimation`,
});
return response.data;
}
public async sendMixnodeRewardEstimatedComputation(
mix_id: number
): Promise<RewardEstimation> {
const response = await this.restClient.sendPost({
route: `/mixnode/${mix_id}/compute-reward-estimation`,
data: {
// performance: "10",
active_in_rewarded_set: true,
// pledge_amount: 10,
// total_delegation: 2000,
// interval_operating_cost: {
// denom: "unym",
// amount: "250000000"
// },
// profit_margin_percent: 10
},
});
return response.data;
}
public async getMixnodeHistory(
mix_id: number
): Promise<NodeHistory | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/history`,
});
return response.data;
}
public async getMixnodeAverageUptime(
mix_id: number
): Promise<AvgUptime | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/avg_uptime`,
});
return response.data;
}
public async getMixnodeInclusionProbability(
mix_id: number
): Promise<InclusionProbability | ErrorMsg> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/inclusion-probability`,
});
return response.data;
}
public async getMixnodeStatus(mix_id: number): Promise<ActiveStatus> {
const response = await this.restClient.sendGet({
route: `/mixnode/${mix_id}/status`,
});
return response.data;
}
public async getAllMixnodeInclusionProbability(): Promise<InclusionProbabilities> {
const response = await this.restClient.sendGet({
route: `/mixnodes/inclusion_probability`,
});
return response.data;
}
public async getDetailedMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({
route: `/mixnodes/detailed`,
});
return response.data;
}
public async getDetailedRewardedMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({
route: `/mixnodes/rewarded/detailed`,
});
return response.data;
}
public async getUnfilteredMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({
route: `/mixnodes/detailed-unfiltered`,
});
return response.data;
}
public async getDetailedActiveMixnodes(): Promise<DetailedMixnodes[]> {
const response = await this.restClient.sendGet({
route: `/mixnodes/active/detailed`,
});
return response.data;
}
}
@@ -1,30 +0,0 @@
import { Logger } from "tslog";
import ConfigHandler from "../../../../../common/api-test-utils/config/configHandler";
import { RestClient } from "../../../../../common/api-test-utils/restClient/RestClient";
export abstract class APIClient {
protected constructor(serviceUrl: string) {
const baseUrl: string = this.config.environmentConfig.api_base_url;
this.url = baseUrl + serviceUrl;
this.restClient = new RestClient(this.url);
this.serviceName = this.constructor.toString().match(/\w+/g)[1];
this.log.info(`The Service URL for ${this.serviceName} is ${this.url}`);
}
public createdItemIds: Set<string> = new Set();
protected config = ConfigHandler.getInstance();
protected log: Logger = new Logger({
minLevel: this.config.environmentConfig.log_level,
dateTimeTimezone:
this.config.environmentConfig.time_zone ||
Intl.DateTimeFormat().resolvedOptions().timeZone,
});
protected url: string;
public restClient: RestClient;
protected serviceName: string;
}
@@ -1,26 +0,0 @@
export type Detailed = {
total_supply: InitialSupply;
mixmining_reserve: MixminingReserve;
vesting_tokens: VestingTokens;
circulating_supply: CirculatingSupply;
};
export type InitialSupply = {
demon: "unym";
amount: string;
};
export type MixminingReserve = {
demon: "unym";
amount: string;
};
export type VestingTokens = {
demon: "unym";
amount: string;
};
export type CirculatingSupply = {
demon: "unym";
amount: string;
};
@@ -1,154 +0,0 @@
export interface AllMixnodes {
bond_information: BondInformation;
rewarding_details: RewardingDetails;
}
export interface BondInformation {
mix_id: number;
owner: string;
original_pledge: DenominationAndAmount;
layer: number;
mix_node: Mixnode;
proxy: string;
bonding_height: number;
is_unbonding: boolean;
}
export interface RewardingDetails {
cost_params: CostParams;
operator: string;
delegates: string;
total_unit_reward: string;
unit_delegation: string;
last_rewarded_epoch: number;
unique_delegations: number;
}
export interface CostParams {
profit_margin_percent: string;
interval_operating_cost: DenominationAndAmount;
}
export interface DenominationAndAmount {
denom: string;
amount: string;
}
export interface Mixnode {
host: string;
mix_port: number;
verloc_port: number;
http_api_port: number;
sphinx_key: string;
identity_key: string;
version: string;
}
export interface MixnodeBond {
pledge_amount: DenominationAndAmount;
total_delegation: DenominationAndAmount;
owner: string;
layer: string;
block_height: string;
mix_node: Mixnode;
proxy: string;
accumulated_rewards: string;
}
export interface MixnodesDetailed {
mixnode_details: AllMixnodes;
stake_saturation: string;
uncapped_stake_saturation: string;
performance: string;
estimated_operator_apy: string;
estimated_delegators_apy: string;
family: string;
}
export interface Gateway {
host: string;
mix_port: number;
clients_port: number;
location: string;
sphinx_key: string;
identity_key: string;
version: string;
}
export interface AllGateways {
pledge_amount: DenominationAndAmount;
owner: string;
block_height: number;
gateway: Gateway;
proxy: string;
}
export interface EpochRewardParams {
interval: Interval;
rewarded_set_size: number;
active_set_size: number;
}
export interface Interval {
reward_pool: string;
staking_supply: string;
staking_supply_scale_factor: string;
epoch_reward_budget: string;
stake_saturation_point: string;
sybil_resistance: string;
active_set_work_factor: string;
interval_pool_emission: string;
}
export interface CurrentEpoch {
id: number;
epochs_in_interval: number;
current_epoch_start: string;
current_epoch_id: number;
epoch_length: EpochLength;
total_elapsed_epochs: number;
}
export interface EpochLength {
secs: number;
nanos: number;
}
export interface ServiceProviders {
services: Services[];
}
export interface Services {
service_id: number;
service: Service;
}
export interface Service {
nym_address: NymAddress;
service_type: string;
announcer: string;
block_height: number;
deposit: DenominationAndAmount;
}
export interface NymAddress {
address: string;
}
export interface NymAddressNames {
names: Names[];
}
export interface Names {
id: number;
name: Name;
owner: string;
block_height: number;
deposit: DenominationAndAmount;
}
export interface Name {
name: string;
address: NameAddress;
identity_key: string;
}
export interface NameAddress {
client_id: string;
client_enc: string;
gateway_id: string;
}
-72
View File
@@ -1,72 +0,0 @@
export interface NetworkDetails {
connected_nyxd: string;
network: Network;
}
export interface Network {
network_name: string;
chain_details: ChainDetails;
endpoints: Endpoint[];
contracts: Contracts;
explorer_api: string;
}
export interface ChainDetails {
bech32_account_prefix: string;
mix_denom: Denom;
stake_denom: Denom;
}
export interface Denom {
base: string;
display: string;
display_exponent: number;
}
export interface Contracts {
mixnet_contract_address: string;
vesting_contract_address: string;
coconut_bandwidth_contract_address: string;
group_contract_address: string;
multisig_contract_address: string;
coconut_dkg_contract_address: string;
}
export interface Endpoint {
nyxd_url: string;
api_url: string;
}
export interface NymContracts {
[additionalProp: string]: AdditionalProp;
}
export interface AdditionalProp {
address: string;
details: Info;
}
export interface Info {
contract: string;
version: string;
}
export interface NymContractsDetailed {
[additionalProp: string]: AdditionalPropDetailed;
}
export interface AdditionalPropDetailed {
address: string;
details: InfoDetailed;
}
export interface InfoDetailed {
build_timestamp: string;
build_version: string;
commit_sha: string;
commit_timestamp: string;
commit_branch: string;
rustc_version: string;
}
-232
View File
@@ -1,232 +0,0 @@
export interface CurrentEpoch {
epoch_reward_pool: string;
rewarded_set_size: string;
active_set_size: string;
staking_supply: string;
sybil_resistance_percent: number;
active_set_work_factor: number;
}
export interface Epoch {
id: number;
epochs_in_interval: number;
current_epoch_start: string;
current_epoch_id: number;
epoch_length: EpochLength;
total_elapsed_epochs: number;
}
export interface EpochLength {
secs: number;
nanos: number;
}
export interface Node {
reward_blockstamp: number;
uptime: string;
in_active_set: boolean;
}
export interface Estimation {
total_node_reward: string;
operator: string;
delegates: string;
operating_cost: string;
}
export interface RewardEstimation {
estimation: Estimation;
reward_params: RewardParams;
epoch: Epoch;
as_at: number;
}
export interface RewardParams {
interval: Interval;
rewarded_set_size: number;
active_set_size: number;
}
export interface ComputeRewardEstimation {
performance: string;
active_in_rewarded_set: boolean;
pledge_amount: number;
total_delegation: number;
interval_operating_cost: DenominationAndAmount;
profit_margin_percent: string;
}
export interface DenominationAndAmount {
denom: string;
amount: string;
}
export interface Interval {
reward_pool: string;
staking_supply: string;
staking_supply_scale_factor: string;
epoch_reward_budget: string;
stake_saturation_point: string;
sybil_resistance: string;
active_set_work_factor: string;
interval_pool_emission: string;
}
export interface StakeSaturation {
saturation: string;
uncapped_saturation: string;
as_at: number;
}
export interface SingleInclusionProbability {
in_active: number;
in_reserve: number;
}
export interface InclusionProbability {
mix_id: number;
in_active: string;
in_reserve: string;
}
export interface InclusionProbabilities {
inclusion_probabilities: InclusionProbability[];
samples: number;
elapsed: Elapsed;
delta_max: number;
delta_l2: number;
as_at: number;
}
export interface Elapsed {
secs: number;
nanos: number;
}
export interface Report {
mix_id: number;
identity: string;
owner: string;
most_recent: number;
last_hour: number;
last_day: number;
}
export interface History {
date: string;
uptime: number;
}
export interface NodeHistory {
mix_id: number;
identity: string;
owner: string;
history: History[];
}
export interface ErrorMsg {
message: string;
}
export interface CoreCount {
mix_id: number;
identity: string;
count: number;
}
export interface ActiveStatus {
status: string;
}
export interface Gateway {
host: string;
mix_port: number;
clients_port: number;
location: string;
sphinx_key: string;
identity_key: string;
version: string;
}
export interface GatewayBond {
pledge_amount: DenominationAndAmount;
owner: string;
block_height: number;
gateway: Gateway;
proxy?: any;
}
export interface nodePerformance {
most_recent: string;
last_hour: string;
last_24h: string;
}
export interface AvgUptime {
mix_id: number;
avg_uptime: number;
node_performance: nodePerformance;
}
export interface GatewayUptimeResponse {
identity: string;
avg_uptime: number;
node_performance: nodePerformance;
}
export interface DetailedGateway {
gateway_bond: GatewayBond;
performance: string;
node_performance: nodePerformance;
}
export interface MixNode {
host: string;
mix_port: number;
verloc_port: number;
http_api_port: number;
sphinx_key: string;
identity_key: string;
version: string;
}
export interface BondInformation {
mix_id: number;
owner: string;
original_pledge: DenominationAndAmount;
layer: string;
mix_node: MixNode;
proxy: string;
bonding_height: number;
is_unbonding: boolean;
}
export interface CostParams {
profit_margin_percent: string;
interval_operating_cost: DenominationAndAmount;
}
export interface RewardingDetails {
cost_params: CostParams;
operator: string;
delegates: string;
total_unit_reward: string;
unit_delegation: string;
last_rewarded_epoch: number;
unique_delegations: number;
}
export interface MixnodeDetails {
bond_information: BondInformation;
rewarding_details: RewardingDetails;
}
export interface DetailedMixnodes {
mixnode_details: MixnodeDetails;
stake_saturation: string;
uncapped_stake_saturation: string;
performance: string;
estimated_operator_apy: string;
estimated_delegators_apy: string;
family: string;
}
-5
View File
@@ -1,5 +0,0 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*", "functional_test/**/*", "unit_test/**/*", "*.ts"],
"exclude": ["node_modules", "dist"]
}
-25
View File
@@ -1,25 +0,0 @@
{
"compilerOptions": {
"removeComments": true,
"allowJs": true,
"preserveConstEnums": true,
"module": "commonjs",
"target": "ES2019",
"declaration": true,
"esModuleInterop": true,
"sourceMap": true,
"lib": ["esnext"],
"outDir": "dist",
"resolveJsonModule": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"paths": {
"*": ["types/*"]
},
"baseUrl": "./",
"typeRoots": ["node_modules/@types"],
"alwaysStrict": true
},
"include": ["src/**/*", "tests/functional_test/*/*"],
"exclude": ["unit_test/**/*"]
}
File diff suppressed because it is too large Load Diff