Skip to content

Commit 747b480

Browse files
committed
Fix links and add script
1 parent 15e7eec commit 747b480

12 files changed

+224
-14
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ witness.wtns
3535
*.zkey
3636
circuit_cpp/
3737
circuit_js
38+
39+
# Link checker results
40+
docs/dead_links_report.txt

docs/3_guides/0_submitting_proofs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ This will create the ECDSA keystore file in `~/.aligned_keystore/keystore0`
6161

6262
### Alternative 2: With EigenLayer CLI
6363

64-
- If you have the EigenLayer CLI installed, the keystore can be generated following [these](https://docs.eigenlayer.xyz/eigenlayer/operator-guides/operator-installation#import-keys) instructions. The key will be stored into `~/.eigenlayer/operator_keys`.
64+
- If you have the EigenLayer CLI installed, the keystore can be generated following [these](https://docs.eigencloud.xyz/products/eigenlayer/operators/howto/operator-installation) instructions. The key will be stored into `~/.eigenlayer/operator_keys`.
6565

6666
## 2. Send funds to Aligned
6767

docs/3_guides/2.2_modify_zkquiz_questions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ if output
7474
## 3. Compile the Program
7575

7676
Now we need to compile the updated Program, generating the binary file that will be run by the zkVM (ELF).
77-
For this, ensure that the [SP1 Rust toolchain](https://docs.succinct.xyz/introduction.html) is installed. Run:
77+
For this, ensure that the [SP1 Rust toolchain](https://docs.succinct.xyz/docs/sp1/introduction) is installed. Run:
7878

7979
```
8080
make compile_elf

docs/3_guides/2_build_your_first_aligned_application.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ ZkQuiz has three main components:
9696
The user interacts with ZkQuiz App to solve a trivia challenge answering questions. Then, the App generates a Zk Proof with the Program generated using SP1.
9797

9898
{% hint style="info" %}
99-
The ZkQuiz Program is built using SP1 following the [quickstart guide](https://docs.succinct.xyz/getting-started/quickstart.html#project-overview). For your projects, you can user any of the [prooving systems supported by Aligned](../2_architecture/0_supported_verifiers.md).
99+
The ZkQuiz Program is built using SP1 following the [quickstart guide](https://docs.succinct.xyz/docs/sp1/getting-started/quickstart). For your projects, you can user any of the [prooving systems supported by Aligned](../2_architecture/0_supported_verifiers.md).
100100
{% endhint %}
101101

102102
Once the proof is generated, the App sends the proof to Aligned, and once it is verified, the App calls to the ZkQuiz Verifier Contract to check the proof verification and send an NFT to the user is the proof was verified in Aligned.

docs/3_guides/3_validating_public_input.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This guide demonstrates how to validate Risc0 and SP1 proofs using the Aligned S
77
In this case, the Fibonacci number to be calculated is **500** and the last two numbers of the sequence modulo 7919 are **1268** and **1926**.
88

99
## Requirements
10-
- [SP1](https://docs.succinct.xyz/getting-started/install.html)
10+
- [SP1](https://docs.succinct.xyz/docs/sp1/getting-started/install)
1111
- [Risc0](https://dev.risczero.com/api/zkvm/install)
1212
- [Foundry](https://book.getfoundry.sh/getting-started/installation)
1313

@@ -29,7 +29,7 @@ For `SP1`, the Fibonacci program is located in `examples/validating-public-input
2929

3030
> [!IMPORTANT]
3131
> To generate the proof ensure you have [docker](https://www.docker.com/get-started/) installed and the docker daemon running.
32-
> This is necessary to ensure deterministic builds of the binary we want to generate a proof of. If not used, builds may differ depending on the system you are running on. To know more about this, check [this link](https://dev.risczero.com/terminology#deterministic-builds) from RiscZero docs or [this](https://docs.succinct.xyz/writing-programs/compiling.html#advanced-build-options-1) from SP1.
32+
> This is necessary to ensure deterministic builds of the binary we want to generate a proof of. If not used, builds may differ depending on the system you are running on. To know more about this, check [this link](https://dev.risczero.com/terminology#deterministic-builds) from RiscZero docs or [this](https://docs.succinct.xyz/docs/sp1/writing-programs/compiling) from SP1.
3333
3434
To submit proofs to **Aligned** and get them verified, you first need to generate those proofs. Every proving system has its own method for generating proofs.
3535

docs/3_guides/4_generating_proofs.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
This guide assumes that:
88

9-
- sp1 prover installed (instructions [here](https://succinctlabs.github.io/sp1/getting-started/install.html))
9+
- sp1 prover installed (instructions [here](https://docs.succinct.xyz/docs/sp1/getting-started/install))
1010
- sp1 project to generate the proofs
11-
(instructions [here](https://succinctlabs.github.io/sp1/generating-proofs/setup.html))
11+
(instructions [here](https://docs.succinct.xyz/docs/sp1/getting-started/quickstart))
1212
- aligned installed (instructions [here](../1_introduction/1_try_aligned.md#quickstart))
1313

1414
### How to generate a proof

docs/3_guides/7_contract_addresses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Below is the list of supported strategies available on Aligned Mainnet:
3232
| [lsETH](https://app.eigenlayer.xyz/restake/lsETH) | [0xAe60d8180437b5C34bB956822ac2710972584473](https://etherscan.io/address/0xAe60d8180437b5C34bB956822ac2710972584473) |
3333
| [mETH](https://app.eigenlayer.xyz/restake/mETH) | [0x298aFB19A105D59E74658C4C334Ff360BadE6dd2](https://etherscan.io/address/0x298aFB19A105D59E74658C4C334Ff360BadE6dd2) |
3434

35-
For additional details, refer to the [official EigenLayer documentation](https://github.com/Layr-Labs/eigenlayer-contracts/tree/mainnet?tab=readme-ov-file#strategies).
35+
For additional details, refer to the [official EigenLayer documentation](https://github.com/Layr-Labs/eigenlayer-contracts).
3636

3737

3838
## Holesky Deployments

docs/3_guides/setup_holesky.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
These contracts are not deployed by Aligned. Current EigenLayer contracts:
66

7-
- [Holesky Contracts](https://github.com/Layr-Labs/eigenlayer-contracts/blob/testnet-holesky/script/configs/holesky/Holesky_current_deployment.config.json)
8-
- [Mainnet Contracts](https://github.com/Layr-Labs/eigenlayer-contracts/blob/mainnet/script/configs/mainnet/Mainnet_current_deployment.config.json)
7+
- [Holesky Contracts](https://github.com/Layr-Labs/eigenlayer-contracts/blob/main/script/configs/holesky.json)
8+
- [Mainnet Contracts](https://github.com/Layr-Labs/eigenlayer-contracts/blob/main/script/configs/mainnet.json)
99

1010
## Aligned Contracts: Holesky/Mainnet
1111

docs/about_aligned/learning_resources.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Aligned blog post:
44

5-
* [Aligned](https://blog.alignedlayer.com/aligned-layer/)
5+
* [Aligned Blog](https://blog.alignedlayer.com)
66

77
## Aligned repo:
88

docs/check_markdown_links.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import re
5+
import urllib.request
6+
import urllib.error
7+
from concurrent.futures import ThreadPoolExecutor, as_completed
8+
from datetime import datetime
9+
import threading
10+
import time
11+
import random
12+
13+
# Thread-safe counters
14+
alive_count = 0
15+
dead_count = 0
16+
count_lock = threading.Lock()
17+
18+
def find_markdown_files():
19+
"""Find all markdown files in the current directory"""
20+
md_files = []
21+
docs_path = "."
22+
23+
if not os.path.exists(docs_path):
24+
print(f"Current folder not found")
25+
return md_files
26+
27+
for root, dirs, files in os.walk(docs_path):
28+
for file in files:
29+
if file.endswith('.md'):
30+
md_files.append(os.path.join(root, file))
31+
32+
return md_files
33+
34+
def extract_links_from_file(file_path):
35+
"""Extract HTTP/HTTPS links from a markdown file"""
36+
links = []
37+
38+
try:
39+
with open(file_path, 'r', encoding='utf-8') as f:
40+
for line_num, line in enumerate(f, 1):
41+
# Find markdown links [text](url)
42+
markdown_links = re.findall(r'\[([^\]]*)\]\(([^)]+)\)', line)
43+
for text, url in markdown_links:
44+
if url.startswith(('http://', 'https://')):
45+
links.append((file_path, line_num, url.strip()))
46+
47+
# Find direct links <url>
48+
direct_links = re.findall(r'<(https?://[^>]+)>', line)
49+
for url in direct_links:
50+
links.append((file_path, line_num, url.strip()))
51+
52+
except Exception as e:
53+
print(f"Error reading {file_path}: {e}")
54+
55+
return links
56+
57+
def check_link_with_retry(file_path, line_num, url, max_retries=3):
58+
"""Check if a link is alive or dead with retry logic for rate limiting"""
59+
global alive_count, dead_count
60+
61+
for attempt in range(max_retries):
62+
try:
63+
# Create request with a user agent to avoid 403 errors
64+
req = urllib.request.Request(
65+
url,
66+
headers={'User-Agent': 'Mozilla/5.0 (compatible; LinkChecker/1.0)'}
67+
)
68+
69+
# Set timeout for the request
70+
with urllib.request.urlopen(req, timeout=15) as response:
71+
status_code = response.getcode()
72+
if 200 <= status_code < 400:
73+
with count_lock:
74+
alive_count += 1
75+
return 'ALIVE', file_path, line_num, url, None
76+
else:
77+
with count_lock:
78+
dead_count += 1
79+
return 'DEAD', file_path, line_num, url, f"HTTP {status_code}"
80+
81+
except urllib.error.HTTPError as e:
82+
if e.code == 429: # Too Many Requests
83+
if attempt < max_retries - 1: # Don't wait on last attempt
84+
# Exponential backoff with jitter
85+
wait_time = (2 ** attempt) + random.uniform(0, 1)
86+
print(f"⏳ Rate limited for {url}, waiting {wait_time:.1f}s before retry {attempt + 2}/{max_retries}")
87+
time.sleep(wait_time)
88+
continue
89+
else:
90+
# Final attempt failed with rate limiting
91+
with count_lock:
92+
alive_count += 1 # Assume it's alive if we're just rate limited
93+
return 'ALIVE', file_path, line_num, url, "Rate limited (assumed alive)"
94+
else:
95+
# Other HTTP errors (404, 403, etc.) - don't retry
96+
with count_lock:
97+
dead_count += 1
98+
return 'DEAD', file_path, line_num, url, f"HTTP {e.code}: {e.reason}"
99+
100+
except (urllib.error.URLError, Exception) as e:
101+
if attempt < max_retries - 1:
102+
# Retry on network errors
103+
wait_time = (2 ** attempt) + random.uniform(0, 1)
104+
print(f"⏳ Network error for {url}, waiting {wait_time:.1f}s before retry {attempt + 2}/{max_retries}")
105+
time.sleep(wait_time)
106+
continue
107+
else:
108+
# Final attempt failed
109+
with count_lock:
110+
dead_count += 1
111+
return 'DEAD', file_path, line_num, url, str(e)
112+
113+
def main():
114+
global alive_count, dead_count
115+
116+
print("Starting markdown link checking...")
117+
print("==================================")
118+
119+
# Find all markdown files
120+
print("Finding markdown files in current folder and extracting links...")
121+
md_files = find_markdown_files()
122+
123+
if not md_files:
124+
print("No markdown files found in current folder.")
125+
return
126+
127+
# Extract all links
128+
all_links = []
129+
for file_path in md_files:
130+
links = extract_links_from_file(file_path)
131+
all_links.extend(links)
132+
133+
print(f"Found {len(all_links)} HTTP/HTTPS links to check in current folder")
134+
135+
if not all_links:
136+
print("No HTTP/HTTPS links found in markdown files.")
137+
return
138+
139+
# Check links in parallel
140+
print("Checking links...")
141+
dead_links = []
142+
results = []
143+
144+
# Use ThreadPoolExecutor for parallel processing
145+
with ThreadPoolExecutor(max_workers=20) as executor:
146+
# Submit all link checking tasks
147+
future_to_link = {
148+
executor.submit(check_link_with_retry, file_path, line_num, url): (file_path, line_num, url)
149+
for file_path, line_num, url in all_links
150+
}
151+
152+
# Process results as they complete
153+
for future in as_completed(future_to_link):
154+
status, file_path, line_num, url, error = future.result()
155+
156+
if status == 'ALIVE':
157+
if error:
158+
print(f"✓ ALIVE: {url} ({error})")
159+
else:
160+
print(f"✓ ALIVE: {url}")
161+
else:
162+
print(f"✗ DEAD: {url} ({error})")
163+
dead_links.append((file_path, line_num, url, error))
164+
165+
results.append((status, file_path, line_num, url, error))
166+
167+
# Calculate statistics
168+
total_checked = alive_count + dead_count
169+
alive_percentage = (alive_count * 100) // total_checked if total_checked > 0 else 0
170+
dead_percentage = (dead_count * 100) // total_checked if total_checked > 0 else 0
171+
172+
# Display summary
173+
print("\n===============================")
174+
print("LINK CHECK SUMMARY")
175+
print("===============================")
176+
print(f"Total links found: {len(all_links)}")
177+
print(f"Total links checked: {total_checked}")
178+
print(f"Alive links: {alive_count} ({alive_percentage}%)")
179+
print(f"Dead links: {dead_count} ({dead_percentage}%)")
180+
print()
181+
182+
# Save dead links to file and display them
183+
if dead_links:
184+
output_file = "dead_links_report.txt"
185+
with open(output_file, 'w') as f:
186+
f.write(f"Dead Links Report - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
187+
f.write("================================\n\n")
188+
189+
for file_path, line_num, url, error in dead_links:
190+
f.write(f"File: {file_path}\n")
191+
f.write(f"Line: {line_num}\n")
192+
f.write(f"URL: {url}\n")
193+
f.write(f"Error: {error}\n")
194+
f.write("---\n")
195+
196+
print(f"Dead links details saved to: {output_file}")
197+
print("\nDEAD LINKS:")
198+
print("----------")
199+
for file_path, line_num, url, error in dead_links:
200+
print(f"{file_path}:{line_num} - {url}")
201+
else:
202+
print("🎉 All links are alive!")
203+
204+
print("\nLink checking complete!")
205+
206+
if __name__ == "__main__":
207+
main()

0 commit comments

Comments
 (0)