mirror of
https://github.com/tig-pool-nk/tig-monorepo.git
synced 2026-02-21 11:29:31 +08:00
Update scripts.
This commit is contained in:
parent
a250046618
commit
4ab829c92c
@ -8,8 +8,8 @@ RUN ARCH=$(uname -m) && \
|
||||
echo "Unsupported architecture: $ARCH. Must be 'aarch64', 'arm64', 'amd64', or 'x86_64'." && exit 1; \
|
||||
fi
|
||||
|
||||
# Common setup for all images
|
||||
RUN apt update && apt install -y curl build-essential zstd python3
|
||||
RUN apt update && apt install -y curl build-essential zstd python3 python3-pip
|
||||
RUN pip3 install blake3 requests --break-system-packages
|
||||
|
||||
# Install Rust with specific version
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
@ -58,8 +58,9 @@ RUN if command -v nvcc > /dev/null 2>&1; then \
|
||||
chmod +x /usr/local/bin/tig-verifier && \
|
||||
rm -rf tig-monorepo
|
||||
|
||||
COPY tig-binary/scripts /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/build_so && \
|
||||
chmod +x /usr/local/bin/build_ptx
|
||||
COPY scripts/ /usr/local/bin/tig-scripts/
|
||||
COPY tig-binary/scripts/ /usr/local/bin/tig-scripts/
|
||||
RUN chmod +x /usr/local/bin/tig-scripts/*
|
||||
ENV PATH="/usr/local/bin/tig-scripts:${PATH}"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@ -18,6 +18,10 @@ RUN chmod +x /usr/local/bin/tig-runtime && \
|
||||
RUN apt update && apt install -y python3 python3-pip
|
||||
RUN pip3 install blake3 requests randomname --break-system-packages
|
||||
|
||||
COPY scripts/ /usr/local/bin/tig-scripts/
|
||||
RUN chmod +x /usr/local/bin/tig-scripts/*
|
||||
ENV PATH="/usr/local/bin/tig-scripts:${PATH}"
|
||||
|
||||
COPY tig-benchmarker /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
21
README.md
21
README.md
@ -25,16 +25,23 @@ This repository contains the implementation of The Innovation Game (TIG).
|
||||
* [tig-utils](./tig-utils/README.md) - A Rust crate that contains utility functions used throughout TIG
|
||||
* [tig-verifier](./tig-verifier/README.md) - A Rust crate that verifies a single solution or Merkle proof.
|
||||
|
||||
## Docker Images
|
||||
|
||||
TIG docker images are hosted on [Github Packages](https://github.com/orgs/tig-foundation/packages):
|
||||
|
||||
* [dev](https://github.com/orgs/tig-foundation/packages/container/package/tig-monorepo%2Fdev) - environment for Innovators who are developing algorithms
|
||||
* [runtime](https://github.com/orgs/tig-foundation/packages/container/package/tig-monorepo%2Fruntime) - environment for Benchmarkers who are running slaves
|
||||
|
||||
## Useful Scripts
|
||||
|
||||
Under `scripts/` folder is a bunch of useful bash scripts:
|
||||
Under `scripts/` folder is a bunch of useful scripts:
|
||||
|
||||
* `list_algorithms.sh`
|
||||
* `list_benchmark_ids.sh`
|
||||
* `list_challenges.sh`
|
||||
* `get_benchmark_data.sh`
|
||||
* `test_algorithm.sh`
|
||||
* `verify_benchmark.sh`
|
||||
* `download_algorithm`
|
||||
* `list_algorithms`
|
||||
* `list_challenges`
|
||||
* `test_algorithms`
|
||||
|
||||
These are available on `PATH` in the `dev` and `runtime` docker images
|
||||
|
||||
## License
|
||||
|
||||
|
||||
64
scripts/download_algorithm
Normal file
64
scripts/download_algorithm
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='TIG Algorithm Downloader')
|
||||
parser.add_argument('challenge', help="Challenge name or id")
|
||||
parser.add_argument('algorithm', help="Algorithm name or id")
|
||||
parser.add_argument('--out', default="tig-algorithms/lib", help="Output directory (default: tig-algorithms/lib)")
|
||||
parser.add_argument('--testnet', action='store_true', help="Use testnet API")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
api_url = f"https://{'test' if args.testnet else 'main'}net-api.tig.foundation"
|
||||
block = requests.get(f"{api_url}/get-block").json()["block"]
|
||||
challenges = requests.get(f"{api_url}/get-challenges?block_id={block['id']}").json()["challenges"]
|
||||
data = requests.get(f"{api_url}/get-algorithms?block_id={block['id']}").json()
|
||||
algorithms = data["algorithms"]
|
||||
download_urls = {x['algorithm_id']: x['details']['download_url'] for x in data['binarys']}
|
||||
|
||||
c_id = next(
|
||||
(
|
||||
c['id'] for c in challenges
|
||||
if c['details']['name'] == args.challenge or c['id'] == args.challenge
|
||||
),
|
||||
None
|
||||
)
|
||||
if c_id is None:
|
||||
print(f"Challenge '{args.challenge}' not found.")
|
||||
sys.exit(1)
|
||||
|
||||
a_id = next(
|
||||
(
|
||||
a['id'] for a in algorithms
|
||||
if (
|
||||
a['details']['name'] == args.algorithm or a['id'] == args.algorithm
|
||||
) and a['details']['challenge_id'] == c_id
|
||||
),
|
||||
None
|
||||
)
|
||||
if a_id is None:
|
||||
print(f"Algorithm '{args.algorithm}' not found for challenge '{args.challenge}'.")
|
||||
sys.exit(1)
|
||||
|
||||
download_url = download_urls.get(a_id)
|
||||
if download_url is None:
|
||||
print(f"Download URL for algorithm '{args.algorithm}' not found.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Downloading algorithm '{args.algorithm}' from {download_url}...")
|
||||
resp = requests.get(download_url, stream=True)
|
||||
output_dir = f"{args.out}/{args.challenge}"
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
with tarfile.open(fileobj=io.BytesIO(resp.content), mode='r:gz') as tar:
|
||||
tar.extractall(path=output_dir)
|
||||
print(f"Algorithm '{args.algorithm}' downloaded and extracted to '{output_dir}'.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
read -p "Enter benchmark_id: " benchmark_id
|
||||
curl -s https://mainnet-api.tig.foundation/get-benchmark-data?benchmark_id=$benchmark_id
|
||||
@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Fetching latest block..."
|
||||
BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.id')
|
||||
echo "Fetching algorithms..."
|
||||
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-algorithms?block_id=$BLOCK_ID")
|
||||
echo "Filtering algorithms..."
|
||||
ALGORITHMS=$(echo $RESP | jq -c '.algorithms[]' | jq 'select(.block_data.adoption | length > 15)' | jq -s 'sort_by(.block_data.adoption|tonumber)' | jq 'reverse')
|
||||
|
||||
declare -A CHALLENGES
|
||||
|
||||
echo "Calculating adoption percentage..."
|
||||
for ALGO in $(echo $ALGORITHMS | jq -c '.[]'); do
|
||||
A_NAME=$(echo $ALGO | jq -r '.details.name')
|
||||
ADOPTION=$(echo $ALGO | jq -r '.block_data.adoption')
|
||||
|
||||
ADOPTION_PERCENT=$(awk "BEGIN {printf \"%.2f\", $ADOPTION / 10000000000000000}")
|
||||
|
||||
case $(echo $ALGO | jq -r '.details.challenge_id') in
|
||||
"c001") C_NAME="satisfiability" ;;
|
||||
"c002") C_NAME="vehicle_routing" ;;
|
||||
"c003") C_NAME="knapsack" ;;
|
||||
"c004") C_NAME="vector_search" ;;
|
||||
*) C_NAME="unknown" ;;
|
||||
esac
|
||||
|
||||
CHALLENGES[$C_NAME]+="$(printf " %-30s %-20s\n" "$A_NAME" "adoption: $ADOPTION_PERCENT%")\n"
|
||||
done
|
||||
echo "Printing..."
|
||||
echo ""
|
||||
for CHALLENGE in "${!CHALLENGES[@]}"; do
|
||||
echo " Challenge: $CHALLENGE"
|
||||
echo -e "${CHALLENGES[$CHALLENGE]}"
|
||||
done
|
||||
|
||||
55
scripts/list_algorithms
Normal file
55
scripts/list_algorithms
Normal file
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='TIG Algorithm Lister')
|
||||
parser.add_argument('challenge', help="Challenge name or id")
|
||||
parser.add_argument('--testnet', action='store_true', help="Use testnet API")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
api_url = f"https://{'test' if args.testnet else 'main'}net-api.tig.foundation"
|
||||
block = requests.get(f"{api_url}/get-block").json()["block"]
|
||||
challenges = requests.get(f"{api_url}/get-challenges?block_id={block['id']}").json()["challenges"]
|
||||
data = requests.get(f"{api_url}/get-algorithms?block_id={block['id']}").json()
|
||||
algorithms = data["algorithms"]
|
||||
compile_success = {x['algorithm_id']: x['details']['compile_success'] for x in data['binarys']}
|
||||
|
||||
c_id = next(
|
||||
(
|
||||
c['id'] for c in challenges
|
||||
if c['details']['name'] == args.challenge or c['id'] == args.challenge
|
||||
),
|
||||
None
|
||||
)
|
||||
if c_id is None:
|
||||
print(f"Challenge '{args.challenge}' not found.")
|
||||
sys.exit(1)
|
||||
|
||||
algorithms = sorted([
|
||||
a for a in algorithms if a['details']['challenge_id'] == c_id
|
||||
], key=lambda x: x['id'])
|
||||
|
||||
for a in algorithms:
|
||||
if a["id"] not in compile_success:
|
||||
status = f"pending compilation"
|
||||
elif not compile_success[a["id"]]:
|
||||
status = f"failed to compile"
|
||||
elif a["state"]["round_merged"] is not None:
|
||||
status = f"merged @ round {a['state']['round_merged']}"
|
||||
elif a["state"]["round_active"] <= block["details"]["round"]:
|
||||
status = f"active with {a['block_data']['merge_points']} merge points"
|
||||
elif a["state"]["round_pushed"] <= block["details"]["round"]:
|
||||
status = f"active @ round {a['state']['round_active']}"
|
||||
else:
|
||||
status = f"pushed @ round {a['state']['round_pushed']}"
|
||||
print(f"id: {a['id']:<12} name: {a['details']['name']:<20} status: {status}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.id')
|
||||
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-algorithms?block_id=$BLOCK_ID")
|
||||
|
||||
ALGORITHMS=$(echo $RESP | jq -c '.algorithms[]' | jq -s 'sort_by(.id)')
|
||||
WASMS_DICT=$(echo $RESP | jq -c '[.binarys[] | {key: .algorithm_id, value: .}] | from_entries')
|
||||
|
||||
for ALGO in $(echo $ALGORITHMS | jq -c '.[]'); do
|
||||
ID=$(echo $ALGO | jq -r '.id')
|
||||
A_NAME=$(echo $ALGO | jq -r '.details.name')
|
||||
case $(echo $ALGO | jq -r '.details.challenge_id') in
|
||||
"c001") C_NAME="satisfiability" ;;
|
||||
"c002") C_NAME="vehicle_routing" ;;
|
||||
"c003") C_NAME="knapsack" ;;
|
||||
"c004") C_NAME="vector_search" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
ROUND_SUBMITTED=$(echo $ALGO | jq -r '.state.round_submitted')
|
||||
ROUND_PUSHED=$(echo $ALGO | jq -r '.state.round_pushed')
|
||||
COMPILE_SUCCESS=$(echo $WASMS_DICT | jq -c --arg ID "$ID" '.[$ID] | .details.compile_success')
|
||||
printf "(%-9s) %-40s %-20s %-20s %-20s\n" "$ID" "$C_NAME/$A_NAME" "round_submitted: $ROUND_SUBMITTED" "round_pushed: $ROUND_PUSHED" "compile_success: $COMPILE_SUCCESS"
|
||||
done
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
curl -s https://mainnet-api.tig.foundation/get-block?include_data | jq -r '.block.data.active_ids.benchmark[]' | nl
|
||||
26
scripts/list_challenges
Normal file
26
scripts/list_challenges
Normal file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='TIG Challenge Lister')
|
||||
parser.add_argument('--testnet', action='store_true', help="Use testnet API")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
api_url = f"https://{'test' if args.testnet else 'main'}net-api.tig.foundation"
|
||||
block = requests.get(f"{api_url}/get-block").json()["block"]
|
||||
challenges = requests.get(f"{api_url}/get-challenges?block_id={block['id']}").json()["challenges"]
|
||||
|
||||
challenges = sorted(challenges, key=lambda x: x['id'])
|
||||
for c in challenges:
|
||||
status = f"active @ round {c['state']['round_active']}"
|
||||
print(f"id: {c['id']:<7} name: {c['details']['name']:<20} status: {status}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.id')
|
||||
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-challenges?block_id=$BLOCK_ID")
|
||||
|
||||
CHALLENGES=$(echo $RESP | jq -c '.challenges[]' | jq -s 'sort_by(.id)')
|
||||
|
||||
for C in $(echo $CHALLENGES | jq -c '.[]'); do
|
||||
ID=$(echo $C | jq -r '.id')
|
||||
NAME=$(echo $C | jq -r '.details.name')
|
||||
ROUND_ACTIVE=$(echo $C | jq -r '.state.round_active')
|
||||
NUM_QUALIFIERS=$(echo $C | jq -c '.block_data.num_qualifiers')
|
||||
DIFFICULTIES=$(echo $C | jq -c '.block_data.qualifier_difficulties')
|
||||
printf "(%-4s) %-20s %-20s %-20s\n%-s\n\n" "$ID" "$NAME" "round_active: $ROUND_ACTIVE" "num_qualifiers: $NUM_QUALIFIERS" "qualifier_difficulties: $DIFFICULTIES"
|
||||
done
|
||||
@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Ask for player_id as input
|
||||
read -p "Enter player ID: " PLAYER_ID
|
||||
|
||||
BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.id')
|
||||
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-benchmarks?block_id=$BLOCK_ID&player_id=$PLAYER_ID")
|
||||
|
||||
BENCHMARKS=$(echo $RESP | jq -c '[.benchmarks[]] | sort_by(.settings.challenge_id, -.details.num_solutions)')
|
||||
|
||||
declare -A SOLUTIONS_COUNT
|
||||
|
||||
for BENCHMARK in $(echo $BENCHMARKS | jq -c '.[]'); do
|
||||
ID=$(echo $BENCHMARK | jq -r '.id')
|
||||
SETTINGS=$(echo $BENCHMARK | jq -c '.settings')
|
||||
CHALLENGE_ID=$(echo $BENCHMARK | jq -r '.settings.challenge_id')
|
||||
NUM_SOLUTIONS=$(echo $BENCHMARK | jq -r '.details.num_solutions')
|
||||
printf "ID: %-38s #Solutions: %-5s Settings: %-50s \n" "$ID" "$NUM_SOLUTIONS" "$SETTINGS"
|
||||
SOLUTIONS_COUNT["$CHALLENGE_ID"]=$(( ${SOLUTIONS_COUNT["$CHALLENGE_ID"]:-0} + NUM_SOLUTIONS ))
|
||||
done
|
||||
|
||||
echo "Total solutions by Challenge ID:"
|
||||
for CHALLENGE_ID in "${!SOLUTIONS_COUNT[@]}"; do
|
||||
echo "Challenge ID: $CHALLENGE_ID, Total Solutions: ${SOLUTIONS_COUNT[$CHALLENGE_ID]}"
|
||||
done
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.id')
|
||||
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-opow?block_id=$BLOCK_ID")
|
||||
|
||||
PLAYERS=$(echo $RESP | jq -c '[.opow[] | .block_data.reward = (if .block_data.reward == null then 0 else (.block_data.reward | tonumber) end)] | sort_by(.block_data.reward) | reverse')
|
||||
|
||||
for PLAYER in $(echo $PLAYERS | jq -c '.[]'); do
|
||||
ID=$(echo $PLAYER | jq -r '.player_id')
|
||||
REWARD=$(echo $PLAYER | jq -r '.block_data.reward | if . == null then "null" else tonumber / 1e18 end')
|
||||
printf "Player ID: %-25s Reward: %-20s\n" "$ID" "$REWARD"
|
||||
done
|
||||
172
scripts/test_algorithm
Normal file
172
scripts/test_algorithm
Normal file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
if (CPU_ARCH := platform.machine().lower()) in ["x86_64", "amd64"]:
|
||||
CPU_ARCH = "amd64"
|
||||
elif CPU_ARCH in ["arm64", "aarch64"]:
|
||||
CPU_ARCH = "aarch64"
|
||||
else:
|
||||
print(f"Unsupported CPU architecture: {CPU_ARCH}")
|
||||
sys.exit(1)
|
||||
|
||||
HAS_GPU = subprocess.run(["which", "nvidia-smi"], capture_output=True).returncode == 0
|
||||
if (VISIBLE_CPUS := os.environ.get("CPU_VISIBLE_CORES", None)) is None:
|
||||
VISIBLE_CPUS = list(os.sched_getaffinity(0))
|
||||
else:
|
||||
VISIBLE_CPUS = list(map(int, VISIBLE_CPUS.split(",")))
|
||||
os.sched_setaffinity(0, VISIBLE_CPUS)
|
||||
|
||||
if not HAS_GPU:
|
||||
VISIBLE_GPUS = []
|
||||
elif (VISIBLE_GPUS := os.environ.get("CUDA_VISIBLE_DEVICES", None)) is None:
|
||||
VISIBLE_GPUS = [
|
||||
int(match.group(1))
|
||||
for line in subprocess.check_output(["nvidia-smi", "-L"]).decode("utf-8").splitlines()
|
||||
if (match := re.match(r'^GPU (\d+):', line)) is not None
|
||||
]
|
||||
else:
|
||||
VISIBLE_GPUS = list(map(int, VISIBLE_GPUS.split(",")))
|
||||
|
||||
def now():
|
||||
return int(time.time() * 1000)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tig_runtime_path = shutil.which("tig-runtime")
|
||||
parser = argparse.ArgumentParser(description="TIG Algorithm Tester")
|
||||
parser.add_argument("challenge", type=str, help="Challenge name")
|
||||
parser.add_argument("algorithm", type=str, help="Algorithm name")
|
||||
parser.add_argument("difficulty", type=str, help="JSON string of difficulty")
|
||||
parser.add_argument("--tig_runtime_path", type=str, default=tig_runtime_path, help=f"Path to tig-runtime executable (default: {tig_runtime_path})")
|
||||
parser.add_argument("--lib-dir", type=str, default="./tig-algorithms/lib", help="Path to the algorithms library folder (default: ./tig-algorithms/lib)")
|
||||
parser.add_argument("--seed", type=str, default="rand_hash", help="String to use as seed instance generation (default: 'rand_hash')")
|
||||
parser.add_argument("--start", type=int, default=0, help="Starting nonce (default: 0)")
|
||||
parser.add_argument("--nonces", type=int, default=100, help="Number of nonces to process (default: 100)")
|
||||
parser.add_argument("--fuel", type=int, default=int(100e9), help="Max fuel (default: 100 billion)")
|
||||
parser.add_argument("--workers", type=int, default=1, help="Number of worker threads (default: 1)")
|
||||
parser.add_argument("--verbose", action='store_true', help="Print debug logs")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
so_path = f"{args.lib_dir}/{args.challenge}/{CPU_ARCH}/{args.algorithm}.so"
|
||||
ptx_path = f"{args.lib_dir}/{args.challenge}/ptx/{args.algorithm}.ptx"
|
||||
|
||||
if not os.path.exists(so_path):
|
||||
print(
|
||||
f"""Library not found at {so_path}:
|
||||
* To download: use download_algorithm
|
||||
* To build: use build_so and/or build_ptx
|
||||
* To set the lib folder: set --lib-dir <path_to_folder>
|
||||
""")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.exists(ptx_path):
|
||||
ptx_path = None
|
||||
elif not HAS_GPU:
|
||||
print(f"PTX file found at {ptx_path}, but no GPU support detected (failed to run nvidia-smi)")
|
||||
sys.exit(1)
|
||||
|
||||
difficulty = json.loads(args.difficulty)
|
||||
if not (
|
||||
isinstance(difficulty, list) and
|
||||
len(difficulty) == 2 and
|
||||
all(isinstance(x, int) for x in difficulty)
|
||||
):
|
||||
print("Difficulty must be a JSON array of two integers '[x,y]'")
|
||||
sys.exit(1)
|
||||
|
||||
challenge_ids = {
|
||||
"satisfiability": "c001",
|
||||
"vehicle_routing": "c002",
|
||||
"knapsack": "c003",
|
||||
"vector_search": "c004",
|
||||
"hypergraph": "c005",
|
||||
"optimiser": "c006",
|
||||
}
|
||||
challenge_id = challenge_ids.get(args.challenge, None)
|
||||
if challenge_id is None:
|
||||
print(f"Unknown challenge '{args.challenge}'. Choices: ({', '.join(challenge_ids.keys())})")
|
||||
sys.exit(1)
|
||||
|
||||
settings = {"algorithm_id": "", "challenge_id": challenge_id, "difficulty": difficulty, "block_id": "", "player_id": ""}
|
||||
pool = ThreadPoolExecutor(max_workers=args.workers + 1)
|
||||
|
||||
results = {}
|
||||
def print_results():
|
||||
start = now()
|
||||
while True:
|
||||
time.sleep(0.5)
|
||||
num_processing, num_finished, num_solutions = 0, 0, 0
|
||||
for (_, _, ret) in results.values():
|
||||
if ret is None:
|
||||
num_processing += 1
|
||||
else:
|
||||
num_finished += 1
|
||||
num_solutions += int(ret == 0)
|
||||
|
||||
elapsed = (now() - start) / 1000
|
||||
solution_ratio = num_solutions / (num_finished or 1)
|
||||
solution_rate = num_solutions / elapsed
|
||||
score = solution_rate * solution_ratio
|
||||
out = f"#processing: {num_processing}, #finished: {num_finished}, #solutions: {num_solutions}, elapsed: {elapsed:.2f}s, solution_ratio: {solution_ratio:.4f}, solution_rate: {solution_rate:.4f}, score: {score:.4f}"
|
||||
if args.verbose:
|
||||
print(out)
|
||||
else:
|
||||
print(f"\r{out}", end="")
|
||||
|
||||
if num_finished == args.nonces:
|
||||
break
|
||||
if not args.verbose:
|
||||
print("\n")
|
||||
|
||||
def run_tig_runtime(nonce):
|
||||
cmd = [
|
||||
args.tig_runtime_path,
|
||||
json.dumps(settings),
|
||||
args.seed,
|
||||
str(nonce),
|
||||
so_path,
|
||||
"--fuel", str(args.fuel),
|
||||
]
|
||||
if ptx_path is not None:
|
||||
cmd += [
|
||||
"--ptx", ptx_path,
|
||||
"--gpu", str(nonce % len(VISIBLE_GPUS)),
|
||||
]
|
||||
if args.verbose:
|
||||
print(f"computing nonce {nonce}: {' '.join(cmd)}")
|
||||
start = now()
|
||||
results[nonce] = (start, None, None)
|
||||
ret = subprocess.run(cmd, capture_output=True, text=True)
|
||||
elapsed = now() - start
|
||||
results[nonce] = (start, elapsed, ret.returncode)
|
||||
if args.verbose:
|
||||
out = f"computing nonce {nonce}: took {elapsed}ms, "
|
||||
if ret.returncode == 0:
|
||||
out += "found solution"
|
||||
elif ret.returncode == 1:
|
||||
out += f"error: {ret.stderr.strip()}"
|
||||
elif ret.returncode == 85:
|
||||
out += "no solution found"
|
||||
elif ret.returncode == 86:
|
||||
out += f"invalid solution: {ret.stderr.strip()}"
|
||||
elif ret.returncode == 87:
|
||||
out += "out of fuel"
|
||||
else:
|
||||
out += f"unknown exit code {ret.returncode}"
|
||||
print(out)
|
||||
|
||||
nonces = list(range(args.start, args.start + args.nonces))
|
||||
if args.verbose:
|
||||
print(f"Processing {len(nonces)} nonces with {args.workers} workers...")
|
||||
pool.submit(print_results)
|
||||
list(pool.map(run_tig_runtime, nonces))
|
||||
@ -1,173 +0,0 @@
|
||||
#!/bin/bash
|
||||
REPO_DIR=$(dirname $(dirname "$(realpath "$0")"))
|
||||
TIG_WORKER_PATH="$REPO_DIR/target/release/tig-worker"
|
||||
|
||||
if [ ! -f $TIG_WORKER_PATH ]; then
|
||||
echo "Error: tig-worker binary not found at ./target/release/tig-worker"
|
||||
echo "Run: cd $REPO_DIR && cargo build -p tig-worker --release"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
options=()
|
||||
index=0
|
||||
echo "Available WASMs:"
|
||||
for w in $(find $REPO_DIR/tig-algorithms/wasm -name '*.wasm'); do
|
||||
a_name=$(basename $w .wasm)
|
||||
c_name=$(basename $(dirname $w))
|
||||
echo "$index) $c_name/$a_name"
|
||||
options+=("$c_name/$a_name")
|
||||
index=$((index + 1))
|
||||
done
|
||||
echo "Don't see the algorithm you're looking for? Can run: git pull origin <challenge_name>/<algorithm_name> --no-edit"
|
||||
read -p "Enter the index of the algorithm to test: " selected_index
|
||||
if [[ $selected_index =~ ^[0-9]+$ ]] && [ "$selected_index" -ge 0 ] && [ "$selected_index" -lt "$index" ]; then
|
||||
selected_option=${options[$selected_index]}
|
||||
echo "Testing: $selected_option"
|
||||
else
|
||||
echo "Invalid index"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CHALLENGE=$(dirname $selected_option)
|
||||
ALGORITHM=$(basename $selected_option)
|
||||
|
||||
case $CHALLENGE in
|
||||
satisfiability)
|
||||
CHALLENGE_ID="c001"
|
||||
;;
|
||||
vehicle_routing)
|
||||
CHALLENGE_ID="c002"
|
||||
;;
|
||||
knapsack)
|
||||
CHALLENGE_ID="c003"
|
||||
;;
|
||||
vector_search)
|
||||
CHALLENGE_ID="c004"
|
||||
;;
|
||||
*)
|
||||
echo "Error: Challenge '$CHALLENGE' is not recognized."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
read -p "Enter difficulty for $CHALLENGE in format [x,y]: " difficulty
|
||||
regex='^\[[0-9]+,[0-9]+\]$'
|
||||
if ! [[ $difficulty =~ $regex ]]; then
|
||||
echo "Error: Difficulty must be in the format [x,y] where x and y are positive integers."
|
||||
exit 1
|
||||
fi
|
||||
is_positive_integer() {
|
||||
[[ $1 =~ ^[0-9]+$ ]] && [ "$1" -ge 0 ]
|
||||
}
|
||||
read -p "Enter starting nonce: " start_nonce
|
||||
if ! is_positive_integer "$start_nonce"; then
|
||||
echo "Error: Starting nonce must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
read -p "Enter number of nonces: " num_nonces
|
||||
if ! is_positive_integer "$num_nonces"; then
|
||||
echo "Error: Number of nonces must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
read -p "Enter number of workers (default is 1): " num_workers
|
||||
num_workers=${num_workers:-1}
|
||||
if ! is_positive_integer "$num_workers"; then
|
||||
echo "Error: Number of workers must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
read -p "Enter max fuel (default is 10000000000): " max_fuel
|
||||
max_fuel=${max_fuel:-10000000000}
|
||||
if ! is_positive_integer "$max_fuel"; then
|
||||
echo "Error: Max fuel must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
read -p "Enable debug mode? (leave blank to disable) " enable_debug
|
||||
if [[ -n $enable_debug ]]; then
|
||||
debug_mode=true
|
||||
else
|
||||
debug_mode=false
|
||||
fi
|
||||
|
||||
get_closest_power_of_2() {
|
||||
local n=$1
|
||||
local p=1
|
||||
while [ $p -lt $n ]; do
|
||||
p=$((p * 2))
|
||||
done
|
||||
echo $p
|
||||
}
|
||||
|
||||
|
||||
SETTINGS="{\"challenge_id\":\"$CHALLENGE_ID\",\"difficulty\":$difficulty,\"algorithm_id\":\"\",\"player_id\":\"\",\"block_id\":\"\"}"
|
||||
num_solutions=0
|
||||
num_invalid=0
|
||||
total_ms=0
|
||||
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Testing performance of $CHALLENGE/$ALGORITHM"
|
||||
echo "Settings: $SETTINGS"
|
||||
echo "Starting nonce: $start_nonce"
|
||||
echo "Number of nonces: $num_nonces"
|
||||
echo "Number of workers: $num_workers"
|
||||
echo -ne ""
|
||||
|
||||
remaining_nonces=$num_nonces
|
||||
current_nonce=$start_nonce
|
||||
|
||||
while [ $remaining_nonces -gt 0 ]; do
|
||||
nonces_to_compute=$((num_workers < remaining_nonces ? num_workers : remaining_nonces))
|
||||
|
||||
power_of_2_nonces=$(get_closest_power_of_2 $nonces_to_compute)
|
||||
|
||||
start_time=$(date +%s%3N)
|
||||
stdout=$(mktemp)
|
||||
stderr=$(mktemp)
|
||||
./target/release/tig-worker compute_batch "$SETTINGS" "random_string" $current_nonce $nonces_to_compute $power_of_2_nonces $REPO_DIR/tig-algorithms/wasm/$CHALLENGE/$ALGORITHM.wasm --workers $nonces_to_compute --fuel $max_fuel >"$stdout" 2>"$stderr"
|
||||
exit_code=$?
|
||||
output_stdout=$(cat "$stdout")
|
||||
output_stderr=$(cat "$stderr")
|
||||
end_time=$(date +%s%3N)
|
||||
duration=$((end_time - start_time))
|
||||
total_ms=$((total_ms + (duration * nonces_to_compute)))
|
||||
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
solutions_count=$(echo "$output_stdout" | grep -o '"solution_nonces":\[.*\]' | sed 's/.*\[\(.*\)\].*/\1/' | awk -F',' '{print NF}')
|
||||
invalid_count=$((nonces_to_compute - solutions_count))
|
||||
num_solutions=$((num_solutions + solutions_count))
|
||||
num_invalid=$((num_invalid + invalid_count))
|
||||
fi
|
||||
|
||||
if [ $num_solutions -eq 0 ]; then
|
||||
avg_ms_per_solution=0
|
||||
else
|
||||
avg_ms_per_solution=$((total_ms / num_solutions))
|
||||
fi
|
||||
|
||||
if [[ $debug_mode == true ]]; then
|
||||
echo " Current nonce: $current_nonce"
|
||||
echo " Nonces computed: $nonces_to_compute"
|
||||
echo " Exit code: $exit_code"
|
||||
echo " Stdout: $output_stdout"
|
||||
echo " Stderr: $output_stderr"
|
||||
echo " Duration: $duration ms"
|
||||
echo "#instances: $((num_solutions + num_invalid)), #solutions: $num_solutions, #invalid: $num_invalid, average ms/solution: $avg_ms_per_solution"
|
||||
else
|
||||
echo -ne "#instances: $((num_solutions + num_invalid)), #solutions: $num_solutions, #invalid: $num_invalid, average ms/solution: $avg_ms_per_solution\033[K\r"
|
||||
fi
|
||||
|
||||
current_nonce=$((current_nonce + nonces_to_compute))
|
||||
remaining_nonces=$((remaining_nonces - nonces_to_compute))
|
||||
done
|
||||
|
||||
echo
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "To re-run this test, run the following commands:"
|
||||
echo " git clone https://github.com/tig-foundation/tig-monorepo.git"
|
||||
echo " cd tig-monorepo"
|
||||
echo " git pull origin/$CHALLENGE/$ALGORITHM --no-edit"
|
||||
echo " bash scripts/test_algorithm.sh"
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Share your results on https://www.reddit.com/r/TheInnovationGame"
|
||||
echo "----------------------------------------------------------------------"
|
||||
rm "$stdout" "$stderr"
|
||||
@ -1,83 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
REPO_DIR=$(dirname $(dirname "$(realpath "$0")"))
|
||||
TIG_WORKER_PATH="$REPO_DIR/target/release/tig-worker"
|
||||
|
||||
if [ ! -f $TIG_WORKER_PATH ]; then
|
||||
echo "Error: tig-worker binary not found at ./target/release/tig-worker"
|
||||
echo "Run: cd $REPO_DIR && cargo build -p tig-worker --release"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -p "Enter benchmark_id: " benchmark_id
|
||||
|
||||
echo "Fetching benchmark data"
|
||||
response=$(curl -s "https://mainnet-api.tig.foundation/get-benchmark-data?benchmark_id=$benchmark_id")
|
||||
|
||||
# parse data from resp
|
||||
proof=$(echo "$response" | python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
for item in data['proof']['solutions_data']:
|
||||
item['nonce'] = str(item['nonce'])
|
||||
print(json.dumps(data))
|
||||
" | jq '.proof')
|
||||
if [ "$proof" == "null" ]; then
|
||||
echo "No proofs found"
|
||||
exit 0
|
||||
fi
|
||||
solutions_count=$(echo "$proof" | jq -r '.solutions_data | length')
|
||||
settings=$(echo "$response" | jq -r '.benchmark.settings')
|
||||
algorithm_id=$(echo "$settings" | jq -r '.algorithm_id')
|
||||
echo "Found $solutions_count solutions to verify"
|
||||
|
||||
# Fetch block id
|
||||
echo "Fetching block data"
|
||||
block_response=$(curl -s "https://mainnet-api.tig.foundation/get-block")
|
||||
block_id=$(echo "$block_response" | jq -r '.block.id')
|
||||
|
||||
# Fetch algorithms for the block
|
||||
echo "Fetching algorithms data"
|
||||
algorithms_response=$(curl -s "https://mainnet-api.tig.foundation/get-algorithms?block_id=$block_id")
|
||||
wasms=$(echo "$algorithms_response" | jq -c '.wasms[]')
|
||||
|
||||
wasm=$(echo "$wasms" | jq -c "select(.algorithm_id == \"$algorithm_id\")")
|
||||
|
||||
if [ -z "$wasm" ]; then
|
||||
echo "No matching WASM found for $algorithm_id"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
compile_success=$(echo "$wasm" | jq -r '.details.compile_success')
|
||||
if [ "$compile_success" == "false" ]; then
|
||||
echo "WASM was not successful compiled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
download_url=$(echo "$wasm" | jq -r '.details.download_url')
|
||||
echo "Downloading WASM from $download_url"
|
||||
curl -s -o "$algorithm_id.wasm" "$download_url"
|
||||
|
||||
# verify solutions
|
||||
for i in $(seq 0 $(($solutions_count - 1))); do
|
||||
solution_data=$(echo "$proof" | jq -c -S ".solutions_data[$i]")
|
||||
echo Verifying $solution_data
|
||||
nonce=$(echo "$solution_data" | jq -r '.nonce')
|
||||
solution=$(echo "$solution_data" | jq -r '.solution')
|
||||
echo Verifying solution is valid
|
||||
./target/release/tig-worker verify_solution "$settings" $nonce "$solution"
|
||||
echo Verifying runtime_signature and fuel_consumed
|
||||
compute_output=$(./target/release/tig-worker compute_solution "$settings" $nonce ./$algorithm_id.wasm | python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
data['nonce'] = str(data['nonce'])
|
||||
print(json.dumps(data))
|
||||
" | jq -c -S)
|
||||
if [[ "$compute_output" == "$solution_data" ]]; then
|
||||
echo "Ok"
|
||||
else
|
||||
echo "Mismatch. Actual: $compute_output"
|
||||
fi
|
||||
done
|
||||
rm $algorithm_id.wasm
|
||||
Loading…
Reference in New Issue
Block a user