master
cyhhao 2 years ago
parent 7fe3e66102
commit 707d58869c

@ -1,3 +1,10 @@
export interface QueueTaskOptions {
maxRetry?: number
queueInterval?: number
maxPending?: number
retryInterval?: number
}
export class QueueTask { export class QueueTask {
maxRetry: number = 0 maxRetry: number = 0
queueInterval: number = 0 queueInterval: number = 0
@ -11,7 +18,12 @@ export class QueueTask {
checkPointResolve: any checkPointResolve: any
index: number = 0 index: number = 0
constructor({ maxRetry = 10, queueInterval = 0, maxPending = 0, retryInterval = 0 }) { constructor({
maxRetry = 10,
queueInterval = 0,
maxPending = 0,
retryInterval = 0,
}: QueueTaskOptions) {
this.maxRetry = maxRetry this.maxRetry = maxRetry
this.queueInterval = queueInterval this.queueInterval = queueInterval
this.maxPending = maxPending this.maxPending = maxPending
@ -41,7 +53,8 @@ export class QueueTask {
setTimeout(() => { setTimeout(() => {
resolve(true) resolve(true)
}, delta) }, delta)
this.lastTaskScheduled = delta // console.error("wait delta", delta, "ms")
this.lastTaskScheduled = now + delta
return return
} else { } else {
this.lastTaskScheduled = now this.lastTaskScheduled = now
@ -55,14 +68,17 @@ export class QueueTask {
let lastError let lastError
for (let i = 0; i < retry; i++) { for (let i = 0; i < retry; i++) {
this.index++ this.index++
let start = Date.now().valueOf() // let start = Date.now().valueOf()
console.error("wait-" + this.index) // let index = this.index
// console.error("wait-" + index)
await this.tickThread() await this.tickThread()
console.log("run-" + this.index, Date.now().valueOf() - start, "ms") // console.error("run-" + index, Date.now().valueOf() - start, "ms")
this.pending++ this.pending++
try { try {
// let start = Date.now().valueOf()
let res = await func() let res = await func()
// console.error("done-" + index, Date.now().valueOf() - start, "ms")
this.pending-- this.pending--
this.checkPointResolve(true) this.checkPointResolve(true)
return res return res
@ -76,3 +92,10 @@ export class QueueTask {
if (lastError) throw lastError if (lastError) throw lastError
} }
} }
export function Retrier(
func: Function,
{ maxRetry = 10, queueInterval = 0, maxPending = 0, retryInterval = 0 }: QueueTaskOptions
): Promise<any> {
return new QueueTask({ maxRetry, queueInterval, maxPending, retryInterval }).run(func)
}

@ -1,4 +1,5 @@
import { ethers } from "ethers" import { ethers } from "ethers"
import { Retrier } from "./queue-task.js"
export class TxManager { export class TxManager {
contract: ethers.Contract contract: ethers.Contract
@ -88,14 +89,19 @@ export class TxManager {
async SendCall(_method: string, _args: any[]): Promise<any> { async SendCall(_method: string, _args: any[]): Promise<any> {
let lastError: any = null let lastError: any = null
const nonce = await this.getNonce() const nonce = await Retrier(this.getNonce.bind(this), { maxRetry: this.boardcastTimes })
if (this.queueCurrNonce < 0) this.queueCurrNonce = nonce if (this.queueCurrNonce < 0) this.queueCurrNonce = nonce
let unsignedTx = await this.contract.populateTransaction[_method](..._args) let unsignedTx = await this.contract.populateTransaction[_method](..._args)
unsignedTx.nonce = nonce unsignedTx.nonce = nonce
unsignedTx.chainId = this.chainId unsignedTx.chainId = this.chainId
// estimateGas check // estimateGas check
let gasLimit = await this.contract.provider.estimateGas(unsignedTx) let gasLimit = await Retrier(
async () => await this.contract.provider.estimateGas(unsignedTx),
{
maxRetry: this.boardcastTimes,
}
)
unsignedTx.gasLimit = gasLimit.mul((this.gasLimitRatio * 100) | 0).div(100) unsignedTx.gasLimit = gasLimit.mul((this.gasLimitRatio * 100) | 0).div(100)
let retryRBF = this.rbfTimes let retryRBF = this.rbfTimes
let rbfCount = 0 let rbfCount = 0
@ -106,7 +112,9 @@ export class TxManager {
// set gas price // set gas price
let price let price
try { try {
price = await this.FreshBaseGas() price = await await Retrier(this.FreshBaseGas.bind(this), {
maxRetry: this.boardcastTimes,
})
} catch (e) { } catch (e) {
price = this.price price = this.price
} finally { } finally {

@ -1,52 +1,52 @@
// from https://chainid.network/chains.json // from https://chainid.network/chains.json
const evmNetworks: Record<number, any> = { const evmNetworks: Record<number, any> = {
1: { // 1: {
name: "Ethereum", // name: "Ethereum",
nativeCurrency: { // nativeCurrency: {
name: "Ether", // name: "Ether",
symbol: "ETH", // symbol: "ETH",
decimals: 18, // decimals: 18,
}, // },
rpc: [ // rpc: [
"https://rpc.flashbots.net", // "https://rpc.flashbots.net",
"https://singapore.rpc.blxrbdn.com", // "https://singapore.rpc.blxrbdn.com",
"https://rpc.ankr.com/eth", // "https://rpc.ankr.com/eth",
], // ],
explorers: [ // explorers: [
{ // {
name: "etherscan", // name: "etherscan",
url: "https://etherscan.io", // url: "https://etherscan.io",
standard: "EIP3091", // standard: "EIP3091",
}, // },
], // ],
txConst: { // txConst: {
blockTimeSec: 15, // blockTimeSec: 15,
}, // },
contracts: { git3: "" }, // contracts: { git3: "" },
}, // },
5: { // 5: {
name: "Goerli", // name: "Goerli",
rpc: ["https://eth-goerli.g.alchemy.com/v2/asrXwNuiK9my-cZJYZ_ooo4q-lDw8HLm"], // rpc: ["https://eth-goerli.g.alchemy.com/v2/asrXwNuiK9my-cZJYZ_ooo4q-lDw8HLm"],
nativeCurrency: { // nativeCurrency: {
name: "Goerli Ether", // name: "Goerli Ether",
symbol: "ETH", // symbol: "ETH",
decimals: 18, // decimals: 18,
}, // },
explorers: [ // explorers: [
{ // {
name: "etherscan-goerli", // name: "etherscan-goerli",
url: "https://goerli.etherscan.io", // url: "https://goerli.etherscan.io",
standard: "EIP3091", // standard: "EIP3091",
}, // },
], // ],
txConst: { // txConst: {
blockTimeSec: 12, // blockTimeSec: 12,
rbfTimes: 6, // rbfTimes: 6,
boardcastTimes: 5, // boardcastTimes: 5,
}, // },
contracts: { git3: "0x51bb7F23193b88696D25EAec7E3293a2C96e55Ee" }, // contracts: { git3: "0x51bb7F23193b88696D25EAec7E3293a2C96e55Ee" },
}, // },
3334: { 3334: {
name: "Web3Q Galileo", name: "Web3Q Galileo",
nativeCurrency: { nativeCurrency: {
@ -67,29 +67,54 @@ const evmNetworks: Record<number, any> = {
}, },
contracts: { git3: "0x59ef6b2dbfE86CcAaD84E2d8e78177f528521Da9" }, contracts: { git3: "0x59ef6b2dbfE86CcAaD84E2d8e78177f528521Da9" },
}, },
3141: { // 3141: {
name: "Filecoin - Hyperspace testnet", // name: "Filecoin - Hyperspace testnet",
// nativeCurrency: {
// name: "testnet filecoin",
// symbol: "tFIL",
// decimals: 18,
// },
// rpc: [
// "https://api.hyperspace.node.glif.io/rpc/v1",
// // "https://filecoin-hyperspace.chainstacklabs.com/rpc/v1",
// ],
// explorers: [
// {
// name: "Filfox - Hyperspace",
// url: "https://hyperspace.filfox.info/en",
// standard: "none",
// },
// ],
// txConst: {
// blockTimeSec: 30,
// boardcastTimes: 5,
// },
// contracts: { git3: "0xF56A1dd941667911896B9B872AC79E56cfc6a3dB" },
// },
421613: {
name: "Arbitrum - Goerli",
nativeCurrency: { nativeCurrency: {
name: "testnet filecoin", name: "Arbitrum Ether",
symbol: "tFIL", symbol: "ETH",
decimals: 18, decimals: 18,
}, },
rpc: [ rpc: [
"https://api.hyperspace.node.glif.io/rpc/v1", "https://goerli-rollup.arbitrum.io/rpc",
// "https://filecoin-hyperspace.chainstacklabs.com/rpc/v1", "https://arb-goerli.g.alchemy.com/v2/XT-0xyP5nTP1ltJ0MRBzvO-K9taRwt9o",
], ],
explorers: [ explorers: [
{ {
name: "Filfox - Hyperspace", name: "arbiscan-goerli",
url: "https://hyperspace.filfox.info/en", url: "https://goerli.arbiscan.io",
standard: "none", standard: "none",
}, },
], ],
txConst: { txConst: {
blockTimeSec: 30, blockTimeSec: 3,
boardcastTimes: 5, rbfTimes: 5,
boardcastTimes: 10,
}, },
contracts: { git3: "0xF56A1dd941667911896B9B872AC79E56cfc6a3dB" }, contracts: { git3: "0x7Bb1038106fC6490195ec9906b29C81217ab090d" },
}, },
} }

@ -2,7 +2,6 @@ export default {
gateways: [ gateways: [
"https://ipfs.io/ipfs/", "https://ipfs.io/ipfs/",
"https://cloudflare-ipfs.com/ipfs/", "https://cloudflare-ipfs.com/ipfs/",
"https://ipfs.fleek.co/ipfs/",
"https://gateway.ipfs.io/ipfs/", "https://gateway.ipfs.io/ipfs/",
], ],
} }

@ -15,6 +15,10 @@ const ns: Record<string, any> = {
chainId: 5, chainId: 5,
resolver: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", resolver: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
}, },
arb: {
chainId: 421613,
resolver: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
},
} }
export default ns export default ns

@ -4,14 +4,14 @@ import { ethers } from "ethers"
import ipfsConf from "../config/ipfs.js" import ipfsConf from "../config/ipfs.js"
import axios from "axios" import axios from "axios"
import { Git3Protocol } from "../common/git3-protocol.js" import { Git3Protocol } from "../common/git3-protocol.js"
import { QueueTask } from "../common/queue-task.js" import { QueueTask, Retrier } from "../common/queue-task.js"
export class SLIStorage implements Storage { export class SLIStorage implements Storage {
repoName: string repoName: string
wallet: ethers.Wallet wallet: ethers.Wallet
contract: ethers.Contract contract: ethers.Contract
txManager: TxManager txManager: TxManager
auth: string auth: string[]
batchQueue: Record<string, string>[] = [] batchQueue: Record<string, string>[] = []
maxBatchSize = 20 maxBatchSize = 20
@ -28,8 +28,10 @@ export class SLIStorage implements Storage {
this.contract = protocol.contract this.contract = protocol.contract
this.wallet = protocol.wallet this.wallet = protocol.wallet
this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst) this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst)
this.auth = this.auth = [
"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGFEQTdCOWFlQTdGNTc2ZDI5NzM0ZWUxY0Q2ODVFMzc2OWNCM2QwRDEiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTY3NTQ5NDYwMDkzMiwibmFtZSI6ImZ2bS1oYWNrc29uIn0.YBqfsj_LTZSJPKc0OH586avnQNqove_Htzl5rrToXTk" "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGFEQTdCOWFlQTdGNTc2ZDI5NzM0ZWUxY0Q2ODVFMzc2OWNCM2QwRDEiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTY3NTQ5NDYwMDkzMiwibmFtZSI6ImZ2bS1oYWNrc29uIn0.YBqfsj_LTZSJPKc0OH586avnQNqove_Htzl5rrToXTk",
"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweDhmOTY1ZjAyRWY1MzkxODBlNDNiQ0M5M0FkZDJDZDI1RjU5RjRiMzIiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTY3NjY1NDE1MzExMCwibmFtZSI6ImdpdDMifQ.f7vpBmQCMV3VIqWfPtuDNA5G5ThegjVaO4V-GCmK6wg",
]
this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst) this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst)
@ -38,9 +40,9 @@ export class SLIStorage implements Storage {
}) })
this.storageTask = new QueueTask({ this.storageTask = new QueueTask({
maxRetry: 10, maxRetry: 30,
queueInterval: 400, queueInterval: 400,
maxPending: 20, maxPending: 100,
retryInterval: 500, retryInterval: 500,
}) })
} }
@ -57,19 +59,31 @@ export class SLIStorage implements Storage {
} }
async download(path: string): Promise<[Status, Buffer]> { async download(path: string): Promise<[Status, Buffer]> {
const res = await this.contract.download(Buffer.from(this.repoName), Buffer.from(path)) const res = await Retrier(
async () => await this.contract.download(Buffer.from(this.repoName), Buffer.from(path)),
{ maxRetry: 10 }
)
const buffer = Buffer.from(res.slice(2), "hex") const buffer = Buffer.from(res.slice(2), "hex")
const cid = buffer.toString("utf8") const cid = buffer.toString("utf8")
for (let i = 0; i < ipfsConf.gateways.length; i++) { for (let i = 0; i < ipfsConf.gateways.length; i++) {
let gateway = ipfsConf.gateways[Math.floor(Math.random() * ipfsConf.gateways.length)] //random get rpc let gateway = ipfsConf.gateways[Math.floor(Math.random() * ipfsConf.gateways.length)] //random get rpc
try { try {
let resault = await Retrier(
async () => {
const TIMEOUT = 15
let response = await axios.get(gateway + cid, { let response = await axios.get(gateway + cid, {
responseType: "arraybuffer", responseType: "arraybuffer",
timeout: TIMEOUT * 1000,
}) })
if (response.status === 200) { if (response.status === 200) {
console.error(`=== download file ${path} succeed ===`) return Buffer.from(response.data)
return [Status.SUCCEED, Buffer.from(response.data)] } else {
throw new Error(`download failed: ${response.status}`)
} }
},
{ maxRetry: 3 }
)
return [Status.SUCCEED, resault]
} catch (e) { } catch (e) {
//pass //pass
} }
@ -191,13 +205,13 @@ export class SLIStorage implements Storage {
} }
async storeIPFS(data: Buffer): Promise<string> { async storeIPFS(data: Buffer): Promise<string> {
const TIMEOUT = 30 const TIMEOUT = 15
try { try {
let cid = await this.storageTask.run(async () => { let cid = await this.storageTask.run(async () => {
let response = await axios.post("https://api.nft.storage/upload", data, { let response = await axios.post("https://api.nft.storage/upload", data, {
headers: { headers: {
"Content-Type": "application/octet-stream", "Content-Type": "application/octet-stream",
Authorization: this.auth, Authorization: this.auth[Math.floor(Math.random() * this.auth.length)],
}, },
timeout: TIMEOUT * 1000, timeout: TIMEOUT * 1000,
}) })

Loading…
Cancel
Save