diff --git a/.github/workflows/add-issue-to-backlog.yml b/.github/workflows/add-issue-to-backlog.yml index f9b15aa..0b4bcd9 100644 --- a/.github/workflows/add-issue-to-backlog.yml +++ b/.github/workflows/add-issue-to-backlog.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Add issue to Backlog project - uses: actions/add-to-project@v0.5.0 + uses: actions/add-to-project@v1.0.2 with: project-url: https://github.com/orgs/numbersprotocol/projects/8 # OR for repository projects: diff --git a/.gitignore b/.gitignore index 0bbd89e..2b62896 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,23 @@ .subnet-cli.pk + +# OS artifacts +.DS_Store +Thumbs.db + +# Editor files +.vscode/ +.idea/ + +# Download artifacts +*.tar.gz +*.zip + +# Python caches +__pycache__/ +*.py[cod] +.pytest_cache/ + +# Environment and secret files +.env +*.pem +*.key diff --git a/api/env.sh b/api/env.sh index bbb7296..725960d 100644 --- a/api/env.sh +++ b/api/env.sh @@ -1 +1 @@ -URL="127.0.0.1:9650" +URL="${URL:-127.0.0.1:9650}" diff --git a/api/health.health.sh b/api/health.health.sh index f1c51d2..33da01d 100755 --- a/api/health.health.sh +++ b/api/health.health.sh @@ -1,7 +1,9 @@ #!/bin/bash +source env.sh + curl -X POST --data '{ "jsonrpc":"2.0", "id" :1, "method" :"health.health" - }' -H 'content-type:application/json;' 127.0.0.1:9650/ext/health + }' -H 'content-type:application/json;' ${URL}/ext/health diff --git a/api/info.getNodeID.sh b/api/info.getNodeID.sh index e3c6c95..0cae9ac 100755 --- a/api/info.getNodeID.sh +++ b/api/info.getNodeID.sh @@ -5,7 +5,7 @@ # Expected Output # {"jsonrpc":"2.0","result":{"nodeID":"NodeID-JRhJd4Qn4WTjP28RUFDQa2NC59deo7tT6"},"id":1} -URL="127.0.0.1:9650" +source env.sh curl -X POST --data '{ "jsonrpc":"2.0", diff --git a/api/info.isBootstrapped.sh b/api/info.isBootstrapped.sh index 2940dfd..c939399 100755 --- a/api/info.isBootstrapped.sh +++ b/api/info.isBootstrapped.sh @@ -3,7 +3,7 @@ # Note: The bootstrapping process takes approximately 50–100 hours and requires 100 GB of space. # https://chainstack.com/avalanche-subnet-tutorial-series-running-a-local-avalanche-node-on-fuji-testnet/ -URL="127.0.0.1:9650" +source env.sh CHAIN_ID="$1" curl -X POST --data "{ diff --git a/api/info.peers.sh b/api/info.peers.sh index 7fa32b2..a4cd833 100755 --- a/api/info.peers.sh +++ b/api/info.peers.sh @@ -1,32 +1,16 @@ #!/bin/bash -# Snow -echo "========== Snow nodes information ==========" -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"info.peers", - "params": { - "nodeIDs": [ - "NodeID-7TwAjiRpTbNcqUx6F9EoyXRBLAfeoQXRq", - "NodeID-JbeonHKqomERomXgCiXr9oC9vfynkBupj", - "NodeID-BffXkmzM8EwrBZgpqFp9pwgE9DbDgYKG2", - "NodeID-24WK7qiKXAumya1kKEktwj2ubBbRyq5UW", - "NodeID-A2Z8m7egVLhKf1Qj14uvXadhExM5zrB7p" - ] - } -}' -H 'content-type:application/json;' https://api.avax-test.network/ext/info | jq . +source env.sh + +NODE_IDS="${1:-}" +ENDPOINT="${2:-${URL}}" -# Jade -echo "========== Jade nodes information ==========" -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"info.peers", - "params": { - "nodeIDs": [ - "NodeID-BXTBUqX8gitUDtVam4fhRWGD1SfeHGoBx" - ] +curl -X POST --data "{ + \"jsonrpc\":\"2.0\", + \"id\" :1, + \"method\" :\"info.peers\", + \"params\": { + \"nodeIDs\": [${NODE_IDS}] } -}' -H 'content-type:application/json;' https://api.avax.network/ext/info | jq . +}" -H 'content-type:application/json;' ${ENDPOINT}/ext/info | jq . diff --git a/api/metrics.sh b/api/metrics.sh index a527772..bbffa74 100755 --- a/api/metrics.sh +++ b/api/metrics.sh @@ -1,3 +1,5 @@ #!/bin/bash -curl -X POST 127.0.0.1:9650/ext/metrics +source env.sh + +curl -X POST ${URL}/ext/metrics diff --git a/api/platform.getBlockchainStatus.sh b/api/platform.getBlockchainStatus.sh index e6b1c25..ec4cd29 100755 --- a/api/platform.getBlockchainStatus.sh +++ b/api/platform.getBlockchainStatus.sh @@ -7,7 +7,7 @@ # "vmID": "kmYb53NrmqcW7gfV2FGHBHWXNA6YhhWf7R7LoQeGj9mdDYuaT" # } -URL="127.0.0.1:9650" +source env.sh BLOCKCHAIN_ID="$1" curl -X POST --data "{ diff --git a/api/platform.getCurrentValidators.sh b/api/platform.getCurrentValidators.sh index 0e0f743..3d125c9 100755 --- a/api/platform.getCurrentValidators.sh +++ b/api/platform.getCurrentValidators.sh @@ -3,7 +3,7 @@ # Note: The bootstrapping process takes approximately 50–100 hours and requires 100 GB of space. # https://chainstack.com/avalanche-subnet-tutorial-series-running-a-local-avalanche-node-on-fuji-testnet/ -URL="127.0.0.1:9650" +source env.sh SUBNET_ID="$1" curl -X POST --data "{ \"jsonrpc\": \"2.0\", diff --git a/api/platform.getPendingValidators.sh b/api/platform.getPendingValidators.sh index 8c9402d..2b1cb98 100755 --- a/api/platform.getPendingValidators.sh +++ b/api/platform.getPendingValidators.sh @@ -3,7 +3,7 @@ # Note: The bootstrapping process takes approximately 50–100 hours and requires 100 GB of space. # https://chainstack.com/avalanche-subnet-tutorial-series-running-a-local-avalanche-node-on-fuji-testnet/ -URL="127.0.0.1:9650" +source env.sh echo "URL: ${URL}" diff --git a/api/platform.getSubnets.sh b/api/platform.getSubnets.sh index 3fde414..8c79902 100755 --- a/api/platform.getSubnets.sh +++ b/api/platform.getSubnets.sh @@ -3,7 +3,7 @@ # Note: The bootstrapping process takes approximately 50–100 hours and requires 100 GB of space. # https://chainstack.com/avalanche-subnet-tutorial-series-running-a-local-avalanche-node-on-fuji-testnet/ -URL="127.0.0.1:9650" +source env.sh echo "URL: ${URL}" diff --git a/api/platform.getValidatorsAt.sh b/api/platform.getValidatorsAt.sh index 66ee968..290e831 100755 --- a/api/platform.getValidatorsAt.sh +++ b/api/platform.getValidatorsAt.sh @@ -1,13 +1,16 @@ #!/bin/bash +source env.sh + SUBNET_ID="$1" +HEIGHT="${2:-1}" curl -X POST --data "{ \"jsonrpc\": \"2.0\", \"method\": \"platform.getValidatorsAt\", \"params\": { - \"height\":1, + \"height\":${HEIGHT}, \"subnetID\": \"${SUBNET_ID}\" }, \"id\": 1 -}" -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +}" -H 'content-type:application/json;' ${URL}/ext/bc/P diff --git a/api/platform.validatedBy.sh b/api/platform.validatedBy.sh index 236114c..c19460c 100755 --- a/api/platform.validatedBy.sh +++ b/api/platform.validatedBy.sh @@ -1,5 +1,7 @@ #!/bin/bash +source env.sh + BLOCKCHAIN_ID="$1" curl -X POST --data "{ @@ -9,4 +11,4 @@ curl -X POST --data "{ \"blockchainID\": \"${BLOCKCHAIN_ID}\" }, \"id\": 1 -}" -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +}" -H 'content-type:application/json;' ${URL}/ext/bc/P diff --git a/api/platform.validates.sh b/api/platform.validates.sh index a41d4a7..c5f8c71 100755 --- a/api/platform.validates.sh +++ b/api/platform.validates.sh @@ -1,5 +1,7 @@ #!/bin/bash +source env.sh + SUBNET_ID="$1" curl -X POST --data "{ @@ -9,5 +11,5 @@ curl -X POST --data "{ \"subnetID\":\"${SUBNET_ID}\" }, \"id\": 1 -}" -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +}" -H 'content-type:application/json;' ${URL}/ext/bc/P diff --git a/chains/devnet/genesis.json b/chains/devnet/genesis.json index 3fa9f51..ed93486 100644 --- a/chains/devnet/genesis.json +++ b/chains/devnet/genesis.json @@ -44,7 +44,7 @@ "nonce": "0x0", "timestamp": "0x0", "extraData": "0x", - "gasLimit": "0x7a1200", + "gasLimit": "0x1312D00", "difficulty": "0x0", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", diff --git a/genesis/genesis-nativecoin-feemgr-feerecv.json b/genesis/genesis-nativecoin-feemgr-feerecv.json deleted file mode 100644 index af6ed96..0000000 --- a/genesis/genesis-nativecoin-feemgr-feerecv.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "config": { - "chainId": 10508, - "homesteadBlock": 0, - "eip150Block": 0, - "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "subnetEVMTimestamp": 0, - "feeConfig": { - "gasLimit": 20000000, - "minBaseFee": 1000000000, - "targetGas": 100000000, - "baseFeeChangeDenominator": 48, - "minBlockGasCost": 0, - "maxBlockGasCost": 10000000, - "targetBlockRate": 2, - "blockGasCostStep": 500000 - }, - "allowFeeRecipients": true, - "contractNativeMinterConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x63B7076FC0A914Af543C2e5c201df6C29FCC18c5"] - }, - "feeManagerConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x63B7076FC0A914Af543C2e5c201df6C29FCC18c5"] - } - }, - "alloc": { - "63B7076FC0A914Af543C2e5c201df6C29FCC18c5": { - "balance": "0x52B7D2DCC80CD2E4000000" - } - }, - "nonce": "0x0", - "timestamp": "0x0", - "extraData": "0x00", - "gasLimit": "0x1312D00", - "difficulty": "0x0", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} diff --git a/genesis/genesis-nativecoin-feemgr.json b/genesis/genesis-nativecoin-feemgr.json deleted file mode 100644 index 9e94914..0000000 --- a/genesis/genesis-nativecoin-feemgr.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "config": { - "chainId": 10508, - "homesteadBlock": 0, - "eip150Block": 0, - "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "subnetEVMTimestamp": 0, - "feeConfig": { - "gasLimit": 20000000, - "minBaseFee": 1000000000, - "targetGas": 100000000, - "baseFeeChangeDenominator": 48, - "minBlockGasCost": 0, - "maxBlockGasCost": 10000000, - "targetBlockRate": 2, - "blockGasCostStep": 500000 - }, - "contractNativeMinterConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x63B7076FC0A914Af543C2e5c201df6C29FCC18c5"] - }, - "feeManagerConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x63B7076FC0A914Af543C2e5c201df6C29FCC18c5"] - } - }, - "alloc": { - "63B7076FC0A914Af543C2e5c201df6C29FCC18c5": { - "balance": "0x52B7D2DCC80CD2E4000000" - } - }, - "nonce": "0x0", - "timestamp": "0x0", - "extraData": "0x00", - "gasLimit": "0x1312D00", - "difficulty": "0x0", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} diff --git a/genesis/genesis.json b/genesis/genesis.json deleted file mode 100644 index a060304..0000000 --- a/genesis/genesis.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "config": { - "chainId": 10508, - "homesteadBlock": 0, - "eip150Block": 0, - "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "subnetEVMTimestamp": 0, - "feeConfig": { - "gasLimit": 20000000, - "minBaseFee": 1000000000, - "targetGas": 100000000, - "baseFeeChangeDenominator": 48, - "minBlockGasCost": 0, - "maxBlockGasCost": 10000000, - "targetBlockRate": 2, - "blockGasCostStep": 500000 - } - }, - "alloc": { - "63B7076FC0A914Af543C2e5c201df6C29FCC18c5": { - "balance": "0x52B7D2DCC80CD2E4000000" - } - }, - "nonce": "0x0", - "timestamp": "0x0", - "extraData": "0x00", - "gasLimit": "0x1312D00", - "difficulty": "0x0", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} diff --git a/rpc/requirements.txt b/rpc/requirements.txt new file mode 100644 index 0000000..f5dabb4 --- /dev/null +++ b/rpc/requirements.txt @@ -0,0 +1,4 @@ +pytest +pytest-asyncio +requests +websockets diff --git a/rpc/rpc_test.py b/rpc/rpc_test.py index c3561e8..24d1fbd 100644 --- a/rpc/rpc_test.py +++ b/rpc/rpc_test.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 +import pytest import requests -import json MAINNET_RPC_URL = "https://mainnetrpc.num.network" @@ -10,55 +10,69 @@ TESTNET_CHAIN_ID = 10508 -def test_connectivity(rpc_url): - try: - response = requests.get(rpc_url) - if response.status_code == 200: - print("Node is reachable, HTTP Status Code: 200") - else: - print(f"Node is not reachable, HTTP Status Code: {response.status_code}") - except Exception as e: - print(f"Connection failed, Error: {str(e)}") +def test_mainnet_connectivity(): + response = requests.get(MAINNET_RPC_URL) + assert response.status_code == 200, ( + f"Mainnet node not reachable, HTTP Status Code: {response.status_code}" + ) -def test_functionality(rpc_url): +def test_testnet_connectivity(): + response = requests.get(TESTNET_RPC_URL) + assert response.status_code == 200, ( + f"Testnet node not reachable, HTTP Status Code: {response.status_code}" + ) + + +def test_mainnet_functionality(): payload = { "jsonrpc": "2.0", "method": "web3_clientVersion", "params": [], - "id": 1 + "id": 1, } + response = requests.post(MAINNET_RPC_URL, json=payload) + response_data = response.json() + assert "result" in response_data, f"Unexpected response: {response_data}" - try: - response = requests.post(rpc_url, json=payload) - response_data = response.json() - print("RPC request successful, Response Data:", response_data) - except Exception as e: - print(f"RPC request failed, Error: {str(e)}") - -def test_chain_id(rpc_url, chain_id): +def test_testnet_functionality(): payload = { "jsonrpc": "2.0", - "method": "eth_chainId", - "id": chain_id, + "method": "web3_clientVersion", + "params": [], + "id": 1, } + response = requests.post(TESTNET_RPC_URL, json=payload) + response_data = response.json() + assert "result" in response_data, f"Unexpected response: {response_data}" - try: - response = requests.post(rpc_url, json=payload) - response_data = response.json() - print("RPC request successful, Response Data:", response_data) - except Exception as e: - print(f"RPC request failed, Error: {str(e)}") +def test_mainnet_chain_id(): + payload = { + "jsonrpc": "2.0", + "method": "eth_chainId", + "params": [], + "id": 1, + } + response = requests.post(MAINNET_RPC_URL, json=payload) + response_data = response.json() + assert "result" in response_data, f"Unexpected response: {response_data}" + assert int(response_data["result"], 16) == MAINNET_CHAIN_ID, ( + f"Expected chain ID {MAINNET_CHAIN_ID}, got {response_data['result']}" + ) -if __name__ == '__main__': - print("Testing Mainnet RPC") - test_connectivity(MAINNET_RPC_URL) - test_functionality(MAINNET_RPC_URL) - test_chain_id(MAINNET_RPC_URL, MAINNET_CHAIN_ID) - print("Testing Testnet RPC") - test_connectivity(TESTNET_RPC_URL) - test_functionality(TESTNET_RPC_URL) - test_chain_id(TESTNET_RPC_URL, TESTNET_CHAIN_ID) +def test_testnet_chain_id(): + payload = { + "jsonrpc": "2.0", + "method": "eth_chainId", + "params": [], + "id": 1, + } + response = requests.post(TESTNET_RPC_URL, json=payload) + response_data = response.json() + assert "result" in response_data, f"Unexpected response: {response_data}" + assert int(response_data["result"], 16) == TESTNET_CHAIN_ID, ( + f"Expected chain ID {TESTNET_CHAIN_ID}, got {response_data['result']}" + ) diff --git a/rpc/websocket_test.py b/rpc/websocket_test.py index c47b769..2fb8e28 100644 --- a/rpc/websocket_test.py +++ b/rpc/websocket_test.py @@ -1,37 +1,28 @@ import asyncio import json +import pytest from websockets import connect -TESTNET_RPC_WS_ENDPOINT='wss://testnetrpc.num.network/ws' -MAINNET_RPC_WS_ENDPOINT='wss://mainnetrpc.num.network/ws' +TESTNET_RPC_WS_ENDPOINT = 'wss://testnetrpc.num.network/ws' +MAINNET_RPC_WS_ENDPOINT = 'wss://mainnetrpc.num.network/ws' -async def get_event(rpc_ws_endpoint): +async def subscribe_and_receive(rpc_ws_endpoint): async with connect(rpc_ws_endpoint) as ws: await ws.send('{"jsonrpc":"2.0", "id": 1, "method": "eth_subscribe", "params": ["logs", {"topics": []}]}') subscription_response = await ws.recv() - print(f'Testing WS endpoint {rpc_ws_endpoint}') - print(subscription_response) + return json.loads(subscription_response) - while True: - try: - message = await asyncio.wait_for(ws.recv(), timeout=60) - print(json.loads(message)) - except asyncio.TimeoutError: - print(f"Timeout, no messages received for 60 seconds.") - except Exception as e: - print(f'Error: {e}') - break # This will only break the loop if there is an exception that's not a TimeoutError. +@pytest.mark.asyncio +async def test_testnet_ws_subscription(): + data = await subscribe_and_receive(TESTNET_RPC_WS_ENDPOINT) + assert "result" in data, f"Expected subscription ID in response, got: {data}" -async def main(): - await asyncio.gather( - get_event(rpc_ws_endpoint=TESTNET_RPC_WS_ENDPOINT), - get_event(rpc_ws_endpoint=MAINNET_RPC_WS_ENDPOINT) - ) - -if __name__ == '__main__': - asyncio.run(main()) +@pytest.mark.asyncio +async def test_mainnet_ws_subscription(): + data = await subscribe_and_receive(MAINNET_RPC_WS_ENDPOINT) + assert "result" in data, f"Expected subscription ID in response, got: {data}" diff --git a/subnet-cli/subnet-cli-wizard.sh b/subnet-cli/subnet-cli-wizard.sh index bdf42e3..13d7558 100755 --- a/subnet-cli/subnet-cli-wizard.sh +++ b/subnet-cli/subnet-cli-wizard.sh @@ -5,7 +5,7 @@ subnet-cli wizard \ --node-ids NodeID-24WK7qiKXAumya1kKEktwj2ubBbRyq5UW,NodeID-A2Z8m7egVLhKf1Qj14uvXadhExM5zrB7p \ - --vm-genesis-path ../genesis/genesis-nativecoin-feemgr-feerecv.json \ + --vm-genesis-path ../chains/testnet/genesis-nativecoin-feemgr-feerecv.json \ --vm-id kmYb53NrmqcW7gfV2FGHBHWXNA6YhhWf7R7LoQeGj9mdDYuaT \ --chain-name captevm