From 46910a5839a0f4877848f171571f95a6ef832022 Mon Sep 17 00:00:00 2001 From: cyhhao Date: Tue, 28 Feb 2023 17:26:25 +0800 Subject: [PATCH 1/5] add sync scripts --- .gitignore | 4 +- package.json | 109 +++++++-------- src/common/git3-protocol.ts | 68 ++++++++-- src/config/abis.ts | 4 +- src/config/evm-network.ts | 4 +- src/config/name-services.ts | 4 +- src/git3/index.ts | 119 +++++++++-------- src/scripts/clear.ts | 10 ++ src/scripts/sync.ts | 256 ++++++++++++++++++++++++++++++++++++ yarn.lock | 5 + 10 files changed, 457 insertions(+), 126 deletions(-) create mode 100644 src/scripts/clear.ts create mode 100644 src/scripts/sync.ts diff --git a/.gitignore b/.gitignore index 7f5603c..2e88850 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,6 @@ dist .pnp.* .DS_Store bin/ -dist/ \ No newline at end of file +dist/ + +cache.json \ No newline at end of file diff --git a/package.json b/package.json index 6618e6a..1c13ad0 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,58 @@ { - "name": "git3-cli", - "version": "0.1.1", - "license": "MIT", - "type": "module", - "engines": { - "node": ">=14.16" - }, - "bin": "dist/git3/index.js", - "dependencies": { - "@ethersproject/experimental": "^5.7.0", - "axios": "^1.3.2", - "bip39": "^3.0.4", - "buffer-split": "^1.0.0", - "colors-cli": "^1.0.29", - "commander": "^10.0.0", - "debug": "^4.3.4", - "eth-ens-namehash": "^2.0.8", - "ethers": "^5.7.2", - "form-data": "^4.0.0", - "git-config-path": "^2.0.0", - "inquirer": "^9.1.4", - "js-sha3": "^0.8.0", - "parse-git-config": "^3.0.0", - "rxjs": "^7.8.0", - "rxjs-async-map": "^0.2.0", - "rxjs-stream": "^5.0.0", - "superpathjoin": "^2.0.1", - "url-parse": "^1.5.10" - }, - "scripts": { - "clean": "rm -rf ./dist ./bin", - "build:git3": "esbuild src/git3/index.ts --bundle --platform=node --outfile=dist/git3.cjs --format=cjs", - "build:git-remote": "esbuild src/git-remote-git3/index.ts --bundle --platform=node --outfile=dist/git-remote-git3.cjs --format=cjs", - "build": "yarn clean && ( yarn build:git3 & yarn build:git-remote & wait)", - "pkg:git3": "pkg dist/git3.cjs -c git3.pkg.json", - "pkg:git-remote": "pkg dist/git-remote-git3.cjs -c git-remote-git3.pkg.json", - "pkg:all": "yarn pkg:git3 && yarn pkg:git-remote", - "pkg": "yarn build && yarn pkg:all", - "install-mac": "yarn pkg && cp bin/git3-macos /usr/local/bin/git3 && cp bin/git-remote-git3-macos /usr/local/bin/git-remote-git3", - "install-linux": "yarn pkg && cp bin/git3-linux /usr/local/bin/git3 && cp bin/git-remote-git3-linux /usr/local/bin/git-remote-git3" - }, - "devDependencies": { - "@types/buffer-split": "^1.0.0", - "@types/debug": "^4.1.7", - "@types/inquirer": "^9.0.3", - "@types/node": "^18.11.18", - "@types/parse-git-config": "^3.0.1", - "@types/url-parse": "^1.4.8", - "esbuild": "^0.17.0", - "pkg": "^5.8.0", - "ts-node": "^10.9.1", - "typescript": "^4.9.4" - } + "name": "git3-cli", + "version": "0.1.1", + "license": "MIT", + "type": "module", + "engines": { + "node": ">=14.16" + }, + "bin": "dist/git3/index.js", + "dependencies": { + "@ethersproject/experimental": "^5.7.0", + "axios": "^1.3.2", + "bip39": "^3.0.4", + "buffer-split": "^1.0.0", + "colors-cli": "^1.0.29", + "commander": "^10.0.0", + "debug": "^4.3.4", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.7.2", + "form-data": "^4.0.0", + "git-config-path": "^2.0.0", + "inquirer": "^9.1.4", + "js-sha3": "^0.8.0", + "parse-git-config": "^3.0.0", + "rxjs": "^7.8.0", + "rxjs-async-map": "^0.2.0", + "rxjs-stream": "^5.0.0", + "superpathjoin": "^2.0.1", + "url-parse": "^1.5.10" + }, + "scripts": { + "clean": "rm -rf ./dist ./bin", + "build:git3": "esbuild src/git3/index.ts --bundle --platform=node --outfile=dist/git3.cjs --format=cjs", + "build:git-remote": "esbuild src/git-remote-git3/index.ts --bundle --platform=node --outfile=dist/git-remote-git3.cjs --format=cjs", + "build": "yarn clean && ( yarn build:git3 & yarn build:git-remote & wait)", + "pkg:git3": "pkg dist/git3.cjs -c git3.pkg.json", + "pkg:git-remote": "pkg dist/git-remote-git3.cjs -c git-remote-git3.pkg.json", + "pkg:all": "yarn pkg:git3 && yarn pkg:git-remote", + "pkg": "yarn build && yarn pkg:all", + "install-mac": "yarn pkg && cp bin/git3-macos /usr/local/bin/git3 && cp bin/git-remote-git3-macos /usr/local/bin/git-remote-git3", + "install-linux": "yarn pkg && cp bin/git3-linux /usr/local/bin/git3 && cp bin/git-remote-git3-linux /usr/local/bin/git-remote-git3", + "sync": "ts-node src/scripts/sync.ts", + "clear-sync": "ts-node src/scripts/clear.ts" + }, + "devDependencies": { + "@types/buffer-split": "^1.0.0", + "@types/debug": "^4.1.7", + "@types/inquirer": "^9.0.3", + "@types/node": "^18.11.18", + "@types/parse-git-config": "^3.0.1", + "@types/url-parse": "^1.4.8", + "es-main": "^1.2.0", + "esbuild": "^0.17.0", + "pkg": "^5.8.0", + "ts-node": "^10.9.1", + "typescript": "^4.9.4" + } } diff --git a/src/common/git3-protocol.ts b/src/common/git3-protocol.ts index dc61746..b1fded9 100644 --- a/src/common/git3-protocol.ts +++ b/src/common/git3-protocol.ts @@ -6,6 +6,7 @@ import { getWallet, randomRPC, setupContract } from "./wallet.js" import Url from "url-parse" import network from "../config/evm-network.js" import abis from "../config/abis.js" +import { TxManager } from "./tx-manager.js" export type Git3Protocol = { sender: string @@ -20,23 +21,37 @@ export type Git3Protocol = { ns?: Record nsName?: string nsDomain?: string + factory?: ethers.Contract } -type Option = { +export type ParseOption = { skipRepoName?: boolean ignoreProtocolHeader?: boolean + includeFactory?: boolean +} + +export function initNameService(): ethers.Contract { + let nsContract = setupContract( + new ethers.providers.JsonRpcProvider("https://goerli-rollup.arbitrum.io/rpc"), + nameServices.resolver_, + abis.NameService + ) + return nsContract } export async function parseGit3URI( uri: string, - option: Option = { skipRepoName: false, ignoreProtocolHeader: false } + option: ParseOption = { + skipRepoName: false, + ignoreProtocolHeader: false, + includeFactory: false, + } ): Promise { if (option.ignoreProtocolHeader) { if (!uri.startsWith("git3://")) { uri = "git3://" + uri } } - console.error("uri", uri) const url = new Url(uri) let sender = url.username || "default" let chainId = url.port ? parseInt(url.port) : null @@ -60,12 +75,7 @@ export async function parseGit3URI( chainId = chainId || ns.chainId // Todo: temporary resolve name service - let resolverAddress = ns["resolver"] - let nsContract = setupContract( - new ethers.providers.JsonRpcProvider("https://goerli-rollup.arbitrum.io/rpc"), - resolverAddress, - abis.NameService - ) + let nsContract = initNameService() hubAddress = await nsContract.nameHub([nsName, nsDomain].join(".")) if (hubAddress == "0x0000000000000000000000000000000000000000") throw new Error(`${nsName} not found`) @@ -97,6 +107,11 @@ export async function parseGit3URI( let hub = setupContract(provider, hubAddress, abi, wallet) wallet = wallet.connect(hub.provider) + let factory + if (option.includeFactory) { + factory = setupContract(provider, netConfig.contracts.factory, abis.Factory, wallet) + } + return { sender, senderAddress, @@ -110,5 +125,40 @@ export async function parseGit3URI( ns, nsName, nsDomain, + factory, + } +} +export type FactoryProtocol = { + factory: ethers.Contract + txManager: TxManager + netConfig: Record + chainId: number +} + +export async function initFactoryByChainID( + chain: string, + wallet: ethers.Wallet | null +): Promise { + let netConfig, chainId + chainId = parseInt(chain) + if (chainId) { + netConfig = network[chainId] + } else { + let ns = nameServices[chain] + if (!ns) throw new Error(`invalid name service ${chain}`) + chainId = ns.chainId + netConfig = network[chainId] + } + + let rpc = randomRPC(netConfig.rpc) + const provider = new ethers.providers.JsonRpcProvider(rpc) + let factory = setupContract(provider, netConfig.contracts.factory, abis.Factory, wallet) + let txManager = new TxManager(factory, chainId, netConfig.txConst) + + return { + factory, + txManager, + netConfig, + chainId, } } diff --git a/src/config/abis.ts b/src/config/abis.ts index 5484e6c..13b7c5f 100644 --- a/src/config/abis.ts +++ b/src/config/abis.ts @@ -1,7 +1,7 @@ export default { NameService: - '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"}],"name":"HubRecords","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nameList","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameListLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"hub","type":"address"}],"name":"rebindHubAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"hub","type":"address"}],"name":"registerHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferNameOwner","outputs":[],"stateMutability":"nonpayable","type":"function"}]', + '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"hub","type":"address"}],"name":"RegisterHub","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"}],"name":"HubRecords","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hubName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nameList","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameListLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"hub","type":"address"}],"name":"rebindHubAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"hub","type":"address"}],"name":"registerHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferNameOwner","outputs":[],"stateMutability":"nonpayable","type":"function"}]', Factory: '[{"inputs":[{"internalType":"bool","name":"_dbSelector","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hub","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"}],"name":"CreateHub","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bool","name":"isPermissionless","type":"bool"}],"name":"createHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dbSelector","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubImp","outputs":[{"internalType":"contract Hubv3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hubs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newHubImp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setHubImp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]', - Hub: '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CONTRIBUTOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NOTFOUND","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"RoleList","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"addContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"addManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"address","name":"con","type":"address"}],"name":"addRepoContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes[]","name":"path","type":"bytes[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"batchUpload","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"createRepo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"db","outputs":[{"internalType":"contract database","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"branchPath","type":"bytes"}],"name":"delRepoRef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"deleteRepo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"}],"name":"download","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"branchPath","type":"bytes"}],"name":"getRepoRef","outputs":[{"internalType":"bytes20","name":"","type":"bytes20"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"dbSelector","type":"bool"},{"internalType":"address","name":"user","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"listRepoRefs","outputs":[{"components":[{"internalType":"bytes20","name":"hash","type":"bytes20"},{"internalType":"bytes","name":"name","type":"bytes"}],"internalType":"struct Repolib.refData[]","name":"list","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"memberRole","outputs":[{"internalType":"bool","name":"IsAdmin","type":"bool"},{"internalType":"bool","name":"IsManager","type":"bool"},{"internalType":"bool","name":"IsContributor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"membership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"open","type":"bool"}],"name":"openPermissonlessJoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"permissionless","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionlessJoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"removeContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"removeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"address","name":"con","type":"address"}],"name":"removeRepoContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"repoContributors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"repoNames","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"repoOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"branchPath","type":"bytes"},{"internalType":"bytes20","name":"refHash","type":"bytes20"}],"name":"setRepoRef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upload","outputs":[],"stateMutability":"payable","type":"function"}]', + Hub: '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"repoName","type":"bytes"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"RepoCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"repoName","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"branchPath","type":"bytes"},{"indexed":false,"internalType":"bytes20","name":"refHash","type":"bytes20"}],"name":"SetRepoRef","type":"event"},{"inputs":[],"name":"CONTRIBUTOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NOTFOUND","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"RoleList","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"addContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"addManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"address","name":"con","type":"address"}],"name":"addRepoContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes[]","name":"path","type":"bytes[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"batchUpload","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"createRepo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"db","outputs":[{"internalType":"contract database","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"branchPath","type":"bytes"}],"name":"delRepoRef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"deleteRepo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"}],"name":"download","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"branchPath","type":"bytes"}],"name":"getRepoRef","outputs":[{"internalType":"bytes20","name":"","type":"bytes20"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"dbSelector","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"isPermissionless","type":"bool"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"listRepoRefs","outputs":[{"components":[{"internalType":"bytes20","name":"hash","type":"bytes20"},{"internalType":"bytes","name":"name","type":"bytes"}],"internalType":"struct Repolib.refData[]","name":"list","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"memberRole","outputs":[{"internalType":"bool","name":"IsAdmin","type":"bool"},{"internalType":"bool","name":"IsManager","type":"bool"},{"internalType":"bool","name":"IsContributor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"membership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionless","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionlessJoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"removeContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"removeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"address","name":"con","type":"address"}],"name":"removeRepoContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"repoContributors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"repoList","outputs":[{"internalType":"bytes[]","name":"rn","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"repoNames","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"}],"name":"repoOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"roleToMembers","outputs":[{"internalType":"address[]","name":"members","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"open","type":"bool"}],"name":"setPermissonlessJoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"branchPath","type":"bytes"},{"internalType":"bytes20","name":"refHash","type":"bytes20"}],"name":"setRepoRef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upload","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"repoName","type":"bytes"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint256","name":"chunkId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uploadChunk","outputs":[],"stateMutability":"payable","type":"function"}]', } diff --git a/src/config/evm-network.ts b/src/config/evm-network.ts index ad79bff..03e1da8 100644 --- a/src/config/evm-network.ts +++ b/src/config/evm-network.ts @@ -89,7 +89,7 @@ const evmNetworks: Record = { txConst: { blockTimeSec: 7, }, - contracts: { factory: "0xF2CAd0c8997584D8DDe1c0726De0Fa9ECC3dDa04" }, + contracts: { factory: "0x5f0f1eb909dE5F9EF48C154F61b2FEB8fd3dA53f" }, }, 421613: { name: "Arbitrum - Goerli", @@ -114,7 +114,7 @@ const evmNetworks: Record = { rbfTimes: 5, boardcastTimes: 10, }, - contracts: { factory: "0x51bb7F23193b88696D25EAec7E3293a2C96e55Ee" }, + contracts: { factory: "0xa709975Bc01e745432f8898499E7b9a60f420117" }, }, } diff --git a/src/config/name-services.ts b/src/config/name-services.ts index 7adb006..d3bad57 100644 --- a/src/config/name-services.ts +++ b/src/config/name-services.ts @@ -1,15 +1,13 @@ const ns: Record = { + resolver_: "0xd684DBf9124d6B1f74f37558dD11fdcE0103AF15", w3q: { chainId: 3334, - resolver: "0x372343Dd5274bb7B571F81d4FBA3bC0E28FeF3D9", }, arb: { chainId: 42170, - resolver: "0x372343Dd5274bb7B571F81d4FBA3bC0E28FeF3D9", }, arbg: { chainId: 421613, - resolver: "0x372343Dd5274bb7B571F81d4FBA3bC0E28FeF3D9", }, } diff --git a/src/git3/index.ts b/src/git3/index.ts index 056a93f..8b6a33c 100644 --- a/src/git3/index.ts +++ b/src/git3/index.ts @@ -5,11 +5,9 @@ import bip39 from "bip39" import inquirer from "inquirer" import { importActions, generateActions } from "./actions.js" import network from "../config/evm-network.js" -import { explorerTxUrl, getWallet, randomRPC, setupContract } from "../common/wallet.js" -import { parseGit3URI } from "../common/git3-protocol.js" +import { explorerTxUrl, getWallet, randomRPC } from "../common/wallet.js" +import { initFactoryByChainID, parseGit3URI } from "../common/git3-protocol.js" import { TxManager } from "../common/tx-manager.js" -import nameServices from "../config/name-services.js" -import abis from "../config/abis.js" const program = new Command() @@ -142,31 +140,17 @@ create .argument("[is_permissionless]", "true or false", false) .description("create a new hub") .action(async (chain, isPermissionless) => { - let netConfig, chainId - chainId = parseInt(chain) - if (chainId) { - netConfig = network[chainId] - } else { - let ns = nameServices[chain] - if (!ns) throw new Error(`invalid name service ${chain}`) - chainId = ns.chainId - netConfig = network[chainId] - } - const wallet = await getWallet() - let rpc = randomRPC(netConfig.rpc) - const provider = new ethers.providers.JsonRpcProvider(rpc) + let protocol = await initFactoryByChainID(chain, wallet) - let factory = setupContract(provider, netConfig.contracts.factory, abis.Factory, wallet) - let txManager = new TxManager(factory, chainId, netConfig.txConst) - let receipt = await txManager.SendCall("createHub", [isPermissionless]) + let receipt = await protocol.txManager.SendCall("createHub", [isPermissionless]) // let CreateHubEvent = factory.interface.getEvent("CreateHub"); - console.log(explorerTxUrl(receipt.transactionHash, netConfig.explorers)) + console.log(explorerTxUrl(receipt.transactionHash, protocol.netConfig.explorers)) let events = receipt.logs .map((log: any) => { try { - return factory.interface.parseLog(log) + return protocol.factory.interface.parseLog(log) } catch (e) { return null } @@ -239,18 +223,22 @@ program .argument("", "hub_name.NS or hub_address:chain_id") .argument("", "manager address") .description("add a manager into hub") - .action(async (hub,managerAddr) => { + .action(async (hub, managerAddr) => { let protocol = await parseGit3URI(hub, { ignoreProtocolHeader: true, skipRepoName: true }) - let [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(protocol.wallet.address) + let [isAdmin, isManager, isContributor] = await protocol.hub.memberRole( + protocol.wallet.address + ) if (!isAdmin) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` : protocol.hubAddress - console.error(`[addManager] can only be executed with the admin authority of this hub: ${hubName}`) + console.error( + `[addManager] can only be executed with the admin authority of this hub: ${hubName}` + ) return } - [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(managerAddr) + ;[isAdmin, isManager, isContributor] = await protocol.hub.memberRole(managerAddr) if (isManager) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` @@ -269,18 +257,22 @@ program .argument("", "hub_name.NS or hub_address:chain_id") .argument("", "manager address") .description("remove a manager from hub") - .action(async (hub,managerAddr) => { + .action(async (hub, managerAddr) => { let protocol = await parseGit3URI(hub, { ignoreProtocolHeader: true, skipRepoName: true }) - let [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(protocol.wallet.address) + let [isAdmin, isManager, isContributor] = await protocol.hub.memberRole( + protocol.wallet.address + ) if (!isAdmin) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` : protocol.hubAddress - console.error(`[removeManager] can only be executed with the admin authority of this hub: ${hubName}`) + console.error( + `[removeManager] can only be executed with the admin authority of this hub: ${hubName}` + ) return } - [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(managerAddr) + ;[isAdmin, isManager, isContributor] = await protocol.hub.memberRole(managerAddr) if (!isManager) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` @@ -299,18 +291,22 @@ program .argument("", "hub_name.NS or hub_address:chain_id") .argument("", "contributor address") .description("add a manager into hub") - .action(async (hub,contributorAddr) => { + .action(async (hub, contributorAddr) => { let protocol = await parseGit3URI(hub, { ignoreProtocolHeader: true, skipRepoName: true }) - let [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(protocol.wallet.address) + let [isAdmin, isManager, isContributor] = await protocol.hub.memberRole( + protocol.wallet.address + ) if (!isManager) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` : protocol.hubAddress - console.error(`[addContributor] can only be executed with the manager authority of this hub: ${hubName}`) + console.error( + `[addContributor] can only be executed with the manager authority of this hub: ${hubName}` + ) return } - [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(contributorAddr) + ;[isAdmin, isManager, isContributor] = await protocol.hub.memberRole(contributorAddr) if (isContributor) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` @@ -328,18 +324,22 @@ program .argument("", "hub_name.NS or hub_address:chain_id") .argument("", "contributor address") .description("add a manager into hub") - .action(async (hub,contributorAddr) => { + .action(async (hub, contributorAddr) => { let protocol = await parseGit3URI(hub, { ignoreProtocolHeader: true, skipRepoName: true }) - let [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(protocol.wallet.address) + let [isAdmin, isManager, isContributor] = await protocol.hub.memberRole( + protocol.wallet.address + ) if (!isManager) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` : protocol.hubAddress - console.error(`[removeContributor] can only be executed with the manager authority of this hub: ${hubName}`) + console.error( + `[removeContributor] can only be executed with the manager authority of this hub: ${hubName}` + ) return } - [isAdmin,isManager,isContributor] = await protocol.hub.memberRole(contributorAddr) + ;[isAdmin, isManager, isContributor] = await protocol.hub.memberRole(contributorAddr) if (!isContributor) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` @@ -352,14 +352,12 @@ program console.log(explorerTxUrl(receipt.transactionHash, protocol.netConfig.explorers)) }) -// repo funcitons -let repository = program - .command("repository") - .description("repository related operations") +// repo funcitons +let repository = program.command("repository").description("repository related operations") repository .command("members") - .argument("","ex: git3.w3q/repo_name or hub_addr:chainid/repo_name") + .argument("", "ex: git3.w3q/repo_name or hub_addr:chainid/repo_name") .description("get all members information of the repository") .action(async (uri) => { let protocol = await parseGit3URI(uri, { ignoreProtocolHeader: true, skipRepoName: true }) @@ -371,43 +369,52 @@ repository repository .command("addCon") - .argument("","ex: git3.w3q/repo_name or hub_addr:chainid/repo_name") - .argument("","contributor address") + .argument("", "ex: git3.w3q/repo_name or hub_addr:chainid/repo_name") + .argument("", "contributor address") .description("add a contributor into the specified repository") - .action(async (uri,conAddr) => { + .action(async (uri, conAddr) => { let protocol = await parseGit3URI(uri, { ignoreProtocolHeader: true, skipRepoName: true }) let owner = await protocol.hub.repoOwner(Buffer.from(protocol.repoName)) - if (owner != protocol.wallet.address){ + if (owner != protocol.wallet.address) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` : protocol.hubAddress - console.error(`[repo addContributor] can only be executed with the owner authority of this repository:${protocol.repoName}-hub:${hubName}`) + console.error( + `[repo addContributor] can only be executed with the owner authority of this repository:${protocol.repoName}-hub:${hubName}` + ) } const txManager = new TxManager(protocol.hub, protocol.chainId, protocol.netConfig.txConst) - let receipt = await txManager.SendCall("addRepoContributor", [Buffer.from(protocol.repoName),conAddr]) + let receipt = await txManager.SendCall("addRepoContributor", [ + Buffer.from(protocol.repoName), + conAddr, + ]) console.log(explorerTxUrl(receipt.transactionHash, protocol.netConfig.explorers)) }) repository .command("removeCon") - .argument("","ex: git3.w3q/repo_name or hub_addr:chainid/repo_name") - .argument("","contributor address") + .argument("", "ex: git3.w3q/repo_name or hub_addr:chainid/repo_name") + .argument("", "contributor address") .description("remove a contributor from the specified repository") - .action(async (uri,conAddr) => { + .action(async (uri, conAddr) => { let protocol = await parseGit3URI(uri, { ignoreProtocolHeader: true, skipRepoName: true }) let owner = await protocol.hub.repoOwner(Buffer.from(protocol.repoName)) - if (owner != protocol.wallet.address){ + if (owner != protocol.wallet.address) { let hubName = protocol.ns ? `${protocol.nsName}.${protocol.nsDomain}` : protocol.hubAddress - console.error(`[repository removeContributor] can only be executed with the owner authority of this repository:${protocol.repoName}-hub:${hubName}`) + console.error( + `[repository removeContributor] can only be executed with the owner authority of this repository:${protocol.repoName}-hub:${hubName}` + ) } const txManager = new TxManager(protocol.hub, protocol.chainId, protocol.netConfig.txConst) - let receipt = await txManager.SendCall("removeRepoContributor", [Buffer.from(protocol.repoName),conAddr]) + let receipt = await txManager.SendCall("removeRepoContributor", [ + Buffer.from(protocol.repoName), + conAddr, + ]) console.log(explorerTxUrl(receipt.transactionHash, protocol.netConfig.explorers)) }) - program .command("info") .argument("[wallet]", "wallet you want to get info", "default") diff --git a/src/scripts/clear.ts b/src/scripts/clear.ts new file mode 100644 index 0000000..e8985fc --- /dev/null +++ b/src/scripts/clear.ts @@ -0,0 +1,10 @@ +import { api, deleteHub } from "./sync.js" +import fs from "fs" + +fs.unlinkSync("./cache.json") + +let res = await api.get("/orgs") +for (const org of res.data) { + console.log("hub:", org.name) + deleteHub(org.name) +} diff --git a/src/scripts/sync.ts b/src/scripts/sync.ts new file mode 100644 index 0000000..46beeac --- /dev/null +++ b/src/scripts/sync.ts @@ -0,0 +1,256 @@ +import { + FactoryProtocol, + initFactoryByChainID, + initNameService, + parseGit3URI, +} from "../common/git3-protocol.js" +import network from "../config/evm-network.js" +import { readFileSync, writeFileSync, existsSync } from "fs" +import { ethers } from "ethers" +import axios from "axios" +import nameServices from "../config/name-services.js" +import { Retrier } from "../common/queue-task.js" + +let cache = loadCache() + +export let api = axios.create({ + baseURL: "http://localhost:3001/api/v1/", + responseType: "json", + headers: { + "Content-Type": "application/json", + Authorization: `token ${process.env.TOKEN}`, + }, + validateStatus: function (status) { + return status < 500 + }, +}) + +function loadCache() { + existsSync("./cache.json") || writeFileSync("./cache.json", "") + let text = readFileSync("./cache.json").toString() + if (text == "") { + return { + factory: { + 3334: { + start: 5375112, + last: 5375112, + }, + 421613: { + start: 9341366, + last: 9341366, + }, + }, + hubs: {}, + ns: { + start: 9340900, + last: 9340900, + nameHub: {}, + hubName: {}, + }, + } + } else { + return JSON.parse(text) + } +} + +function saveCache(cache: any) { + writeFileSync("./cache.json", JSON.stringify(cache)) +} +const RANGE = 1000 +const WAIT_SECONDS = 10 + +async function eventIterator( + contract: ethers.Contract, + filter: any, + last: number, + saveLastCallback: (_last: number) => void, + eventCallback: (event: any) => void, + stop: () => boolean = () => false +) { + let provider = contract.provider + while (true) { + if (stop && stop()) break + let lastBlock = await provider.getBlockNumber() + for (let i = last; i < lastBlock; i += RANGE) { + let end = i + RANGE - 1 + if (end >= lastBlock) end = lastBlock - 1 + console.log(i, end) + let events = await Retrier(async () => await contract.queryFilter(filter, i, end), { + maxRetry: 10, + }) + for (const event of events) { + await eventCallback(event) + //console.log(protocol.chainId, i, end, event.args, event) + } + last = end + saveLastCallback(last) + } + await new Promise((resolve) => setTimeout(resolve, WAIT_SECONDS * 1000)) + } +} + +async function syncFactory(protocol: FactoryProtocol) { + let factory = protocol.factory + let last = cache.factory[protocol.chainId].last + console.log("syncFactory", protocol.chainId, last) + await eventIterator( + factory, + factory.filters.CreateHub(), + last, + (_last) => { + cache.factory[protocol.chainId].last = _last + saveCache(cache) + }, + async (event) => { + let hubAddr = event.args!.hub + if (cache.ns.hubName[hubAddr]) { + hubAddr = cache.ns.hubName[hubAddr] + } else { + hubAddr = `${hubAddr}:${protocol.chainId}` + } + console.log("hub:", hubAddr, "block:", event.blockNumber) + await createHub(hubAddr) + syncHub(hubAddr, event.blockNumber) + } + ) +} + +async function syncHub(hubAddr: string, start: number) { + if (start > 0) { + cache.hubs[hubAddr] = { start, last: start } + } + let protocol = await parseGit3URI(hubAddr, { skipRepoName: true, ignoreProtocolHeader: true }) + let hub = protocol.hub + let last = cache.hubs[hubAddr].last + await eventIterator( + hub, + hub.filters.RepoCreated(), + last, + (_last) => { + if (cache.hubs[hubAddr]) { + cache.hubs[hubAddr].last = _last + saveCache(cache) + } + }, + (event) => { + let repoName = Buffer.from(event.args!.repoName).toString() + console.log("repo:", repoName) + mirrorRepo(hubAddr, repoName) + }, + () => { + return !cache.hubs[hubAddr] + } + ) +} + +async function mirrorRepo(hubAddr: string, repoName: string) { + let uri = `git3://${hubAddr}/${repoName}` + let res = await api.post("/repos/migrate", { + clone_addr: uri, + mirror: true, + mirror_interval: "1h", + private: false, + repo_name: repoName, + repo_owner: hubAddr, + service: "git", + uid: 0, + }) + console.log("mirrorRepo", uri, res.status) +} + +async function migrateHub(oldHubAddr: string, newHubAddr: string) { + console.log("migrateHub:", oldHubAddr, newHubAddr) + let oldHub = cache.hubs[oldHubAddr] + if (oldHub) { + deleteHub(oldHubAddr) + delete cache.hubs[oldHubAddr] + await createHub(newHubAddr) + syncHub(newHubAddr, oldHub.start) + } else { + await createHub(newHubAddr) + } +} + +async function syncNameService() { + let nsContract = initNameService() + let last = cache.ns.last + + await eventIterator( + nsContract, + nsContract.filters.RegisterHub(), + last, + (_last) => { + cache.ns.last = _last + saveCache(cache) + }, + async (event) => { + let name = event.args!.name + let hub = event.args!.hub + let [_, nsDomain] = name.split(".") + let ns = nameServices[nsDomain] + let hubAddr = `${hub}:${ns.chainId}` + let old = cache.ns.nameHub[name] + if (!old) { + await migrateHub(hubAddr, name) + } else { + if (old != hub) { + // Rebind NS hub address + delete cache.ns.hubName[old] + await migrateHub(name, name) + } else { + // same name, do nothing + } + } + console.log("ns:", name, hub) + cache.ns.nameHub[name] = hub + cache.ns.hubName[hub] = name + saveCache(cache) + } + ) +} + +export async function deleteHub(hubAddr: string): Promise { + let res = await api.get(`/orgs/${hubAddr}/repos`, { params: { page: 1, limit: 100000 } }) + if (res.status != 200) { + return false + } + for (const repo of res.data) { + res = await api.delete(`/repos/${hubAddr}/${repo.name}`) + console.log("delete repo:", `${hubAddr}/${repo.name}`) + } + res = await api.delete(`/orgs/${hubAddr}`) + console.log(res.status, res.data) + return res.status == 200 +} + +async function createHub(hubAddr: string) { + let res = await api.post(`/orgs`, { + repo_admin_change_team_access: true, + username: hubAddr, + visibility: "public", + }) + if (res.status != 201) { + console.log("[ERROR] createHub", hubAddr, res.status, res.data) + } + return res.status == 201 +} + +async function main() { + let tasks = [] + tasks.push(syncNameService()) + + for (const [chainId, _] of Object.entries(network)) { + let protocol = await initFactoryByChainID(chainId, null) + tasks.push(syncFactory(protocol)) + } + + for (const [hubAddr, _] of Object.entries(cache.hubs)) { + tasks.push(syncHub(hubAddr, 0)) + } + + await Promise.all(tasks) +} +import esMain from "es-main" +if (esMain(import.meta)) { + main() +} diff --git a/yarn.lock b/yarn.lock index 050684e..2eb4954 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1061,6 +1061,11 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +es-main@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-main/-/es-main-1.2.0.tgz#b85954f1d9d9f542fcb08685ec19515f969bad16" + integrity sha512-A4tCSY43O/mH4rHjG1n0mI4DhK2BmKDr8Lk8PXK/GBB6zxGFGmIW4bbkbTQ2Gi9iNamMZ9vbGrwjZOIeiM7vMw== + esbuild@^0.17.0: version "0.17.0" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.0.tgz#fcf19373d1d546bdbec1557276284c0e6350380b" From cfe64db598310c55acb96956d0e0c53734c66eab Mon Sep 17 00:00:00 2001 From: cyhhao Date: Tue, 28 Feb 2023 18:56:45 +0800 Subject: [PATCH 2/5] add sync pull --- src/scripts/sync.ts | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/scripts/sync.ts b/src/scripts/sync.ts index 6a5a0ba..cafb40a 100644 --- a/src/scripts/sync.ts +++ b/src/scripts/sync.ts @@ -61,13 +61,14 @@ const WAIT_SECONDS = 10 async function eventIterator( contract: ethers.Contract, - filter: any, + filters: any[], last: number, saveLastCallback: (_last: number) => void, eventCallback: (event: any) => void, stop: () => boolean = () => false ) { let provider = contract.provider + while (true) { if (stop && stop()) break let lastBlock = await provider.getBlockNumber() @@ -75,13 +76,16 @@ async function eventIterator( let end = i + RANGE - 1 if (end >= lastBlock) end = lastBlock - 1 console.log(i, end) - let events = await Retrier(async () => await contract.queryFilter(filter, i, end), { - maxRetry: 10, - }) - for (const event of events) { - await eventCallback(event) - //console.log(protocol.chainId, i, end, event.args, event) + for (const filter of filters) { + let events = await Retrier(async () => await contract.queryFilter(filter, i, end), { + maxRetry: 10, + }) + for (const event of events) { + await eventCallback(event) + //console.log(protocol.chainId, i, end, event.args, event) + } } + last = end saveLastCallback(last) } @@ -95,7 +99,7 @@ async function syncFactory(protocol: FactoryProtocol) { console.log("syncFactory", protocol.chainId, last) await eventIterator( factory, - factory.filters.CreateHub(), + [factory.filters.CreateHub()], last, (_last) => { cache.factory[protocol.chainId].last = _last @@ -115,6 +119,10 @@ async function syncFactory(protocol: FactoryProtocol) { ) } +function Hex0xToStr(hex0x: string) { + return Buffer.from(hex0x.slice(2), "hex").toString() +} + async function syncHub(hubAddr: string, start: number) { if (start > 0) { cache.hubs[hubAddr] = { start, last: start } @@ -122,9 +130,10 @@ async function syncHub(hubAddr: string, start: number) { let protocol = await parseGit3URI(hubAddr, { skipRepoName: true, ignoreProtocolHeader: true }) let hub = protocol.hub let last = cache.hubs[hubAddr].last + await eventIterator( hub, - hub.filters.RepoCreated(), + [hub.filters.RepoCreated(), hub.filters.SetRepoRef()], last, (_last) => { if (cache.hubs[hubAddr]) { @@ -132,10 +141,15 @@ async function syncHub(hubAddr: string, start: number) { saveCache(cache) } }, - (event) => { - let repoName = Buffer.from(event.args!.repoName.slice(2), "hex").toString() - console.log("repo:", hubAddr, repoName) - mirrorRepo(hubAddr, repoName) + async (event) => { + if (event.event == "RepoCreated") { + let repoName = Hex0xToStr(event.args!.repoName) + console.log("repo:", hubAddr, repoName) + await mirrorRepo(hubAddr, repoName) + } else if (event.event == "SetRepoRef") { + let repoName = Hex0xToStr(event.args!.repoName) + await pullRepo(hubAddr, repoName) + } }, () => { return !cache.hubs[hubAddr] @@ -158,6 +172,12 @@ async function mirrorRepo(hubAddr: string, repoName: string) { console.log("mirrorRepo", uri, res.status) } +async function pullRepo(hubAddr: string, repoName: string) { + let uri = `git3://${hubAddr}/${repoName}` + let res = await api.post(`/repos/${hubAddr}/${repoName}/mirror-sync`) + console.log("pullRepo", uri, res.status) +} + async function migrateHub(oldHubAddr: string, newHubAddr: string) { console.log("migrateHub:", oldHubAddr, newHubAddr) let oldHub = cache.hubs[oldHubAddr] @@ -177,7 +197,7 @@ async function syncNameService() { await eventIterator( nsContract, - nsContract.filters.RegisterHub(), + [nsContract.filters.RegisterHub()], last, (_last) => { cache.ns.last = _last From dc0d46534a77ab1a36e73f836c4248d9130bd409 Mon Sep 17 00:00:00 2001 From: cyhhao Date: Tue, 28 Feb 2023 19:12:11 +0800 Subject: [PATCH 3/5] add port --- src/scripts/sync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/sync.ts b/src/scripts/sync.ts index cafb40a..48f419e 100644 --- a/src/scripts/sync.ts +++ b/src/scripts/sync.ts @@ -14,7 +14,7 @@ import { Retrier } from "../common/queue-task.js" let cache = loadCache() export let api = axios.create({ - baseURL: "http://localhost:3001/api/v1/", + baseURL: `http://127.0.0.1:${process.env.port || 3331}/api/v1/`, responseType: "json", headers: { "Content-Type": "application/json", From 500fb9d2fb214d12d3d7e432e0ae1484bb56877a Mon Sep 17 00:00:00 2001 From: cyhhao Date: Wed, 1 Mar 2023 02:16:49 +0800 Subject: [PATCH 4/5] fix retry --- src/scripts/sync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/sync.ts b/src/scripts/sync.ts index 48f419e..314bcbb 100644 --- a/src/scripts/sync.ts +++ b/src/scripts/sync.ts @@ -71,7 +71,7 @@ async function eventIterator( while (true) { if (stop && stop()) break - let lastBlock = await provider.getBlockNumber() + let lastBlock = await Retrier(provider.getBlockNumber, { maxRetry: 10 }) for (let i = last; i < lastBlock; i += RANGE) { let end = i + RANGE - 1 if (end >= lastBlock) end = lastBlock - 1 From 20b3a3ff8c468a15ce9fba18c019771c58dbcfe6 Mon Sep 17 00:00:00 2001 From: cyhhao Date: Wed, 1 Mar 2023 02:23:24 +0800 Subject: [PATCH 5/5] fix bug --- src/scripts/sync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/sync.ts b/src/scripts/sync.ts index 314bcbb..c651676 100644 --- a/src/scripts/sync.ts +++ b/src/scripts/sync.ts @@ -71,7 +71,7 @@ async function eventIterator( while (true) { if (stop && stop()) break - let lastBlock = await Retrier(provider.getBlockNumber, { maxRetry: 10 }) + let lastBlock = await Retrier(async () => await provider.getBlockNumber(), { maxRetry: 10 }) for (let i = last; i < lastBlock; i += RANGE) { let end = i + RANGE - 1 if (end >= lastBlock) end = lastBlock - 1