Add script to pin all actual Tornado Cash IPFS hashes on any debian server
This commit is contained in:
parent
ab3ab530c0
commit
9d6c6144bf
File diff suppressed because one or more lines are too long
@ -1,30 +0,0 @@
|
|||||||
# Tornado Cash decentralized sources
|
|
||||||
|
|
||||||
This is an entrypoint page to source code and minified versions of all Tornado Cash services and packages.
|
|
||||||
|
|
||||||
### Basic users guide
|
|
||||||
|
|
||||||
If you want to use trusted local versions of Tornado sites, you can download it directly from IPFS:
|
|
||||||
|
|
||||||
1. Classic UI (main site) - [classic-ui.minified.sources.tornadocash.eth](https://app.ens.domains/classic-ui.minified.sources.tornadocash.eth), actual IPFS hash - `bafybeia4x75bn74prpmi6jqa6gbgmsfovunnke5s6oyrddxyopnz6kw5le`
|
|
||||||
2. Nova UI - [nova.minified.sources.tornadocash.eth](https://app.ens.domains/nova.minified.sources.tornadocash.eth), actual IPFS hash - `bafybeihr5h2tfonjn2gybd4yhvchdwt4eyo25lf5twhhn6bnasdv2wwz7i`
|
|
||||||
3. Tornado CLI - [cli.minified.sources.tornadocash.eth](https://app.ens.domains/cli.minified.sources.tornadocash.eth), actual IPFS hash - `bafybeicxxyqjgx5ggvujij4fnjdcwkep4nj5662yrxftb7y3pzwl77qntq`
|
|
||||||
|
|
||||||
Just click on `contenthash` field by link or copy IPFS hash and paste in [any IPFS gateway](https://ipfs.github.io/public-gateway-checker/), and then file start downloading.
|
|
||||||
|
|
||||||
### Developers guide
|
|
||||||
|
|
||||||
Download all Tornado Cash git repositories is easy via special tool located on [download.sources.tornadocash.eth](https://app.ens.domains/download.sources.tornadocash.eth).
|
|
||||||
|
|
||||||
Clone repo with tool via any IPFS resolver by CID on ENS domain above and follow tool readme (located in repo), for example:
|
|
||||||
|
|
||||||
````
|
|
||||||
git clone https://ipfs.io/ipfs/bafybeienn6huru6cxs3ovl5ogeik2wnvviqtoainqj4zn2q3q7zzezvu6u downloader-tool
|
|
||||||
````
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://cloudflare-ipfs.com/ipfs/bafybeienn6huru6cxs3ovl5ogeik2wnvviqtoainqj4zn2q3q7zzezvu6u
|
|
||||||
```
|
|
||||||
|
|
128
scripts/hostIPFS.sh
Normal file
128
scripts/hostIPFS.sh
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script must be running from root
|
||||||
|
if [ "$EUID" -ne 0 ];
|
||||||
|
then echo "Please run as root";
|
||||||
|
exit 1;
|
||||||
|
fi;
|
||||||
|
|
||||||
|
this_repo_ipfs_cid="bafybeienn6huru6cxs3ovl5ogeik2wnvviqtoainqj4zn2q3q7zzezvu6u";
|
||||||
|
user_home_dir=$(eval echo ~$USER);
|
||||||
|
tornado_folder="$user_home_dir/tornado-ipfs";
|
||||||
|
script_log_file="/tmp/tornado-ipfs-installation.log";
|
||||||
|
cron_script_path="$tornado_folder/cronfile.cron";
|
||||||
|
|
||||||
|
function echo_log_err(){
|
||||||
|
echo $1 1>&2;
|
||||||
|
echo -e "$1\n" &>> $script_log_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
function echo_log_err_and_exit(){
|
||||||
|
echo_log_err "$1";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_if_exists(){
|
||||||
|
if test -d $1; then rm -rf $1; fi;
|
||||||
|
if test -f $1; then rm $1; fi;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_package_installed(){
|
||||||
|
if [ $(dpkg-query -W -f='${Status}' $1 2>/dev/null | grep -c "ok installed") -eq 0 ]; then return 1; else return 0; fi;
|
||||||
|
}
|
||||||
|
|
||||||
|
function install_requred_packages(){
|
||||||
|
apt update &>> $script_log_file;
|
||||||
|
|
||||||
|
requred_packages=("curl" "git" "ufw" "cron");
|
||||||
|
local package;
|
||||||
|
for package in ${requred_packages[@]}; do
|
||||||
|
if ! is_package_installed $package; then
|
||||||
|
# Kill apache process, because Debian configuring nginx package right during installation
|
||||||
|
if [ $package = "nginx" ]; then systemctl stop apache2; fi;
|
||||||
|
apt install --yes --force-yes -o DPkg::Options::="--force-confold" $package &>> $script_log_file;
|
||||||
|
if ! is_package_installed $package; then
|
||||||
|
echo_log_err_and_exit "Error: cannot install \"$package\" package";
|
||||||
|
fi;
|
||||||
|
fi;
|
||||||
|
done;
|
||||||
|
|
||||||
|
echo -e "\nAll required packages installed successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
function install_node(){
|
||||||
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash &>> $script_log_file;
|
||||||
|
. ~/.nvm/nvm.sh;
|
||||||
|
. ~/.profile;
|
||||||
|
. ~/.bashrc;
|
||||||
|
nvm install 16.20.2 &>> $script_log_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
function download_repo(){
|
||||||
|
ipfs_gateways=("https://ipfs.io/ipfs" "https://dweb.link/ipfs" "https://cloudflare-ipfs.com/ipfs" "https://gateway.pinata.cloud/ipfs" "https://hardbin.com/ipfs");
|
||||||
|
for gateway in ${ipfs_gateways[@]}; do
|
||||||
|
delete_if_exists $tornado_folder;
|
||||||
|
if git clone $gateway/$this_repo_ipfs_cid $tornado_folder; then break; fi;
|
||||||
|
done;
|
||||||
|
if [ ! -d $tornado_folder ]; then echo_log_err_and_exit "Cannot download repository from IPFS"; fi;
|
||||||
|
}
|
||||||
|
|
||||||
|
function install_node_dependencies(){
|
||||||
|
npm i -g yarn &>> $script_log_file;
|
||||||
|
cd $tornado_folder;
|
||||||
|
yarn &>> $script_log_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_ipfs_daemon(){
|
||||||
|
cd $tornado_folder;
|
||||||
|
wget https://dist.ipfs.tech/kubo/v0.22.0/kubo_v0.22.0_linux-amd64.tar.gz;
|
||||||
|
tar -xvzf kubo_v0.22.0_linux-amd64.tar.gz;
|
||||||
|
cd kubo;
|
||||||
|
sudo bash install.sh;
|
||||||
|
ipfs init --profile server;
|
||||||
|
sudo -b ipfs daemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
function configure_firewall(){
|
||||||
|
ufw allow 8080;
|
||||||
|
ufw allow 4001;
|
||||||
|
ufw deny 5000;
|
||||||
|
ufw deny 5001;
|
||||||
|
ufw insert 1 allow OpenSSH;
|
||||||
|
echo "y" | ufw enable;
|
||||||
|
ufw reload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_to_cron(){
|
||||||
|
delete_if_exists $cron_script_path;
|
||||||
|
|
||||||
|
# Add startup script to cron (job sheduler) to up IPFS daemon after restart
|
||||||
|
echo "@reboot ipfs daemon &" > $cron_script_path;
|
||||||
|
|
||||||
|
# Add existing cron rules (not related to this ipfs) to cron script, so that they are not removed
|
||||||
|
# https://unix.stackexchange.com/questions/21297/how-do-i-add-an-entry-to-my-crontab
|
||||||
|
crontab -l | grep -v "ipfs daemon" >> $cron_script_path;
|
||||||
|
|
||||||
|
crontab $cron_script_path;
|
||||||
|
systemctl restart cron;
|
||||||
|
|
||||||
|
if crontab -l | grep -q "ipfs daemon"; then
|
||||||
|
echo "IPFS daemon added to cron autorun successfully";
|
||||||
|
else
|
||||||
|
echo_log_err "Warning: adding script to cron autorun failed.";
|
||||||
|
fi;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_pinner(){
|
||||||
|
cd $tornado_folder;
|
||||||
|
yarn pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
install_requred_packages;
|
||||||
|
install_node;
|
||||||
|
download_repo;
|
||||||
|
install_node_dependencies;
|
||||||
|
run_ipfs_daemon;
|
||||||
|
configure_firewall;
|
||||||
|
add_to_cron;
|
||||||
|
run_pinner;
|
15
scripts/pinIPFS.ts
Normal file
15
scripts/pinIPFS.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { getV1Cids } from "../src/downloader.ts";
|
||||||
|
import { mainRepos, packageRepos, sitesENS, sourcesDomain } from "../src/contstants.ts";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
|
const ensDomains = [...Object.values(mainRepos), ...Object.values(packageRepos), ...sitesENS, sourcesDomain];
|
||||||
|
const ipfsCids = await getV1Cids(ensDomains.reduce((acc, dom) => Object.assign(acc, { [dom]: dom }), {}));
|
||||||
|
for (const [domain, cid] of Object.entries(ipfsCids)) {
|
||||||
|
try {
|
||||||
|
execSync(`ipfs pin add ${cid}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Cannot pin ipfs content by cid ${cid} for domain ${domain}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("IPFS cids successfully added");
|
@ -1,7 +1,7 @@
|
|||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
|
|
||||||
const rootTornadoDomain = process.env.ENS_ROOT_DOMAIN || "tornadocash.eth";
|
const rootTornadoDomain = process.env.ENS_ROOT_DOMAIN || "tornadocash.eth";
|
||||||
const sourcesDomain = "sources." + rootTornadoDomain;
|
export const sourcesDomain = "sources." + rootTornadoDomain;
|
||||||
const packagesDomain = "packages." + sourcesDomain;
|
const packagesDomain = "packages." + sourcesDomain;
|
||||||
|
|
||||||
export const mainRepos = {
|
export const mainRepos = {
|
||||||
@ -30,6 +30,8 @@ export const packageRepos = {
|
|||||||
"merkle-root-updater": "merkle-root-updater." + packagesDomain,
|
"merkle-root-updater": "merkle-root-updater." + packagesDomain,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const sitesENS = ["tornadocash.eth", "nova.tornadocash.eth", "relayers-ui.tornadocash.eth", "docs.tornadocash.eth"] as const;
|
||||||
|
|
||||||
export const knownIpfsResources = [
|
export const knownIpfsResources = [
|
||||||
`https://ipfs.io/ipfs/`,
|
`https://ipfs.io/ipfs/`,
|
||||||
`https://dweb.link/ipfs/`,
|
`https://dweb.link/ipfs/`,
|
||||||
|
@ -10,7 +10,7 @@ import { Domains, IPFSCids, RepoName } from "./types.ts";
|
|||||||
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL || "https://rpc.mevblocker.io");
|
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL || "https://rpc.mevblocker.io");
|
||||||
const git: SimpleGit = simpleGit();
|
const git: SimpleGit = simpleGit();
|
||||||
|
|
||||||
async function getENSDomainContenthash(repoName: RepoName, domain: string): Promise<[RepoName, string]> {
|
async function getENSDomainContenthash(domain: string): Promise<string> {
|
||||||
const resolver = await provider.getResolver(domain);
|
const resolver = await provider.getResolver(domain);
|
||||||
if (!resolver) throw new Error(`Resolver for domain ${domain} not found!`);
|
if (!resolver) throw new Error(`Resolver for domain ${domain} not found!`);
|
||||||
|
|
||||||
@ -19,18 +19,18 @@ async function getENSDomainContenthash(repoName: RepoName, domain: string): Prom
|
|||||||
if (!contentHash.startsWith("ipfs")) throw new Error(`Contenthash for domain ${domain} invalid, non-IPFS format: ${contentHash}`);
|
if (!contentHash.startsWith("ipfs")) throw new Error(`Contenthash for domain ${domain} invalid, non-IPFS format: ${contentHash}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return [repoName, cidV0ToV1Base32(contentHash.replace("ipfs://", ""))];
|
return cidV0ToV1Base32(contentHash.replace("ipfs://", ""));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Contenthash for domain ${domain} is invalid, cannot convert to V1 IPFS CID: ${contentHash}`);
|
throw new Error(`Contenthash for domain ${domain} is invalid, cannot convert to V1 IPFS CID: ${contentHash}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getV1Cids(domains: Domains): Promise<IPFSCids> {
|
export async function getV1Cids(domains: Domains): Promise<IPFSCids> {
|
||||||
const promises = Object.entries(domains).map(([repoName, domain]) => getENSDomainContenthash(repoName as RepoName, domain));
|
const promises = Object.entries(domains).map(([repoName, domain]) => (async () => [repoName, await getENSDomainContenthash(domain)])());
|
||||||
const result = await Promise.allSettled(promises);
|
const result = await Promise.allSettled(promises);
|
||||||
const ipfsCids = result.reduce((acc, res) => {
|
const ipfsCids = result.reduce((acc, res) => {
|
||||||
if (res.status === "rejected") console.error(res.reason);
|
if (res.status === "rejected") console.error(res.reason);
|
||||||
else acc[res.value[0]] = res.value[1];
|
else acc[res.value[0] as RepoName] = res.value[1];
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as IPFSCids);
|
}, {} as IPFSCids);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { mainRepos, packageRepos } from "./contstants.ts";
|
import { mainRepos, packageRepos, sitesENS } from "./contstants.ts";
|
||||||
|
|
||||||
export type RepoName = keyof typeof mainRepos | keyof typeof packageRepos;
|
export type RepoName = keyof typeof mainRepos | keyof typeof packageRepos | (typeof sitesENS)[number];
|
||||||
|
|
||||||
export type Domains = Partial<Record<RepoName, string>>;
|
export type Domains = Partial<Record<RepoName, string>>;
|
||||||
export type IPFSCids = Record<RepoName, string>;
|
export type IPFSCids = Record<RepoName, string>;
|
||||||
|
Loading…
Reference in New Issue
Block a user