From 1e2aa36ba9789f9c367b5a0900a0bb9e2ed7631b Mon Sep 17 00:00:00 2001 From: ppe Date: Sat, 18 Mar 2023 16:53:13 +0100 Subject: [PATCH 01/95] adapt to gcp --- .dockerignore | 2 + .gitignore | 2 - Dockerfile | 6 +- docker-build.sh | 2 +- docker-run.sh | 2 +- k8s/deployment.yaml | 24 + k8s/ingress.yaml | 18 + k8s/podscaler.yaml | 21 + k8s/service.yaml | 12 + package.json | 14 +- src/gateway/init.ts | 41 +- src/gateway/router/gatewayRouter.ts | 2 + src/gateway/router/routes/gcpRoute.ts | 5 + src/gateway/router/welcomeRouter.ts | 8 +- src/gateway/tasks/TaskRunner.ts | 1 - src/gateway/tasks/networkInfoCache.ts | 15 +- syncer/db/db.go | 157 ----- syncer/go.mod | 26 - syncer/go.sum | 219 ------- syncer/sw_types/types.go | 38 -- syncer/syncer.go | 128 ---- tsconfig.json | 5 +- welcome.html | 32 - yalc.lock | 10 - yarn.lock | 899 +++++++++++++++++++++++--- 25 files changed, 958 insertions(+), 731 deletions(-) create mode 100644 k8s/deployment.yaml create mode 100644 k8s/ingress.yaml create mode 100644 k8s/podscaler.yaml create mode 100644 k8s/service.yaml create mode 100644 src/gateway/router/routes/gcpRoute.ts delete mode 100644 syncer/db/db.go delete mode 100644 syncer/go.mod delete mode 100644 syncer/go.sum delete mode 100644 syncer/sw_types/types.go delete mode 100644 syncer/syncer.go delete mode 100644 welcome.html delete mode 100644 yalc.lock diff --git a/.dockerignore b/.dockerignore index b725cafd..8f048326 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,5 @@ node_modules dist .secrets/sw-gateway-ec2-key.cer gateway.lock +dump* +network-cache.json diff --git a/.gitignore b/.gitignore index 4b6ea42c..2403ca12 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,6 @@ node_modules .idea db*.sqlite .secrets -.secrets/.env -.secrets/local.env gateway.lock network-cache.json .DS_Store diff --git a/Dockerfile b/Dockerfile index 3eb5a2b9..545f8055 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:14.18.2-alpine +FROM node:18 RUN mkdir /app WORKDIR /app @@ -6,7 +6,7 @@ WORKDIR /app # Installing required npm packages COPY package.json package.json COPY yarn.lock yarn.lock -RUN yarn +RUN yarn && yarn global add pm2 # Copying all files COPY . . @@ -17,4 +17,4 @@ RUN yarn build EXPOSE 5666 # Running the gateway -CMD yarn start:prod --env_path .secrets/.env +CMD [ "pm2-runtime", "start", "dist/gateway/init.js", "--name", "gateway", "-i", "max", "--", "--noSync" ] diff --git a/docker-build.sh b/docker-build.sh index 3b62aca4..373dd368 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -1 +1 @@ -docker build -t redstone-sw-gateway . +docker build -t warp-gateway . diff --git a/docker-run.sh b/docker-run.sh index 7ea587a0..3fb3811b 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -1 +1 @@ -docker run -t -i -p 8080:5666 redstone-sw-gateway +docker run -t -i -p 8080:5666 warp-gateway diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 00000000..2b1a974c --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: node + labels: + name: node +spec: + replicas: 1 + selector: + matchLabels: + app: node + template: + metadata: + labels: + app: node + spec: + containers: + - name: node + image: gcr.io/warp-372209/docker-image:2 + imagePullPolicy: Always + ports: + - containerPort: 5666 + protocol: TCP + restartPolicy: Always \ No newline at end of file diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml new file mode 100644 index 00000000..2f8f78db --- /dev/null +++ b/k8s/ingress.yaml @@ -0,0 +1,18 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: gke-warp-gw-ingress + annotations: + kubernetes.io/ingress.global-static-ip-name: "gke-warp-gw-ip" +spec: + rules: + - host: "chart-example.local" + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: gke-warp-gw-deployment + port: + number: 5666 \ No newline at end of file diff --git a/k8s/podscaler.yaml b/k8s/podscaler.yaml new file mode 100644 index 00000000..209cfaaf --- /dev/null +++ b/k8s/podscaler.yaml @@ -0,0 +1,21 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: node + namespace: default + labels: + app: node +spec: + scaleTargetRef: + kind: Deployment + name: node + apiVersion: apps/v1 + minReplicas: 2 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + averageValue: 70 + type: Utilization \ No newline at end of file diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 00000000..c9e3e8db --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: node + labels: + service: node +spec: + selector: + app: node + type: LoadBalancer + ports: + - port: 5666 \ No newline at end of file diff --git a/package.json b/package.json index 988892cb..e91b4772 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "dev:network:watch": "ts-node-dev --watch -- src/gateway/init.ts", "build": "tsc", "start:prod": "node dist/gateway/init.js", + "start:prod:noSync": "node dist/gateway/init.js --noSync", "start:prod:replica": "node dist/gateway/init.js --replica", "start:local": "node dist/gateway/init.js --env_path .secrets/local.env --local", "start:local:replica": "node dist/gateway/init.js --env_path .secrets/local.env --replica --local", @@ -23,26 +24,29 @@ "@idena/vrf-js": "^1.0.1", "@koa/cors": "3.2.0", "@koa/router": "10.1.1", - "@types/yargs": "17.0.7", "JSONStream": "^1.3.5", "arbundles": "^0.7.0", "arweave": "1.11.8", "axios": "^0.26.1", + "bluebird": "^3.7.2", "dotenv": "16.0.3", "elliptic": "^6.5.4", "ethers": "^5.7.2", "exponential-backoff": "3.1.0", "ioredis": "^5.2.4", - "knex": "0.95.14", - "koa": "2.13.4", + "knex": "2.4.2", + "koa": "2.14.1", "koa-bodyparser": "4.3.0", "koa-compress": "5.1.0", "nodemailer": "^6.9.1", "parse-json-stream": "^2.4.0", - "pg": "8.7.3", + "pg": "8.10.0", "pg-query-stream": "^4.2.3", + "pm2": "^5.3.0", + "prom-client": "12", "raw-body": "^2.5.1", "undici": "5.14.0", + "uuid": "^9.0.0", "warp-contracts": "1.2.48", "warp-contracts-pubsub": "^1.0.3", "warp-contracts-subscription-plugin": "1.0.4", @@ -56,6 +60,8 @@ "@types/koa__router": "8.0.11", "@types/nodemailer": "^6.4.7", "@types/object-hash": "2.2.1", + "@types/uuid": "^9.0.1", + "@types/yargs": "17.0.7", "@typescript-eslint/eslint-plugin": "4.33.0", "@typescript-eslint/parser": "4.33.0", "autocannon": "^7.6.0", diff --git a/src/gateway/init.ts b/src/gateway/init.ts index d4d45210..3ccf9828 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -26,6 +26,7 @@ import { DatabaseSource } from '../db/databaseSource'; const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; const replica = (argv.replica as boolean) || false; +const noSync = (argv.noSync as boolean) || false; const localEnv = (argv.local as boolean) || false; const elliptic = require('elliptic'); const EC = new elliptic.ec('secp256k1'); @@ -81,7 +82,7 @@ export interface GatewayContext { const logger = LoggerFactory.INST.create('gateway'); const sLogger = LoggerFactory.INST.create('sequencer'); - logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode.`); + logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode. noSync = ${noSync}`); const arweave = initArweave(); const { bundlr, jwk } = initBundlr(logger); @@ -101,7 +102,6 @@ export interface GatewayContext { ]); const app = new Koa(); - const signatureVerification = new EvmSignatureVerificationServerPlugin(); app.context.dbSource = dbSource; app.context.logger = logger; @@ -121,7 +121,7 @@ export interface GatewayContext { app.context.lastTxSync = new LastTxSync(); app.context.localEnv = localEnv; app.context.appSync = appSync; - app.context.signatureVerification = signatureVerification; + app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); app.use( cors({ @@ -201,24 +201,25 @@ export interface GatewayContext { } if (!fs.existsSync('gateway.lock')) { - try { - logger.info(`Creating lock file for ${cluster.worker?.id}`); - // note: if another process in cluster have already created the file - writing here - // will fail thanks to wx flags. https://stackoverflow.com/a/31777314 - fs.writeFileSync('gateway.lock', '' + cluster.worker?.id, { - flag: 'wx', - }); - removeLock = true; - - await runNetworkInfoCacheTask(app.context); - // note: only one worker in cluster runs the gateway tasks - // all workers in cluster run the http server - if (!localEnv) { - logger.info(`Starting gateway tasks for ${cluster.worker?.id}`); - await runGatewayTasks(app.context); + await runNetworkInfoCacheTask(app.context); + + if (!noSync) { + try { + logger.info(`Creating lock file for ${cluster.worker?.id}`); + // note: if another process in cluster have already created the file - writing here + // will fail thanks to wx flags. https://stackoverflow.com/a/31777314 + fs.writeFileSync('gateway.lock', '' + cluster.worker?.id, {flag: 'wx'}); + removeLock = true; + + // note: only one worker in cluster runs the gateway tasks + // all workers in cluster run the http server + if (!localEnv) { + logger.info(`Starting gateway tasks for ${cluster.worker?.id}`); + await runGatewayTasks(app.context); + } + } catch (e: any) { + logger.error('Error from gateway', e); } - } catch (e: any) { - logger.error('Error from gateway', e); } } } diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 4ec0d11d..196521de 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -28,6 +28,7 @@ import { deploySourceRoute_v2 } from './routes/deploySourceRoute_v2'; import { deployContractRoute_v2 } from './routes/deployContractRoute_v2'; import { registerContractRoute } from './routes/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; +import {gcpRoute} from "./routes/gcpRoute"; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -58,6 +59,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/contract-source', contractSourceRoute); router.get('/contracts-by-source', contractsBySourceRoute); router.get('/creator', creatorRoute); + router.get('/gcp/test', gcpRoute); // post if (!replica) { diff --git a/src/gateway/router/routes/gcpRoute.ts b/src/gateway/router/routes/gcpRoute.ts new file mode 100644 index 00000000..f0861849 --- /dev/null +++ b/src/gateway/router/routes/gcpRoute.ts @@ -0,0 +1,5 @@ +import Router from '@koa/router'; + +export async function gcpRoute(ctx: Router.RouterContext) { + ctx.body = 'hello from gcp'; +} diff --git a/src/gateway/router/welcomeRouter.ts b/src/gateway/router/welcomeRouter.ts index 243a127b..3b65cb73 100644 --- a/src/gateway/router/welcomeRouter.ts +++ b/src/gateway/router/welcomeRouter.ts @@ -1,12 +1,12 @@ import Router from '@koa/router'; -import { createReadStream } from 'fs'; -import * as path from 'path'; const welcomeRouter = new Router(); welcomeRouter.get('/', (ctx: Router.RouterContext) => { - ctx.type = 'text/html'; - ctx.body = createReadStream('welcome.html'); + ctx.body = { + name: 'Warp Gateway', + id: process.env.pm_id, + }; }); export default welcomeRouter; diff --git a/src/gateway/tasks/TaskRunner.ts b/src/gateway/tasks/TaskRunner.ts index 44081fb3..ce9a87df 100644 --- a/src/gateway/tasks/TaskRunner.ts +++ b/src/gateway/tasks/TaskRunner.ts @@ -37,7 +37,6 @@ export class TaskRunner { // https://developer.mozilla.org/en-US/docs/Web/API/setInterval#ensure_that_execution_duration_is_shorter_than_interval_frequency setTimeout(async function () { if (initialRunDone) { - context.logger.info(`Starting ${name} task.`); await worker(context); context.logger.info(`Task ${name} completed.`); } diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index 8f03aa83..af63d17c 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -4,6 +4,7 @@ import { GatewayContext } from '../init'; import { TaskRunner } from './TaskRunner'; import { BLOCKS_INTERVAL_MS } from './syncTransactions'; import fs from 'fs'; +import { fetch } from 'undici'; export type NetworkCacheType = { cachedNetworkInfo: NetworkInfoInterface; @@ -13,11 +14,17 @@ export type NetworkCacheType = { let cache: NetworkCacheType; export async function runNetworkInfoCacheTask(context: GatewayContext) { - const { arweave, logger, arweaveWrapper } = context; + const { arweave, logger } = context; async function updateNetworkInfo() { try { - const newNetworkInfo = await arweaveWrapper.info(); + const newNetworkInfoResponse = await fetch("https://gateway.warp.cc/gateway/arweave/info"); + if (!newNetworkInfoResponse.ok) { + const message = `An error has occured: ${newNetworkInfoResponse.status}`; + throw new Error(message); + } + const newNetworkInfo = (await newNetworkInfoResponse.json()) as NetworkInfoInterface; + if (cache?.cachedNetworkInfo && newNetworkInfo && newNetworkInfo.height < cache.cachedNetworkInfo.height) { logger.warn('New network height lower than current, skipping.', { currentHeight: cache?.cachedNetworkInfo.height, @@ -37,7 +44,7 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { cachedBlockInfo, }; - fs.writeFileSync('network-cache.json', JSON.stringify(cache), 'utf-8'); + // fs.writeFileSync('network-cache.json', JSON.stringify(cache), 'utf-8'); logger.debug('New network height', cache.cachedNetworkInfo.height); } catch (e) { logger.error('Error while loading network info', e); @@ -61,5 +68,5 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { } export function getCachedNetworkData(): NetworkCacheType { - return JSON.parse(fs.readFileSync('network-cache.json', 'utf-8')); + return cache; } diff --git a/syncer/db/db.go b/syncer/db/db.go deleted file mode 100644 index e9a14c45..00000000 --- a/syncer/db/db.go +++ /dev/null @@ -1,157 +0,0 @@ -package db - -import ( - "bufio" - "database/sql" - "fmt" - "github.com/everFinance/arsyncer" - _ "github.com/lib/pq" - "github.com/redstone-finance/redstone-sw-gateway/syncer/sw_types" - "os" - "strings" -) - -var log = arsyncer.NewLog("db") - -type Db struct { - connectionParams ConnectionParams - connection *sql.DB -} - -type ConnectionParams struct { - Host string - Port int - User string - Password string - Dbname string -} - -type AppConfigProperties map[string]string - -func New(connectionParams ConnectionParams) *Db { - return &Db{ - connectionParams: connectionParams, - connection: connectDb(connectionParams), - } -} - -func (db *Db) Close() { - err := db.connection.Close() - if err != nil { - return - } -} - -func (db *Db) LoadLatestSyncedBlock() int64 { - sqlStatement := `SELECT last_checked_height AS blockHeight FROM arsyncer;` - var blockHeight int64 - row := db.connection.QueryRow(sqlStatement) - switch err := row.Scan(&blockHeight); err { - case sql.ErrNoRows: - log.Error("No rows were returned!") - case nil: - log.Info("Last synced block", "height", blockHeight) - default: - panic(err) - } - - return blockHeight -} - -func (db *Db) BatchInsertInteractions(interactions []sw_types.DbInteraction) error { - var valueStrings []string - var valueArgs []interface{} - for _, interaction := range interactions { - valueStrings = append(valueStrings, "(?, ?, ?, ?, ?, ?, ?, ?)") - - valueArgs = append(valueArgs, interaction.InteractionId) - valueArgs = append(valueArgs, interaction.Interaction) - valueArgs = append(valueArgs, interaction.BlockHeight) - valueArgs = append(valueArgs, interaction.BlockId) - valueArgs = append(valueArgs, interaction.ContractId) - valueArgs = append(valueArgs, interaction.Function) - valueArgs = append(valueArgs, interaction.Input) - valueArgs = append(valueArgs, interaction.ConfirmationStatus) - - smt := ` -INSERT INTO interactions( -interaction_id, interaction, block_height, block_id, contract_id, function, input, confirmation_status) -VALUES %s -ON CONFLICT (interaction_id) -DO NOTHING` - smt = fmt.Sprintf(smt, strings.Join(valueStrings, ",")) - log.Debug("smttt:", smt) - tx, _ := db.connection.Begin() - _, err := tx.Exec(smt, valueArgs...) - if err != nil { - tx.Rollback() - return err - } - return tx.Commit() - } - - return nil -} - -func (db *Db) UpdateLastProcessedInteractionHeight(height int64) { - sqlStatement := `UPDATE arsyncer SET last_checked_height = $1;` - - _, err := db.connection.Exec(sqlStatement, height) - if err != nil { - log.Error("Error while updating last checked height", err) - } -} - -func connectDb(params ConnectionParams) *sql.DB { - psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+ - "password=%s dbname=%s sslmode=disable", - params.Host, params.Port, params.User, params.Password, params.Dbname) - - db, err := sql.Open("postgres", psqlInfo) - if err != nil { - panic(err) - } - - err = db.Ping() - if err != nil { - panic(err) - } - - log.Info("Successfully connected!") - return db -} - -func ReadPropertiesFile(filename string) (AppConfigProperties, error) { - config := AppConfigProperties{} - - if len(filename) == 0 { - return config, nil - } - file, err := os.Open(filename) - if err != nil { - log.Error("Cannot open file", filename, err) - return nil, err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - if equal := strings.Index(line, "="); equal >= 0 { - if key := strings.TrimSpace(line[:equal]); len(key) > 0 { - value := "" - if len(line) > equal { - value = strings.TrimSpace(line[equal+1:]) - } - config[key] = value - } - } - } - - if err := scanner.Err(); err != nil { - log.Error("Cannot parse file", err) - return nil, err - } - - return config, nil -} diff --git a/syncer/go.mod b/syncer/go.mod deleted file mode 100644 index b9d768e6..00000000 --- a/syncer/go.mod +++ /dev/null @@ -1,26 +0,0 @@ -module github.com/redstone-finance/redstone-sw-gateway/syncer - -go 1.17 - -require ( - github.com/everFinance/arsyncer v1.0.5 - github.com/everFinance/goar v1.3.8 - github.com/lib/pq v1.10.4 -) - -require ( - github.com/everFinance/gojwk v1.0.0 // indirect - github.com/everFinance/ttcrsa v1.1.3 // indirect - github.com/getsentry/sentry-go v0.11.0 // indirect - github.com/go-stack/stack v1.8.1 // indirect - github.com/hamba/avro v1.5.6 // indirect - github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect - github.com/json-iterator/go v1.1.11 // indirect - github.com/mattn/go-colorable v0.1.11 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/panjf2000/ants/v2 v2.4.6 // indirect - github.com/shopspring/decimal v1.2.0 // indirect - golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect -) diff --git a/syncer/go.sum b/syncer/go.sum deleted file mode 100644 index f52aff1d..00000000 --- a/syncer/go.sum +++ /dev/null @@ -1,219 +0,0 @@ -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/everFinance/arsyncer v1.0.5 h1:yqINNFZ5KiWdR5t3zVo1aJajWsAT2nXA6j/t0zo+xdU= -github.com/everFinance/arsyncer v1.0.5/go.mod h1:LYNm4IAneJgUF/w87GH2OMkypERzyY0ctLc0uxvljro= -github.com/everFinance/goar v1.3.4/go.mod h1:x19A2ttl2SbZA0Q9nLBYerKFQiyVgj8doSAhDd505J4= -github.com/everFinance/goar v1.3.8 h1:6DtHpKalNUkkLDHNVwEnw+jLHNjXOoYWhW4BYzHMGY4= -github.com/everFinance/goar v1.3.8/go.mod h1:x19A2ttl2SbZA0Q9nLBYerKFQiyVgj8doSAhDd505J4= -github.com/everFinance/gojwk v1.0.0 h1:le/oI2NgXlrqg3MHU6ka+V30EWcD7TD6+Ilh+go7924= -github.com/everFinance/gojwk v1.0.0/go.mod h1:icXSXsIdpAczlpAtSljQlmABkMTRZENr73KHmo0GOGc= -github.com/everFinance/ttcrsa v1.1.3 h1:RJl9UizbevHZUiWPHVKz1aM6yA8cmkZWaCbOGTD/L0I= -github.com/everFinance/ttcrsa v1.1.3/go.mod h1:Ws7b/oDbYKaZlvyT17nm+zHmzVhGl51r/yPx/Ib5RQk= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8= -github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hamba/avro v1.5.6 h1:/UBljlJ9hLjkcY7PhpI/bFYb4RMEXHEwHr17gAm/+l8= -github.com/hamba/avro v1.5.6/go.mod h1:3vNT0RLXXpFm2Tb/5KC71ZRJlOroggq1Rcitb6k4Fr8= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac h1:n1DqxAo4oWPMvH1+v+DLYlMCecgumhhgnxAPdqDIFHI= -github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/panjf2000/ants/v2 v2.4.6 h1:drmj9mcygn2gawZ155dRbo+NfXEfAssjZNU1qoIb4gQ= -github.com/panjf2000/ants/v2 v2.4.6/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/syncer/sw_types/types.go b/syncer/sw_types/types.go deleted file mode 100644 index 1a27bb8b..00000000 --- a/syncer/sw_types/types.go +++ /dev/null @@ -1,38 +0,0 @@ -package sw_types - -import "github.com/everFinance/goar/types" - -type DbInteraction struct { - InteractionId string - Interaction string - BlockHeight int64 - BlockId string - ContractId string - Function string - Input string - ConfirmationStatus string -} - -type SwOwner struct { - Address string `json:"address"` -} - -type SwBlock struct { - Height int64 `json:"height"` - Id string `json:"id"` - Timestamp int64 `json:"timestamp"` -} - -type Amount struct { - Winston string `json:"winston"` -} - -type SwInteraction struct { - Id string `json:"id"` - Owner SwOwner `json:"owner"` - Recipient string `json:"recipient"` - Tags []types.Tag `json:"tags"` - Block SwBlock `json:"block"` - Fee Amount `json:"fee"` - Quantity Amount `json:"quantity"` -} diff --git a/syncer/syncer.go b/syncer/syncer.go deleted file mode 100644 index 56f520cf..00000000 --- a/syncer/syncer.go +++ /dev/null @@ -1,128 +0,0 @@ -package main - -import ( - "encoding/json" - "github.com/everFinance/arsyncer" - "github.com/everFinance/goar/types" - "github.com/everFinance/goar/utils" - "github.com/redstone-finance/redstone-sw-gateway/syncer/db" - "github.com/redstone-finance/redstone-sw-gateway/syncer/sw_types" - "os" - "strconv" -) - -var log = arsyncer.NewLog("syncer") - -func main() { - propertiesPath := os.Args[1] - props, err := db.ReadPropertiesFile(propertiesPath) - if err != nil { - log.Error("Cannot read properties file", err) - return - } - - port, err := strconv.Atoi(props["DB_PORT"]) - if err != nil { - log.Error("Cannot parse db port", err) - return - } - - db := db.New(db.ConnectionParams{ - Host: props["DB_HOST"], - Port: port, - User: props["DB_USER"], - Password: props["DB_PASSWORD"], - Dbname: props["DB_NAME"], - }) - defer db.Close() - - startHeight := db.LoadLatestSyncedBlock() - - swcFilterParams := arsyncer.FilterParams{ - Tags: []types.Tag{ - {Name: "App-Name", Value: "SmartWeaveAction"}, - }, - } - - arNode := "https://arweave.net" - concurrencyNumber := 50 - s := arsyncer.New(startHeight, swcFilterParams, arNode, concurrencyNumber, 15) - s.Run() - - for { - select { - case sTx := <-s.SubscribeTxCh(): - interactions := make([]sw_types.DbInteraction, 0) - var highestBlockHeight int64 = 0 - for _, tx := range sTx { - decodedTags, _ := utils.TagsDecode(tx.Tags) - var contract, input, function = "", "", "" - for _, t := range decodedTags { - if t.Name == "Contract" { - contract = t.Value - } - if t.Name == "Input" { - input = t.Value - var parsedInput map[string]interface{} - err := json.Unmarshal([]byte(input), &parsedInput) - if err != nil { - log.Error("Cannot parse function in input", input) - } - if val, ok := parsedInput["function"]; ok { - function = val.(string) - } - } - - if contract != "" && input != "" { - break - } - } - - swInteraction := sw_types.SwInteraction{ - Id: tx.ID, - Owner: sw_types.SwOwner{ - Address: tx.Owner, - }, - Recipient: tx.Target, - Tags: decodedTags, - Block: sw_types.SwBlock{ - Height: tx.BlockHeight, - Id: tx.BlockId, - Timestamp: tx.BlockTimestamp, - }, - Fee: sw_types.Amount{ - Winston: tx.Reward, - }, - Quantity: sw_types.Amount{ - Winston: tx.Quantity, - }, - } - - swInteractionJson, err := json.Marshal(swInteraction) - if err != nil { - log.Error("Error while marshalling interaction", err) - panic(err) - } - log.Debug("Interaction:", string(swInteractionJson)) - highestBlockHeight = tx.BlockHeight - - interactions = append(interactions, sw_types.DbInteraction{ - InteractionId: tx.ID, - Interaction: string(swInteractionJson), - BlockHeight: tx.BlockHeight, - BlockId: tx.BlockId, - ContractId: contract, - Function: function, - Input: input, - ConfirmationStatus: "not_processed", - }) - } - - err := db.BatchInsertInteractions(interactions) - if err == nil && highestBlockHeight != 0 { - log.Info("Updating last processed block height to ", highestBlockHeight) - db.UpdateLastProcessedInteractionHeight(highestBlockHeight) - } - } - } -} diff --git a/tsconfig.json b/tsconfig.json index 1ed549b5..ddd525be 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,10 +5,11 @@ "esModuleInterop": true, "downlevelIteration": true, "skipLibCheck": true, - "allowJs": true + "allowJs": true, + "resolveJsonModule": true }, "ts-node": { "files": true }, - "files": ["src/TsLogFactory.d.ts", "src/JSONStream.d.ts", "src/gateway/init.ts"] + "files": ["src/TsLogFactory.d.ts", "src/JSONStream.d.ts", "src/gateway/init.ts"], } diff --git a/welcome.html b/welcome.html deleted file mode 100644 index e4c61e9f..00000000 --- a/welcome.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - RedStone SmartWeave Gateway - - - -

Hi! I'm the RedStone SmartWeave Gateway, ready to serve your SmartWeave contracts interactions!

-

If you want to learn more about me, check the - gateway docs. -

-

To explore indexed data - head over to - SonAR. -

- -

If you want to learn how to integrate me with the RedStone - Contracts SDK - check the SDK - docs and examples. -

-

If you need more help or happen to find any issues - join our Discord.

-

Powered by RedStone.

- - - - \ No newline at end of file diff --git a/yalc.lock b/yalc.lock deleted file mode 100644 index e1c2aedd..00000000 --- a/yalc.lock +++ /dev/null @@ -1,10 +0,0 @@ -{ - "version": "v1", - "packages": { - "redstone-smartweave": { - "signature": "1bc3761907e2b09ac5f74e5a898b2fc6", - "file": true, - "replaced": "0.4.61" - } - } -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 4fedee39..112a755c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1667,6 +1667,89 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@opencensus/core@0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@opencensus/core/-/core-0.0.9.tgz#b16f775435ee309433e4126af194d37313fc93b3" + integrity sha512-31Q4VWtbzXpVUd2m9JS6HEaPjlKvNMOiF7lWKNmXF84yUcgfAFL5re7/hjDmdyQbOp32oGc+RFV78jXIldVz6Q== + dependencies: + continuation-local-storage "^3.2.1" + log-driver "^1.2.7" + semver "^5.5.0" + shimmer "^1.2.0" + uuid "^3.2.1" + +"@opencensus/core@^0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@opencensus/core/-/core-0.0.8.tgz#df01f200c2d2fbfe14dae129a1a86fb87286db92" + integrity sha512-yUFT59SFhGMYQgX0PhoTR0LBff2BEhPrD9io1jWfF/VDbakRfs6Pq60rjv0Z7iaTav5gQlttJCX2+VPxFWCuoQ== + dependencies: + continuation-local-storage "^3.2.1" + log-driver "^1.2.7" + semver "^5.5.0" + shimmer "^1.2.0" + uuid "^3.2.1" + +"@opencensus/propagation-b3@0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@opencensus/propagation-b3/-/propagation-b3-0.0.8.tgz#0751e6fd75f09400d9d3c419001e9e15a0df68e9" + integrity sha512-PffXX2AL8Sh0VHQ52jJC4u3T0H6wDK6N/4bg7xh4ngMYOIi13aR1kzVvX1sVDBgfGwDOkMbl4c54Xm3tlPx/+A== + dependencies: + "@opencensus/core" "^0.0.8" + uuid "^3.2.1" + +"@pm2/agent@~2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@pm2/agent/-/agent-2.0.1.tgz#0edffc54cd8ee2b12f90136264e7880f3f78c79d" + integrity sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw== + dependencies: + async "~3.2.0" + chalk "~3.0.0" + dayjs "~1.8.24" + debug "~4.3.1" + eventemitter2 "~5.0.1" + fast-json-patch "^3.0.0-1" + fclone "~1.0.11" + nssocket "0.6.0" + pm2-axon "~4.0.1" + pm2-axon-rpc "~0.7.0" + proxy-agent "~5.0.0" + semver "~7.2.0" + ws "~7.4.0" + +"@pm2/io@~5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@pm2/io/-/io-5.0.0.tgz#623cbcaf6fe39375f20ac2e75497477a1b1ec5c5" + integrity sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw== + dependencies: + "@opencensus/core" "0.0.9" + "@opencensus/propagation-b3" "0.0.8" + async "~2.6.1" + debug "~4.3.1" + eventemitter2 "^6.3.1" + require-in-the-middle "^5.0.0" + semver "6.3.0" + shimmer "^1.2.0" + signal-exit "^3.0.3" + tslib "1.9.3" + +"@pm2/js-api@~0.6.7": + version "0.6.7" + resolved "https://registry.yarnpkg.com/@pm2/js-api/-/js-api-0.6.7.tgz#ed28c3b7b6d26f03f826318754fdc5468afa589f" + integrity sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw== + dependencies: + async "^2.6.3" + axios "^0.21.0" + debug "~4.3.1" + eventemitter2 "^6.3.1" + ws "^7.0.0" + +"@pm2/pm2-version-check@latest": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz#cf97fbb14b0eca95430ca05eedccbd2683806e43" + integrity sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA== + dependencies: + debug "^4.3.1" + "@randlabs/communication-bridge@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@randlabs/communication-bridge/-/communication-bridge-1.0.1.tgz#d1ecfc29157afcbb0ca2d73122d67905eecb5bf3" @@ -2049,6 +2132,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/uuid@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6" + integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA== + "@types/ws@^7.4.4": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -2222,7 +2310,7 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -agent-base@6: +agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -2271,6 +2359,18 @@ amazon-cognito-identity-js@5.2.12: isomorphic-unfetch "^3.0.0" js-cookie "^2.2.1" +amp-message@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/amp-message/-/amp-message-0.1.2.tgz#a78f1c98995087ad36192a41298e4db49e3dfc45" + integrity sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg== + dependencies: + amp "0.3.1" + +amp@0.3.1, amp@~0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/amp/-/amp-0.3.1.tgz#6adf8d58a74f361e82c1fa8d389c079e139fc47d" + integrity sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw== + ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" @@ -2317,7 +2417,7 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -anymatch@^3.0.3, anymatch@~3.1.1: +anymatch@^3.0.3, anymatch@~3.1.1, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2458,6 +2558,21 @@ asn1.js@^5.4.1: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" +ast-types@^0.13.2: + version "0.13.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + +async-listener@^0.6.0: + version "0.6.10" + resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" + integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== + dependencies: + semver "^5.3.0" + shimmer "^1.1.0" + async-retry@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" @@ -2465,7 +2580,14 @@ async-retry@^1.3.3: dependencies: retry "0.13.1" -async@^3.2.3: +async@^2.6.3, async@~2.6.1: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +async@^3.2.0, async@^3.2.3, async@~3.2.0: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== @@ -2528,7 +2650,7 @@ axios@0.27.2, axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axios@^0.21.3: +axios@^0.21.0, axios@^0.21.3: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== @@ -2661,6 +2783,11 @@ bindings@^1.3.0: dependencies: file-uri-to-path "1.0.0" +bintrees@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" + integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== + bip39-light@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/bip39-light/-/bip39-light-1.0.7.tgz#06a72f251b89389a136d3f177f29b03342adc5ba" @@ -2688,6 +2815,16 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +blessed@0.1.81: + version "0.1.81" + resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129" + integrity sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ== + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + bn.js@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" @@ -2703,6 +2840,11 @@ bn.js@^5.0.0, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +bodec@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/bodec/-/bodec-0.1.0.tgz#bc851555430f23c9f7650a75ef64c6a94c3418cc" + integrity sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ== + borsh@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.6.0.tgz#a7c9eeca6a31ca9e0607cb49f329cb659eb791e1" @@ -2931,6 +3073,14 @@ catering@^2.1.0, catering@^2.1.1: resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== +chalk@3.0.0, chalk@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2963,6 +3113,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +charm@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296" + integrity sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ== + chokidar@3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" @@ -2978,6 +3133,21 @@ chokidar@3.5.1: optionalDependencies: fsevents "~2.3.1" +chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + ci-info@^3.2.0: version "3.6.2" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.6.2.tgz#362ea15378f1c39378ba786affbc1c9ef015ecfd" @@ -3035,6 +3205,13 @@ cli-table@0.3.11: dependencies: colors "1.0.3" +cli-tableau@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cli-tableau/-/cli-tableau-2.0.1.tgz#baa78d83e08a2d7ab79b7dad9406f0254977053f" + integrity sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ== + dependencies: + chalk "3.0.0" + cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" @@ -3108,10 +3285,10 @@ color-support@^1.1.1: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -colorette@2.0.16: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== +colorette@2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== colors@1.0.3: version "1.0.3" @@ -3130,21 +3307,26 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== + commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^8.2.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commander@^9.1.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + compress-commons@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" @@ -3179,6 +3361,14 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +continuation-local-storage@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" + integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== + dependencies: + async-listener "^0.6.0" + emitter-listener "^1.1.1" + convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" @@ -3248,6 +3438,11 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +croner@~4.1.92: + version "4.1.97" + resolved "https://registry.yarnpkg.com/croner/-/croner-4.1.97.tgz#6e373dc7bb3026fab2deb0d82685feef20796766" + integrity sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ== + cross-argv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/cross-argv/-/cross-argv-2.0.0.tgz#2e7907ba3246f82c967623a3e8525925bbd6c0ad" @@ -3323,6 +3518,16 @@ csv@^6.0.5: csv-stringify "^6.2.2" stream-transform "^3.2.1" +culvert@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/culvert/-/culvert-0.1.2.tgz#9502f5f0154a2d5a22a023e79f71cc936fa6ef6f" + integrity sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg== + +data-uri-to-buffer@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" + integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -3332,7 +3537,17 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: +dayjs@~1.11.5: + version "1.11.7" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" + integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== + +dayjs@~1.8.24: + version "1.8.36" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50" + integrity sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw== + +debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3346,12 +3561,12 @@ debug@4.3.1: dependencies: ms "2.1.2" -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== +debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: - ms "2.1.2" + ms "^2.1.1" decamelize@^4.0.0: version "4.0.0" @@ -3390,6 +3605,16 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +degenerator@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.2.tgz#6a61fcc42a702d6e50ff6023fe17bff435f68235" + integrity sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ== + dependencies: + ast-types "^0.13.2" + escodegen "^1.8.1" + esprima "^4.0.0" + vm2 "^3.9.8" + delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" @@ -3499,6 +3724,13 @@ elliptic@6.5.4, elliptic@^6.5.3, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emitter-listener@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" + integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== + dependencies: + shimmer "^1.2.0" + emittery@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" @@ -3521,7 +3753,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: dependencies: once "^1.4.0" -enquirer@^2.3.5: +enquirer@2.3.6, enquirer@^2.3.5: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -3581,6 +3813,18 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escodegen@^1.8.1: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + escodegen@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" @@ -3703,7 +3947,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -3761,6 +4005,21 @@ ethers@^5.5.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +eventemitter2@5.0.1, eventemitter2@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452" + integrity sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg== + +eventemitter2@^6.3.1: + version "6.4.9" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" + integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== + +eventemitter2@~0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" + integrity sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ== + eventemitter3@^4.0.0, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -3858,6 +4117,11 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-json-patch@^3.0.0-1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.1.1.tgz#85064ea1b1ebf97a3f7ad01e23f9337e72c66947" + integrity sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ== + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -3892,6 +4156,11 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fclone@1.0.11, fclone@~1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640" + integrity sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw== + figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -3911,6 +4180,11 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +file-uri-to-path@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" + integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -3992,16 +4266,33 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.1: +fsevents@^2.3.2, fsevents@~2.3.1, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +ftp@^0.3.10: + version "0.3.10" + resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" + integrity sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ== + dependencies: + readable-stream "1.1.x" + xregexp "2.0.0" + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -4041,12 +4332,34 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -getopts@2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" - integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA== +get-uri@3: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" + integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== + dependencies: + "@tootallnate/once" "1" + data-uri-to-buffer "3" + debug "4" + file-uri-to-path "2" + fs-extra "^8.1.0" + ftp "^0.3.10" + +getopts@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" + integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA== -glob-parent@^5.1.2, glob-parent@~5.1.0: +git-node-fs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/git-node-fs/-/git-node-fs-1.0.0.tgz#49b215e242ebe43aa4c7561bbba499521752080f" + integrity sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ== + +git-sha1@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/git-sha1/-/git-sha1-0.1.2.tgz#599ac192b71875825e13a445f3a6e05118c2f745" + integrity sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg== + +glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4072,7 +4385,7 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: +glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4115,6 +4428,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +graceful-fs@^4.1.6: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -4261,7 +4579,7 @@ http-parser-js@^0.5.2: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== -http-proxy-agent@^4.0.1: +http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== @@ -4270,7 +4588,7 @@ http-proxy-agent@^4.0.1: agent-base "6" debug "4" -https-proxy-agent@^5.0.0: +https-proxy-agent@5, https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -4291,7 +4609,7 @@ hyperid@^3.0.0: uuid "^8.3.2" uuid-parse "^1.1.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4347,11 +4665,16 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + inquirer@^8.2.0: version "8.2.5" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" @@ -4393,6 +4716,16 @@ ioredis@^5.2.4: redis-parser "^3.0.0" standard-as-callback "^2.1.0" +ip@^1.1.5: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" + integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + is-arguments@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -4510,6 +4843,11 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5004,6 +5342,16 @@ js-cookie@^2.2.1: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== +js-git@^0.7.8: + version "0.7.8" + resolved "https://registry.yarnpkg.com/js-git/-/js-git-0.7.8.tgz#52fa655ab61877d6f1079efc6534b554f31e5444" + integrity sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA== + dependencies: + bodec "^0.1.0" + culvert "^0.1.2" + git-sha1 "^0.1.2" + pako "^0.2.5" + js-sha256@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" @@ -5139,6 +5487,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -5165,23 +5520,24 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -knex@0.95.14: - version "0.95.14" - resolved "https://registry.yarnpkg.com/knex/-/knex-0.95.14.tgz#47eca7757cbc5872b7c9a3c67ae3b7ac6d00cf10" - integrity sha512-j4qLjWySrC/JRRVtOpoR2LcS1yBOsd7Krc6mEukPvmTDX/w11pD52Pq9FYR56/kLXGeAV8jFdWBjsZFi1mscWg== +knex@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/knex/-/knex-2.4.2.tgz#a34a289d38406dc19a0447a78eeaf2d16ebedd61" + integrity sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg== dependencies: - colorette "2.0.16" - commander "^7.1.0" - debug "4.3.2" + colorette "2.0.19" + commander "^9.1.0" + debug "4.3.4" escalade "^3.1.1" esm "^3.2.25" - getopts "2.2.5" + get-package-type "^0.1.0" + getopts "2.3.0" interpret "^2.2.0" lodash "^4.17.21" pg-connection-string "2.5.0" - rechoir "0.7.0" + rechoir "^0.8.0" resolve-from "^5.0.0" - tarn "^3.0.1" + tarn "^3.0.2" tildify "2.0.0" koa-bodyparser@4.3.0: @@ -5221,10 +5577,10 @@ koa-is-json@^1.0.0: resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" integrity sha512-+97CtHAlWDx0ndt0J8y3P12EWLwTLMXIfMnYDev3wOTwH/RpBGMlfn4bDXlMEg1u73K6XRE9BbUp+5ZAYoRYWw== -koa@2.13.4: - version "2.13.4" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e" - integrity sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g== +koa@2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.14.1.tgz#defb9589297d8eb1859936e777f3feecfc26925c" + integrity sha512-USJFyZgi2l0wDgqkfD27gL4YGno7TfUkcmOe6UOLFOVuN+J7FwnNu4Dydl4CUQzraM1lBAiGed0M9OVJoT0Kqw== dependencies: accepts "^1.3.5" cache-content-type "^1.0.0" @@ -5250,6 +5606,11 @@ koa@2.13.4: type-is "^1.6.16" vary "^1.1.2" +lazy@~1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" + integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== + lazystream@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" @@ -5376,11 +5737,16 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== -lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-driver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" + integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== + log-symbols@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" @@ -5396,6 +5762,13 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -5526,6 +5899,11 @@ minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +mkdirp@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mocha@^8.1.2: version "8.4.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" @@ -5557,6 +5935,11 @@ mocha@^8.1.2: yargs-parser "20.2.4" yargs-unparser "2.0.0" +module-details-from-path@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" + integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== + module-error@^1.0.1, module-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" @@ -5567,7 +5950,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5585,7 +5968,7 @@ mustache@^4.0.0: resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== -mute-stream@0.0.8: +mute-stream@0.0.8, mute-stream@~0.0.4: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== @@ -5641,11 +6024,25 @@ near-seed-phrase@^0.2.0: near-hd-key "^1.2.1" tweetnacl "^1.0.2" +needle@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +netmask@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" @@ -5690,6 +6087,14 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +nssocket@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/nssocket/-/nssocket-0.6.0.tgz#59f96f6ff321566f33c70f7dbeeecdfdc07154fa" + integrity sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w== + dependencies: + eventemitter2 "~0.4.14" + lazy "~1.0.11" + nwsapi@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" @@ -5815,6 +6220,30 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pac-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz#b718f76475a6a5415c2efbe256c1c971c84f635e" + integrity sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + get-uri "3" + http-proxy-agent "^4.0.1" + https-proxy-agent "5" + pac-resolver "^5.0.0" + raw-body "^2.2.0" + socks-proxy-agent "5" + +pac-resolver@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-5.0.1.tgz#c91efa3a9af9f669104fa2f51102839d01cde8e7" + integrity sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q== + dependencies: + degenerator "^3.0.2" + ip "^1.1.5" + netmask "^2.0.2" + packet-reader@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" @@ -5825,6 +6254,11 @@ paho-mqtt@^1.1.0: resolved "https://registry.yarnpkg.com/paho-mqtt/-/paho-mqtt-1.1.0.tgz#8c10e29eb162e966fb15188d965c3dce505de9d9" integrity sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA== +pako@^0.2.5: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== + pako@^1.0.3: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -5918,15 +6352,15 @@ pg-int8@1.0.1: resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== -pg-pool@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.2.tgz#ed1bed1fb8d79f1c6fd5fb1c99e990fbf9ddf178" - integrity sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w== +pg-pool@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.0.tgz#3190df3e4747a0d23e5e9e8045bcd99bda0a712e" + integrity sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ== -pg-protocol@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" - integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== +pg-protocol@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833" + integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q== pg-query-stream@^4.2.3: version "4.2.4" @@ -5946,16 +6380,16 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@8.7.3: - version "8.7.3" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.3.tgz#8a5bdd664ca4fda4db7997ec634c6e5455b27c44" - integrity sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw== +pg@8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.10.0.tgz#5b8379c9b4a36451d110fc8cd98fc325fe62ad24" + integrity sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ== dependencies: buffer-writer "2.0.0" packet-reader "1.0.0" pg-connection-string "^2.5.0" - pg-pool "^3.5.1" - pg-protocol "^1.5.0" + pg-pool "^3.6.0" + pg-protocol "^1.6.0" pg-types "^2.1.0" pgpass "1.x" @@ -5976,6 +6410,20 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidusage@^2.0.21: + version "2.0.21" + resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-2.0.21.tgz#7068967b3d952baea73e57668c98b9eaa876894e" + integrity sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA== + dependencies: + safe-buffer "^5.2.1" + +pidusage@~3.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-3.0.2.tgz#6faa5402b2530b3af2cf93d13bcf202889724a53" + integrity sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w== + dependencies: + safe-buffer "^5.2.1" + pirates@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" @@ -5988,6 +6436,86 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pm2-axon-rpc@~0.7.0, pm2-axon-rpc@~0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz#2daec5383a63135b3f18babb70266dacdcbc429a" + integrity sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw== + dependencies: + debug "^4.3.1" + +pm2-axon@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pm2-axon/-/pm2-axon-4.0.1.tgz#a7b4bb586e9aeb35b1042b488cde15b60cabafd2" + integrity sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg== + dependencies: + amp "~0.3.1" + amp-message "~0.1.1" + debug "^4.3.1" + escape-string-regexp "^4.0.0" + +pm2-deploy@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pm2-deploy/-/pm2-deploy-1.0.2.tgz#98d8385553a3a4dca11c7b3116deb519bc5961a7" + integrity sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg== + dependencies: + run-series "^1.1.8" + tv4 "^1.3.0" + +pm2-multimeter@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz#1a1e55153d41a05534cea23cfe860abaa0eb4ace" + integrity sha512-S+wT6XfyKfd7SJIBqRgOctGxaBzUOmVQzTAS+cg04TsEUObJVreha7lvCfX8zzGVr871XwCSnHUU7DQQ5xEsfA== + dependencies: + charm "~0.1.1" + +pm2-sysmonit@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz#eddea34a53fd8c8d7c3efb73b97a3c548686e24d" + integrity sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA== + dependencies: + async "^3.2.0" + debug "^4.3.1" + pidusage "^2.0.21" + systeminformation "^5.7" + tx2 "~1.0.4" + +pm2@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pm2/-/pm2-5.3.0.tgz#06850810f77cd98495ae1c66fbdd028a8fb5899e" + integrity sha512-xscmQiAAf6ArVmKhjKTeeN8+Td7ZKnuZFFPw1DGkdFPR/0Iyx+m+1+OpCdf9+HQopX3VPc9/wqPQHqVOfHum9w== + dependencies: + "@pm2/agent" "~2.0.0" + "@pm2/io" "~5.0.0" + "@pm2/js-api" "~0.6.7" + "@pm2/pm2-version-check" latest + async "~3.2.0" + blessed "0.1.81" + chalk "3.0.0" + chokidar "^3.5.3" + cli-tableau "^2.0.0" + commander "2.15.1" + croner "~4.1.92" + dayjs "~1.11.5" + debug "^4.3.1" + enquirer "2.3.6" + eventemitter2 "5.0.1" + fclone "1.0.11" + mkdirp "1.0.4" + needle "2.4.0" + pidusage "~3.0" + pm2-axon "~4.0.1" + pm2-axon-rpc "~0.7.1" + pm2-deploy "~1.0.2" + pm2-multimeter "^0.1.2" + promptly "^2" + semver "^7.2" + source-map-support "0.5.21" + sprintf-js "1.1.2" + vizion "~2.2.1" + yamljs "0.3.0" + optionalDependencies: + pm2-sysmonit "^1.2.8" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -6054,6 +6582,20 @@ progress@^2.0.0, progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +prom-client@12: + version "12.0.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-12.0.0.tgz#9689379b19bd3f6ab88a9866124db9da3d76c6ed" + integrity sha512-JbzzHnw0VDwCvoqf8y1WDtq4wSBAbthMB1pcVI/0lzdqHGJI3KBJDXle70XK+c7Iv93Gihqo0a5LlOn+g8+DrQ== + dependencies: + tdigest "^0.1.1" + +promptly@^2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/promptly/-/promptly-2.2.0.tgz#2a13fa063688a2a5983b161fff0108a07d26fc74" + integrity sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA== + dependencies: + read "^1.0.4" + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -6062,6 +6604,25 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +proxy-agent@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-5.0.0.tgz#d31405c10d6e8431fde96cba7a0c027ce01d633b" + integrity sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g== + dependencies: + agent-base "^6.0.0" + debug "4" + http-proxy-agent "^4.0.0" + https-proxy-agent "^5.0.0" + lru-cache "^5.1.1" + pac-proxy-agent "^5.0.0" + proxy-from-env "^1.0.0" + socks-proxy-agent "^5.0.0" + +proxy-from-env@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -6114,6 +6675,16 @@ randombytes@^2.0.1, randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +raw-body@^2.2.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + raw-body@^2.3.3, raw-body@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" @@ -6136,6 +6707,23 @@ react-native-get-random-values@^1.4.0: dependencies: fast-base64-decode "^1.0.0" +read@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + integrity sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ== + dependencies: + mute-stream "~0.0.4" + +readable-stream@1.1.x: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.3.3: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -6172,12 +6760,19 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" -rechoir@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca" - integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q== +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: - resolve "^1.9.0" + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" @@ -6246,6 +6841,15 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-in-the-middle@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz#4b71e3cc7f59977100af9beb76bf2d056a5a6de2" + integrity sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg== + dependencies: + debug "^4.1.1" + module-details-from-path "^1.0.3" + resolve "^1.22.1" + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -6273,7 +6877,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.20.0, resolve@^1.9.0: +resolve@^1.20.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -6352,6 +6956,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +run-series@^1.1.8: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.9.tgz#15ba9cb90e6a6c054e67c98e1dc063df0ecc113a" + integrity sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g== + rxjs@^7.5.5: version "7.5.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" @@ -6359,7 +6968,7 @@ rxjs@^7.5.5: dependencies: tslib "^2.1.0" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -6379,6 +6988,11 @@ safe-stable-stringify@2.4.1, safe-stable-stringify@^2.4.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -6400,17 +7014,27 @@ secp256k1@^4.0.2: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: +semver@6.3.0, semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@7.x, semver@^7.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^5.3.0, semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@~7.2.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.2.3.tgz#3641217233c6382173c76bf2c7ecd1e1c16b0d8a" + integrity sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig== serialize-javascript@5.0.1: version "5.0.1" @@ -6444,6 +7068,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shimmer@^1.1.0, shimmer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -6468,7 +7097,29 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -source-map-support@^0.5.6: +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@5, socks-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== + dependencies: + agent-base "^6.0.2" + debug "4" + socks "^2.3.3" + +socks@^2.3.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +source-map-support@0.5.21, source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -6491,6 +7142,11 @@ split2@^4.1.0: resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== +sprintf-js@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -6565,6 +7221,11 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -6657,6 +7318,11 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +systeminformation@^5.7: + version "5.17.12" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.17.12.tgz#5b3e1bfcd5c2c5b459f1a88e61fed27cf9668ba8" + integrity sha512-I3pfMW2vue53u+X08BNxaJieaHkRoMMKjWetY9lbYJeWFaeWPO6P4FkNc4XOCX8F9vbQ0HqQ25RJoz3U/B7liw== + tar-stream@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" @@ -6668,11 +7334,18 @@ tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tarn@^3.0.1: +tarn@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693" integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ== +tdigest@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" + integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA== + dependencies: + bintrees "1.0.2" + terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -6828,6 +7501,11 @@ tsconfig-paths@^3.10.1: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + tslib@^1.11.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -6838,6 +7516,11 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.0.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -6850,11 +7533,23 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tv4@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.3.0.tgz#d020c846fadd50c855abb25ebaecc68fc10f7963" + integrity sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw== + tweetnacl@1.0.3, tweetnacl@^1.0.1, tweetnacl@^1.0.2, tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== +tx2@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tx2/-/tx2-1.0.5.tgz#ee0b0e5e2c351f8d23e54bdf46dd60afa3bbc73d" + integrity sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg== + dependencies: + json-stringify-safe "^5.0.1" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -6941,6 +7636,11 @@ universal-cookie@^4.0.4: "@types/cookie" "^0.3.3" cookie "^0.4.0" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" @@ -7027,6 +7727,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + uzip-module@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/uzip-module/-/uzip-module-1.0.3.tgz#6bbabe2a3efea5d5a4a47479f523a571de3427ce" @@ -7056,6 +7761,16 @@ vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +vizion@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/vizion/-/vizion-2.2.1.tgz#04201ea45ffd145d5b5210e385a8f35170387fb2" + integrity sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww== + dependencies: + async "^2.6.3" + git-node-fs "^1.0.0" + ini "^1.3.5" + js-git "^0.7.8" + vlq@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/vlq/-/vlq-2.0.4.tgz#6057b85729245b9829e3cc7755f95b228d4fe041" @@ -7069,6 +7784,14 @@ vm2@3.9.11: acorn "^8.7.0" acorn-walk "^8.2.0" +vm2@^3.9.8: + version "3.9.14" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.14.tgz#964042b474cf1e6e4f475a39144773cdb9deb734" + integrity sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA== + dependencies: + acorn "^8.7.0" + acorn-walk "^8.2.0" + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -7307,12 +8030,12 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@7.4.6: +ws@7.4.6, ws@~7.4.0: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@^7.4.5, ws@^7.4.6: +ws@^7.0.0, ws@^7.4.5, ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== @@ -7332,6 +8055,11 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xregexp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" + integrity sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA== + xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -7342,11 +8070,24 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yamljs@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/yamljs/-/yamljs-0.3.0.tgz#dc060bf267447b39f7304e9b2bfbe8b5a7ddb03b" + integrity sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ== + dependencies: + argparse "^1.0.7" + glob "^7.0.5" + yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" From 7e9056b6a675f4caa71e6c3df64898bf18f807ca Mon Sep 17 00:00:00 2001 From: ppe Date: Fri, 24 Mar 2023 13:26:16 +0100 Subject: [PATCH 02/95] chore: logging --- src/gateway/LastTxSyncer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/LastTxSyncer.ts b/src/gateway/LastTxSyncer.ts index 346bd476..4802c347 100644 --- a/src/gateway/LastTxSyncer.ts +++ b/src/gateway/LastTxSyncer.ts @@ -14,9 +14,9 @@ export class LastTxSync { }); // https://stackoverflow.com/a/20963803 - const benchmark = Benchmark.measure(); - await trx.raw(`SET LOCAL lock_timeout = '2s';`) + await trx.raw(`SET LOCAL lock_timeout = '2s';`) + const benchmark = Benchmark.measure(); await trx.raw(` SELECT pg_advisory_xact_lock(?, ?); `, [lockId[0], lockId[1]]); From f990346011b221da87c5e0410ba3723af6d98d51 Mon Sep 17 00:00:00 2001 From: ppe Date: Fri, 24 Mar 2023 13:34:57 +0100 Subject: [PATCH 03/95] fix: path fix --- src/gateway/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 3ccf9828..855f81f8 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -236,7 +236,7 @@ function initArweave(): Arweave { } function readGwPubSubConfig(filename: string) { - const pubSubConfigPath = path.join('.secrets', filename); + const pubSubConfigPath = path.join('./.secrets', filename); if (fs.existsSync(pubSubConfigPath)) { const json = fs.readFileSync(pubSubConfigPath, 'utf-8'); return JSON.parse(json); From b597db57c7ccb583e97da6c2e93eb88abb31a59a Mon Sep 17 00:00:00 2001 From: ppe Date: Sun, 26 Mar 2023 12:05:05 +0200 Subject: [PATCH 04/95] fix: issue with pubsub config path --- src/gateway/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 855f81f8..52685372 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -236,7 +236,7 @@ function initArweave(): Arweave { } function readGwPubSubConfig(filename: string) { - const pubSubConfigPath = path.join('./.secrets', filename); + const pubSubConfigPath = path.join(`./.secrets/${filename}`); if (fs.existsSync(pubSubConfigPath)) { const json = fs.readFileSync(pubSubConfigPath, 'utf-8'); return JSON.parse(json); From abb65300d82e7173e3b167dc35548b527f33425a Mon Sep 17 00:00:00 2001 From: ppe Date: Sun, 26 Mar 2023 12:09:55 +0200 Subject: [PATCH 05/95] fix: issue with pubsub config path --- src/gateway/init.ts | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 52685372..4e31d62b 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -1,27 +1,25 @@ import yargs from 'yargs'; -import { hideBin } from 'yargs/helpers'; -import { Knex } from 'knex'; +import {hideBin} from 'yargs/helpers'; import Koa from 'koa'; import Application from 'koa'; import bodyParser from 'koa-bodyparser'; -import { ArweaveWrapper, LexicographicalInteractionsSorter, LoggerFactory, WarpLogger } from 'warp-contracts'; +import {ArweaveWrapper, LexicographicalInteractionsSorter, LoggerFactory, WarpLogger} from 'warp-contracts'; import Arweave from 'arweave'; -import { runGatewayTasks } from './runGatewayTasks'; +import {runGatewayTasks} from './runGatewayTasks'; import gatewayRouter from './router/gatewayRouter'; import * as fs from 'fs'; import cluster from 'cluster'; import welcomeRouter from './router/welcomeRouter'; import Bundlr from '@bundlr-network/client'; -import { initBundlr } from '../bundlr/connect'; -import { JWKInterface } from 'arweave/node/lib/wallet'; -import { runNetworkInfoCacheTask } from './tasks/networkInfoCache'; -import path from 'path'; +import {initBundlr} from '../bundlr/connect'; +import {JWKInterface} from 'arweave/node/lib/wallet'; +import {runNetworkInfoCacheTask} from './tasks/networkInfoCache'; import Redis from 'ioredis'; -import { LastTxSync } from './LastTxSyncer'; -import { initPubSub } from 'warp-contracts-pubsub'; +import {LastTxSync} from './LastTxSyncer'; +import {initPubSub} from 'warp-contracts-pubsub'; // @ts-ignore -import { EvmSignatureVerificationServerPlugin } from 'warp-signature/server'; -import { DatabaseSource } from '../db/databaseSource'; +import {EvmSignatureVerificationServerPlugin} from 'warp-signature/server'; +import {DatabaseSource} from '../db/databaseSource'; const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; @@ -85,7 +83,7 @@ export interface GatewayContext { logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode. noSync = ${noSync}`); const arweave = initArweave(); - const { bundlr, jwk } = initBundlr(logger); + const {bundlr, jwk} = initBundlr(logger); const dbSource = new DatabaseSource([ { @@ -236,11 +234,6 @@ function initArweave(): Arweave { } function readGwPubSubConfig(filename: string) { - const pubSubConfigPath = path.join(`./.secrets/${filename}`); - if (fs.existsSync(pubSubConfigPath)) { - const json = fs.readFileSync(pubSubConfigPath, 'utf-8'); - return JSON.parse(json); - } else { - return false; - } + const json = fs.readFileSync(`./.secrets/${filename}`, 'utf-8'); + return JSON.parse(json); } From d161aa68c8986468cd88b966f6dc12ab8c33506c Mon Sep 17 00:00:00 2001 From: ppe Date: Sun, 26 Mar 2023 13:29:16 +0200 Subject: [PATCH 06/95] feat: access log middleware --- package.json | 2 +- src/gateway/accessLogMiddleware.ts | 26 ++++++++++++++++++++++++++ src/gateway/init.ts | 6 ++++++ yarn.lock | 10 +++++----- 4 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 src/gateway/accessLogMiddleware.ts diff --git a/package.json b/package.json index e91b4772..46e61160 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "arweave": "1.11.8", "axios": "^0.26.1", "bluebird": "^3.7.2", + "date-fns": "^2.29.3", "dotenv": "16.0.3", "elliptic": "^6.5.4", "ethers": "^5.7.2", @@ -46,7 +47,6 @@ "prom-client": "12", "raw-body": "^2.5.1", "undici": "5.14.0", - "uuid": "^9.0.0", "warp-contracts": "1.2.48", "warp-contracts-pubsub": "^1.0.3", "warp-contracts-subscription-plugin": "1.0.4", diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts new file mode 100644 index 00000000..d79bc598 --- /dev/null +++ b/src/gateway/accessLogMiddleware.ts @@ -0,0 +1,26 @@ +import * as util from "util"; +import {format} from 'date-fns' +import {DefaultState, Next, ParameterizedContext} from "koa"; +import {GatewayContext} from "./init"; + +const LOG_FORMAT = '%s - - [%s] "%s %s HTTP/%s" %d %s\n'; +const DATE_FORMAT = 'd/MMM/yyyy:HH:mm:ss xx'; + +export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { + await next(); + try { + ctx.accessLogger.debug(util.format( + LOG_FORMAT, + ctx.ip, + format(new Date(), DATE_FORMAT), + ctx.method, + ctx.path, + ctx.req.httpVersion, + ctx.status, + ctx.length ? ctx.length.toString() : '-' + ) + ); + } catch (err: any) { + console.error(err); + } +} \ No newline at end of file diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 4e31d62b..b5a9b12d 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -20,6 +20,7 @@ import {initPubSub} from 'warp-contracts-pubsub'; // @ts-ignore import {EvmSignatureVerificationServerPlugin} from 'warp-signature/server'; import {DatabaseSource} from '../db/databaseSource'; +import {accessLogMiddleware} from "./accessLogMiddleware"; const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; @@ -37,6 +38,7 @@ export interface GatewayContext { dbSource: DatabaseSource; logger: WarpLogger; sLogger: WarpLogger; + accessLogger: WarpLogger; arweave: Arweave; bundlr: Bundlr; jwk: JWKInterface; @@ -77,8 +79,10 @@ export interface GatewayContext { LoggerFactory.INST.logLevel('info', 'gateway'); LoggerFactory.INST.logLevel('debug', 'sequencer'); LoggerFactory.INST.logLevel('debug', 'LastTxSync'); + LoggerFactory.INST.logLevel('debug', 'access'); const logger = LoggerFactory.INST.create('gateway'); const sLogger = LoggerFactory.INST.create('sequencer'); + const accessLogger = LoggerFactory.INST.create('access'); logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode. noSync = ${noSync}`); @@ -104,6 +108,7 @@ export interface GatewayContext { app.context.dbSource = dbSource; app.context.logger = logger; app.context.sLogger = sLogger; + app.context.accessLogger = accessLogger; app.context.arweave = arweave; app.context.bundlr = bundlr; app.context.jwk = jwk; @@ -121,6 +126,7 @@ export interface GatewayContext { app.context.appSync = appSync; app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); + app.use(accessLogMiddleware); app.use( cors({ async origin() { diff --git a/yarn.lock b/yarn.lock index 112a755c..1f7586bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3537,6 +3537,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@^2.29.3: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + dayjs@~1.11.5: version "1.11.7" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" @@ -7727,11 +7732,6 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== - uzip-module@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/uzip-module/-/uzip-module-1.0.3.tgz#6bbabe2a3efea5d5a4a47479f523a571de3427ce" From 95d622b70d27d31f6d3063fb6750907d6779b12e Mon Sep 17 00:00:00 2001 From: ppe Date: Sun, 26 Mar 2023 13:34:37 +0200 Subject: [PATCH 07/95] feat: alive route --- src/gateway/accessLogMiddleware.ts | 2 +- src/gateway/router/gatewayRouter.ts | 4 ++-- src/gateway/router/routes/gcpAliveRoute.ts | 5 +++++ src/gateway/router/routes/gcpRoute.ts | 5 ----- 4 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 src/gateway/router/routes/gcpAliveRoute.ts delete mode 100644 src/gateway/router/routes/gcpRoute.ts diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts index d79bc598..26c08b6d 100644 --- a/src/gateway/accessLogMiddleware.ts +++ b/src/gateway/accessLogMiddleware.ts @@ -3,7 +3,7 @@ import {format} from 'date-fns' import {DefaultState, Next, ParameterizedContext} from "koa"; import {GatewayContext} from "./init"; -const LOG_FORMAT = '%s - - [%s] "%s %s HTTP/%s" %d %s\n'; +const LOG_FORMAT = '%s [%s] "%s %s HTTP/%s" %d %s'; const DATE_FORMAT = 'd/MMM/yyyy:HH:mm:ss xx'; export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 196521de..d313d733 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -28,7 +28,7 @@ import { deploySourceRoute_v2 } from './routes/deploySourceRoute_v2'; import { deployContractRoute_v2 } from './routes/deployContractRoute_v2'; import { registerContractRoute } from './routes/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; -import {gcpRoute} from "./routes/gcpRoute"; +import {gcpAliveRoute} from "./routes/gcpAliveRoute"; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -59,7 +59,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/contract-source', contractSourceRoute); router.get('/contracts-by-source', contractsBySourceRoute); router.get('/creator', creatorRoute); - router.get('/gcp/test', gcpRoute); + router.get('/gcp/alive', gcpAliveRoute); // post if (!replica) { diff --git a/src/gateway/router/routes/gcpAliveRoute.ts b/src/gateway/router/routes/gcpAliveRoute.ts new file mode 100644 index 00000000..6df87eab --- /dev/null +++ b/src/gateway/router/routes/gcpAliveRoute.ts @@ -0,0 +1,5 @@ +import Router from '@koa/router'; + +export async function gcpAliveRoute(ctx: Router.RouterContext) { + ctx.body = 'ok'; +} diff --git a/src/gateway/router/routes/gcpRoute.ts b/src/gateway/router/routes/gcpRoute.ts deleted file mode 100644 index f0861849..00000000 --- a/src/gateway/router/routes/gcpRoute.ts +++ /dev/null @@ -1,5 +0,0 @@ -import Router from '@koa/router'; - -export async function gcpRoute(ctx: Router.RouterContext) { - ctx.body = 'hello from gcp'; -} From 803930fca2c9a82d44e946119dff9607c87980d5 Mon Sep 17 00:00:00 2001 From: ppe Date: Sun, 26 Mar 2023 13:45:29 +0200 Subject: [PATCH 08/95] fix: don't log health checks... --- package.json | 2 -- src/gateway/accessLogMiddleware.ts | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 46e61160..4bbef3a8 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,6 @@ "arbundles": "^0.7.0", "arweave": "1.11.8", "axios": "^0.26.1", - "bluebird": "^3.7.2", - "date-fns": "^2.29.3", "dotenv": "16.0.3", "elliptic": "^6.5.4", "ethers": "^5.7.2", diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts index 26c08b6d..0049854c 100644 --- a/src/gateway/accessLogMiddleware.ts +++ b/src/gateway/accessLogMiddleware.ts @@ -1,18 +1,18 @@ import * as util from "util"; -import {format} from 'date-fns' import {DefaultState, Next, ParameterizedContext} from "koa"; import {GatewayContext} from "./init"; -const LOG_FORMAT = '%s [%s] "%s %s HTTP/%s" %d %s'; -const DATE_FORMAT = 'd/MMM/yyyy:HH:mm:ss xx'; +const LOG_FORMAT = '%s "%s %s HTTP/%s" %d %s'; export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { await next(); try { + if (ctx.path == '/gateway/gcp/alive') { + return; + } ctx.accessLogger.debug(util.format( LOG_FORMAT, ctx.ip, - format(new Date(), DATE_FORMAT), ctx.method, ctx.path, ctx.req.httpVersion, From 1c4031f2b8533b0c74cf1814af4d731ffc0d62a4 Mon Sep 17 00:00:00 2001 From: ppe Date: Mon, 27 Mar 2023 13:32:55 +0200 Subject: [PATCH 09/95] restore original lock timeout --- src/gateway/LastTxSyncer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/LastTxSyncer.ts b/src/gateway/LastTxSyncer.ts index 4802c347..5bf0a713 100644 --- a/src/gateway/LastTxSyncer.ts +++ b/src/gateway/LastTxSyncer.ts @@ -15,7 +15,7 @@ export class LastTxSync { // https://stackoverflow.com/a/20963803 - await trx.raw(`SET LOCAL lock_timeout = '2s';`) + await trx.raw(`SET LOCAL lock_timeout = '5s';`) const benchmark = Benchmark.measure(); await trx.raw(` SELECT pg_advisory_xact_lock(?, ?); From 96870d94597b6c985323a24b87a797b841c409e7 Mon Sep 17 00:00:00 2001 From: ppe Date: Mon, 27 Mar 2023 16:05:28 +0200 Subject: [PATCH 10/95] fix: sortKey-lastSortKey sanity chceck --- src/gateway/router/routes/sequencerRoute.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 2320416c..2d583db3 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -79,10 +79,14 @@ export async function sequencerRoute(ctx: Router.RouterContext) { arweave ); + // note: contractLastSortKey will be null for the very first interaction with a given contract const contractLastSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); const millis = Date.now(); const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, transaction.id, currentHeight); + if (contractLastSortKey !== null && sortKey.localeCompare(contractLastSortKey) <= 0) { + throw new Error('New sortKey <= lastSortKey!'); + } tags.push({ name: 'Sequencer-Mills', value: '' + millis }); tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); From 4a2b399e52230d696a1c2bf6d28c0fa3baacfa6e Mon Sep 17 00:00:00 2001 From: ppe Date: Tue, 28 Mar 2023 15:28:08 +0200 Subject: [PATCH 11/95] cache network info --- src/gateway/router/routes/sequencerRoute.ts | 2 +- src/gateway/tasks/networkInfoCache.ts | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 2d583db3..1ffcdbef 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -85,7 +85,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { const millis = Date.now(); const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, transaction.id, currentHeight); if (contractLastSortKey !== null && sortKey.localeCompare(contractLastSortKey) <= 0) { - throw new Error('New sortKey <= lastSortKey!'); + throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractLastSortKey})!`); } tags.push({ name: 'Sequencer-Mills', value: '' + millis }); diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index af63d17c..8f03aa83 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -4,7 +4,6 @@ import { GatewayContext } from '../init'; import { TaskRunner } from './TaskRunner'; import { BLOCKS_INTERVAL_MS } from './syncTransactions'; import fs from 'fs'; -import { fetch } from 'undici'; export type NetworkCacheType = { cachedNetworkInfo: NetworkInfoInterface; @@ -14,17 +13,11 @@ export type NetworkCacheType = { let cache: NetworkCacheType; export async function runNetworkInfoCacheTask(context: GatewayContext) { - const { arweave, logger } = context; + const { arweave, logger, arweaveWrapper } = context; async function updateNetworkInfo() { try { - const newNetworkInfoResponse = await fetch("https://gateway.warp.cc/gateway/arweave/info"); - if (!newNetworkInfoResponse.ok) { - const message = `An error has occured: ${newNetworkInfoResponse.status}`; - throw new Error(message); - } - const newNetworkInfo = (await newNetworkInfoResponse.json()) as NetworkInfoInterface; - + const newNetworkInfo = await arweaveWrapper.info(); if (cache?.cachedNetworkInfo && newNetworkInfo && newNetworkInfo.height < cache.cachedNetworkInfo.height) { logger.warn('New network height lower than current, skipping.', { currentHeight: cache?.cachedNetworkInfo.height, @@ -44,7 +37,7 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { cachedBlockInfo, }; - // fs.writeFileSync('network-cache.json', JSON.stringify(cache), 'utf-8'); + fs.writeFileSync('network-cache.json', JSON.stringify(cache), 'utf-8'); logger.debug('New network height', cache.cachedNetworkInfo.height); } catch (e) { logger.error('Error while loading network info', e); @@ -68,5 +61,5 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { } export function getCachedNetworkData(): NetworkCacheType { - return cache; + return JSON.parse(fs.readFileSync('network-cache.json', 'utf-8')); } From 7142b52f331af4baaf473e4a420e0118f2f29718 Mon Sep 17 00:00:00 2001 From: ppe Date: Tue, 28 Mar 2023 15:33:22 +0200 Subject: [PATCH 12/95] network info check fix --- src/gateway/tasks/networkInfoCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index 8f03aa83..9ed0d362 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -18,8 +18,8 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { async function updateNetworkInfo() { try { const newNetworkInfo = await arweaveWrapper.info(); - if (cache?.cachedNetworkInfo && newNetworkInfo && newNetworkInfo.height < cache.cachedNetworkInfo.height) { - logger.warn('New network height lower than current, skipping.', { + if (cache?.cachedNetworkInfo && newNetworkInfo && newNetworkInfo.height <= cache.cachedNetworkInfo.height) { + logger.warn('New network height lower or equal than current, skipping.', { currentHeight: cache?.cachedNetworkInfo.height, newHeight: newNetworkInfo.height, }); From 52d92ad763dbd69b624bac5d243426d58816fea4 Mon Sep 17 00:00:00 2001 From: ppe Date: Wed, 12 Apr 2023 11:59:00 +0200 Subject: [PATCH 13/95] stop loggin' shit --- src/gateway/tasks/networkInfoCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index 9ed0d362..8674e4a7 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -19,7 +19,7 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { try { const newNetworkInfo = await arweaveWrapper.info(); if (cache?.cachedNetworkInfo && newNetworkInfo && newNetworkInfo.height <= cache.cachedNetworkInfo.height) { - logger.warn('New network height lower or equal than current, skipping.', { + logger.debug('New network height lower or equal than current, skipping.', { currentHeight: cache?.cachedNetworkInfo.height, newHeight: newNetworkInfo.height, }); From 62d030cabd21ba2963012c57a6a219cbefd82d66 Mon Sep 17 00:00:00 2001 From: ppe Date: Fri, 7 Apr 2023 21:43:41 +0200 Subject: [PATCH 14/95] feat: errors handling middleware --- package.json | 8 +- src/db/insertInterfaces.ts | 2 +- src/gateway/accessLogMiddleware.ts | 7 +- src/gateway/errorHandlerMiddleware.ts | 41 + src/gateway/init.ts | 80 +- src/gateway/publisher.ts | 2 +- src/gateway/router/gatewayRouter.ts | 45 +- src/gateway/router/routes/arweaveInfoRoute.ts | 9 +- .../router/routes/contractDataRoute.ts | 109 --- src/gateway/router/routes/contractRoute.ts | 55 -- .../router/routes/contractSourceRoute.ts | 49 -- .../router/routes/contractWithSourceRoute.ts | 65 -- .../routes/contractWithSourceRoute_v2.ts | 72 -- .../routes/contracts/contractDataRoute.ts | 100 +++ .../router/routes/contracts/contractRoute.ts | 48 + .../routes/contracts/contractSourceRoute.ts | 40 + .../contracts/contractWithSourceRoute.ts | 54 ++ .../contracts/contractWithSourceRoute_v2.ts | 65 ++ .../{ => contracts}/contractsBySourceRoute.ts | 47 +- .../router/routes/contracts/contractsRoute.ts | 69 ++ src/gateway/router/routes/contractsRoute.ts | 75 -- src/gateway/router/routes/creatorRoute.ts | 90 +- src/gateway/router/routes/dashboardRoute.ts | 126 ++- .../routes/{ => deploy}/deployBundledRoute.ts | 71 +- .../{ => deploy}/deployContractRoute.ts | 18 +- .../{ => deploy}/deployContractRoute_v2.ts | 52 +- .../routes/{ => deploy}/deploySourceRoute.ts | 12 +- .../{ => deploy}/deploySourceRoute_v2.ts | 44 +- .../{ => deploy}/registerContractRoute.ts | 85 +- src/gateway/router/routes/interactionRoute.ts | 43 - .../routes/interactions/interactionRoute.ts | 37 + .../routes/interactions/interactionsRoute.ts | 110 +++ .../routes/interactions/interactionsSonar.ts | 102 +++ .../interactions/interactionsSortKeyRoute.ts | 115 +++ .../interactionsSortKeyRoute_v2.ts | 116 +++ .../interactionsStreamRoute.ts | 42 +- .../routes/interactionsContractGroupsRoute.ts | 172 ---- .../router/routes/interactionsRoute.ts | 120 --- .../router/routes/interactionsSonar.ts | 110 --- .../router/routes/interactionsSortKeyRoute.ts | 124 --- .../routes/interactionsSortKeyRoute_v2.ts | 122 --- .../router/routes/nftsOwnedByAddressRoute.ts | 47 +- .../router/routes/safeContractsRoute.ts | 31 - src/gateway/router/routes/searchRoute.ts | 28 +- src/gateway/router/routes/sequencerRoute.ts | 21 +- .../router/routes/stats/totalTxsRoute.ts | 47 +- .../router/routes/stats/txsPerDayRoute.ts | 64 +- src/gateway/runGatewayTasks.ts | 1 - yarn.lock | 817 +----------------- 49 files changed, 1376 insertions(+), 2433 deletions(-) create mode 100644 src/gateway/errorHandlerMiddleware.ts delete mode 100644 src/gateway/router/routes/contractDataRoute.ts delete mode 100644 src/gateway/router/routes/contractRoute.ts delete mode 100644 src/gateway/router/routes/contractSourceRoute.ts delete mode 100644 src/gateway/router/routes/contractWithSourceRoute.ts delete mode 100644 src/gateway/router/routes/contractWithSourceRoute_v2.ts create mode 100644 src/gateway/router/routes/contracts/contractDataRoute.ts create mode 100644 src/gateway/router/routes/contracts/contractRoute.ts create mode 100644 src/gateway/router/routes/contracts/contractSourceRoute.ts create mode 100644 src/gateway/router/routes/contracts/contractWithSourceRoute.ts create mode 100644 src/gateway/router/routes/contracts/contractWithSourceRoute_v2.ts rename src/gateway/router/routes/{ => contracts}/contractsBySourceRoute.ts (71%) create mode 100644 src/gateway/router/routes/contracts/contractsRoute.ts delete mode 100644 src/gateway/router/routes/contractsRoute.ts rename src/gateway/router/routes/{ => deploy}/deployBundledRoute.ts (63%) rename src/gateway/router/routes/{ => deploy}/deployContractRoute.ts (93%) rename src/gateway/router/routes/{ => deploy}/deployContractRoute_v2.ts (83%) rename src/gateway/router/routes/{ => deploy}/deploySourceRoute.ts (87%) rename src/gateway/router/routes/{ => deploy}/deploySourceRoute_v2.ts (65%) rename src/gateway/router/routes/{ => deploy}/registerContractRoute.ts (67%) delete mode 100644 src/gateway/router/routes/interactionRoute.ts create mode 100644 src/gateway/router/routes/interactions/interactionRoute.ts create mode 100644 src/gateway/router/routes/interactions/interactionsRoute.ts create mode 100644 src/gateway/router/routes/interactions/interactionsSonar.ts create mode 100644 src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts create mode 100644 src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts rename src/gateway/router/routes/{ => interactions}/interactionsStreamRoute.ts (50%) delete mode 100644 src/gateway/router/routes/interactionsContractGroupsRoute.ts delete mode 100644 src/gateway/router/routes/interactionsRoute.ts delete mode 100644 src/gateway/router/routes/interactionsSonar.ts delete mode 100644 src/gateway/router/routes/interactionsSortKeyRoute.ts delete mode 100644 src/gateway/router/routes/interactionsSortKeyRoute_v2.ts delete mode 100644 src/gateway/router/routes/safeContractsRoute.ts diff --git a/package.json b/package.json index 4bbef3a8..605cfb66 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "start:local": "node dist/gateway/init.js --env_path .secrets/local.env --local", "start:local:replica": "node dist/gateway/init.js --env_path .secrets/local.env --replica --local", "start:local:testnet": "node dist/gateway/init.js --env_path .secrets/local-testnet.env --local", + "start:local:noSync": "node dist/gateway/init.js --env_path .secrets/local.env --local --noSync", "start:prod:testnet": "node dist/gateway/init.js --env_path .secrets/prod-testnet.env", "format": "prettier --write .", "test": "jest", @@ -35,16 +36,15 @@ "ioredis": "^5.2.4", "knex": "2.4.2", "koa": "2.14.1", - "koa-bodyparser": "4.3.0", + "koa-bodyparser": "4.4.0", "koa-compress": "5.1.0", "nodemailer": "^6.9.1", "parse-json-stream": "^2.4.0", "pg": "8.10.0", "pg-query-stream": "^4.2.3", - "pm2": "^5.3.0", - "prom-client": "12", "raw-body": "^2.5.1", - "undici": "5.14.0", + "undici": "5.21.0", + "uuid": "^9.0.0", "warp-contracts": "1.2.48", "warp-contracts-pubsub": "^1.0.3", "warp-contracts-subscription-plugin": "1.0.4", diff --git a/src/db/insertInterfaces.ts b/src/db/insertInterfaces.ts index 5fbaab90..021e1f72 100644 --- a/src/db/insertInterfaces.ts +++ b/src/db/insertInterfaces.ts @@ -1,5 +1,5 @@ import { GQLTagInterface, Tags } from 'warp-contracts'; -import { WarpDeployment } from '../gateway/router/routes/deployContractRoute'; +import { WarpDeployment } from '../gateway/router/routes/deploy/deployContractRoute'; export interface SequencerInsert { original_sig: string; diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts index 0049854c..f47cc6e7 100644 --- a/src/gateway/accessLogMiddleware.ts +++ b/src/gateway/accessLogMiddleware.ts @@ -1,10 +1,12 @@ import * as util from "util"; +import { v4 as uuidv4 } from 'uuid'; import {DefaultState, Next, ParameterizedContext} from "koa"; import {GatewayContext} from "./init"; -const LOG_FORMAT = '%s "%s %s HTTP/%s" %d %s'; +const LOG_FORMAT = '%s %s "%s %s HTTP/%s" %d %s'; export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { + ctx.state.requestId = uuidv4(); await next(); try { if (ctx.path == '/gateway/gcp/alive') { @@ -12,6 +14,7 @@ export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { + try { + await next(); + } catch (err: any) { + if (err.name == 'GatewayError') { + ctx.status = err.status; + ctx.message = `[${ctx.state.requestId}]: ${err.message}`; + if (err.log) { + ctx.logger.error(util.format( + ERROR_LOG_FORMAT, + ctx.state.requestId, + `${ctx.path}${ctx.querystring}`, + err.message, + err.properties ? JSON.stringify(err.properties): '' + ), err); + } + } else { + ctx.status = 500; + ctx.message = `Unknown gateway error ${err?.message || err}`; + ctx.logger.error(util.format( + ERROR_LOG_FORMAT, + ctx.state.requestId, + `${ctx.path}${ctx.querystring}`, + err.message || err + ), err); + } + } +} diff --git a/src/gateway/init.ts b/src/gateway/init.ts index b5a9b12d..99ca0b0b 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -21,6 +21,7 @@ import {initPubSub} from 'warp-contracts-pubsub'; import {EvmSignatureVerificationServerPlugin} from 'warp-signature/server'; import {DatabaseSource} from '../db/databaseSource'; import {accessLogMiddleware} from "./accessLogMiddleware"; +import {errorHandlerMiddleware} from "./errorHandlerMiddleware"; const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; @@ -93,7 +94,7 @@ export interface GatewayContext { { client: 'pg', url: process.env.DB_URL_GCP as string, - ssl: { + ssl: localEnv ? undefined : { rejectUnauthorized: false, ca: fs.readFileSync('.secrets/ca.pem'), cert: fs.readFileSync('.secrets/cert.pem'), @@ -126,7 +127,9 @@ export interface GatewayContext { app.context.appSync = appSync; app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); + app.use(errorHandlerMiddleware); app.use(accessLogMiddleware); + app.use( cors({ async origin() { @@ -162,46 +165,47 @@ export interface GatewayContext { logger.info('vrf', app.context.vrf); - const connectionOptions = readGwPubSubConfig('gw-pubsub.json'); - logger.info('Redis connection options', connectionOptions); - if (connectionOptions) { - const publisher = new Redis(connectionOptions); - await publisher.connect(); - logger.info(`Publisher status`, { - host: connectionOptions.host, - status: publisher.status, - }); - app.context.publisher = publisher; - } + if (!localEnv) { + const connectionOptions = readGwPubSubConfig('gw-pubsub.json'); + logger.info('Redis connection options', connectionOptions); + if (connectionOptions) { + const publisher = new Redis(connectionOptions); + await publisher.connect(); + logger.info(`Publisher status`, { + host: connectionOptions.host, + status: publisher.status, + }); + app.context.publisher = publisher; + } - // temporary.. - const connectionOptions2 = readGwPubSubConfig('gw-pubsub_2.json'); - if (connectionOptions2) { - console.log({ - ...connectionOptions2, - tls: { - ca: [process.env.GW_TLS_CA_CERT], - checkServerIdentity: () => { - return null; + // temporary.. + const connectionOptions2 = readGwPubSubConfig('gw-pubsub_2.json'); + if (connectionOptions2) { + console.log({ + ...connectionOptions2, + tls: { + ca: [process.env.GW_TLS_CA_CERT], + checkServerIdentity: () => { + return null; + }, }, - }, - }); - - const publisher2 = new Redis({ - ...connectionOptions2, - tls: { - ca: [process.env.GW_TLS_CA_CERT], - checkServerIdentity: () => { - return null; + }); + const publisher2 = new Redis({ + ...connectionOptions2, + tls: { + ca: [process.env.GW_TLS_CA_CERT], + checkServerIdentity: () => { + return null; + }, }, - }, - }); - await publisher2.connect(); - logger.info(`Publisher 2 status`, { - host: connectionOptions2.host, - status: publisher2.status, - }); - app.context.publisher_v2 = publisher2; + }); + await publisher2.connect(); + logger.info(`Publisher 2 status`, { + host: connectionOptions2.host, + status: publisher2.status, + }); + app.context.publisher_v2 = publisher2; + } } if (!fs.existsSync('gateway.lock')) { diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index 65f49802..72694bce 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -61,7 +61,7 @@ export function publishInteraction( ) { const { logger, appSync } = ctx; - if (!appSync) { + if (!appSync || ctx.localEnv) { logger.warn('App sync key not set'); return; } diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index d313d733..cf54597e 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -1,32 +1,30 @@ import Router from '@koa/router'; -import { contractsRoute } from './routes/contractsRoute'; -import { interactionsRoute } from './routes/interactionsRoute'; +import { contractsRoute } from './routes/contracts/contractsRoute'; +import { interactionsRoute } from './routes/interactions/interactionsRoute'; import { searchRoute } from './routes/searchRoute'; import { totalTxsRoute } from './routes/stats/totalTxsRoute'; -import { contractRoute } from './routes/contractRoute'; -import { contractWithSourceRoute } from './routes/contractWithSourceRoute'; -import { contractWithSourceRoute_v2 } from './routes/contractWithSourceRoute_v2'; -import { interactionRoute } from './routes/interactionRoute'; -import { safeContractsRoute } from './routes/safeContractsRoute'; +import { contractRoute } from './routes/contracts/contractRoute'; +import { contractWithSourceRoute } from './routes/contracts/contractWithSourceRoute'; +import { contractWithSourceRoute_v2 } from './routes/contracts/contractWithSourceRoute_v2'; +import { interactionRoute } from './routes/interactions/interactionRoute'; import { sequencerRoute } from './routes/sequencerRoute'; -import { interactionsStreamRoute } from './routes/interactionsStreamRoute'; -import { deployContractRoute } from './routes/deployContractRoute'; +import { interactionsStreamRoute } from './routes/interactions/interactionsStreamRoute'; +import { deployContractRoute } from './routes/deploy/deployContractRoute'; import { arweaveBlockRoute, arweaveInfoRoute } from './routes/arweaveInfoRoute'; -import { interactionsSortKeyRoute } from './routes/interactionsSortKeyRoute'; -import { contractDataRoute } from './routes/contractDataRoute'; +import { interactionsSortKeyRoute } from './routes/interactions/interactionsSortKeyRoute'; +import { contractDataRoute } from './routes/contracts/contractDataRoute'; import { nftsOwnedByAddressRoute } from './routes/nftsOwnedByAddressRoute'; import { txsPerDayRoute } from './routes/stats/txsPerDayRoute'; -import { interactionsContractGroupsRoute } from './routes/interactionsContractGroupsRoute'; -import { interactionsSortKeyRoute_v2 } from './routes/interactionsSortKeyRoute_v2'; -import { contractSourceRoute } from './routes/contractSourceRoute'; -import { contractsBySourceRoute } from './routes/contractsBySourceRoute'; +import { interactionsSortKeyRoute_v2 } from './routes/interactions/interactionsSortKeyRoute_v2'; +import { contractSourceRoute } from './routes/contracts/contractSourceRoute'; +import { contractsBySourceRoute } from './routes/contracts/contractsBySourceRoute'; import { creatorRoute } from './routes/creatorRoute'; -import { interactionsSonar } from './routes/interactionsSonar'; -import { deployBundledRoute } from './routes/deployBundledRoute'; -import { deploySourceRoute } from './routes/deploySourceRoute'; -import { deploySourceRoute_v2 } from './routes/deploySourceRoute_v2'; -import { deployContractRoute_v2 } from './routes/deployContractRoute_v2'; -import { registerContractRoute } from './routes/registerContractRoute'; +import { interactionsSonar } from './routes/interactions/interactionsSonar'; +import { deployBundledRoute } from './routes/deploy/deployBundledRoute'; +import { deploySourceRoute } from './routes/deploy/deploySourceRoute'; +import { deploySourceRoute_v2 } from './routes/deploy/deploySourceRoute_v2'; +import { deployContractRoute_v2 } from './routes/deploy/deployContractRoute_v2'; +import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; import {gcpAliveRoute} from "./routes/gcpAliveRoute"; @@ -38,7 +36,6 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/v2/contract', contractWithSourceRoute_v2); router.get('/contract-data/:id', contractDataRoute); router.get('/contracts/:id', contractRoute); - router.get('/contracts-safe', safeContractsRoute); router.get('/dashboard', dashboardRoute); router.get('/search/:phrase', searchRoute); router.get('/nft/owner/:address', nftsOwnedByAddressRoute); @@ -50,7 +47,6 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/interactions-sort-key', interactionsSortKeyRoute); router.get('/v2/interactions-sort-key', interactionsSortKeyRoute_v2); router.get('/interactions-stream', interactionsStreamRoute); - router.get('/interactions-contract-groups', interactionsContractGroupsRoute); router.get('/interactions/:id', interactionRoute); router.get('/stats', totalTxsRoute); router.get('/stats/per-day', txsPerDayRoute); @@ -63,9 +59,10 @@ const gatewayRouter = (replica: boolean): Router => { // post if (!replica) { + router.post('/sequencer/register', sequencerRoute); + router.post('/contracts/deploy', deployContractRoute); router.post('/contracts/deploy-bundled', deployBundledRoute); - router.post('/sequencer/register', sequencerRoute); router.post('/sources/deploy', deploySourceRoute); router.post('/v2/sources/deploy', deploySourceRoute_v2); router.post('/v2/contracts/deploy', deployContractRoute_v2); diff --git a/src/gateway/router/routes/arweaveInfoRoute.ts b/src/gateway/router/routes/arweaveInfoRoute.ts index d132fbaf..6171995d 100644 --- a/src/gateway/router/routes/arweaveInfoRoute.ts +++ b/src/gateway/router/routes/arweaveInfoRoute.ts @@ -1,14 +1,13 @@ import Router from '@koa/router'; import { getCachedNetworkData } from '../../tasks/networkInfoCache'; +import {GatewayError} from "../../errorHandlerMiddleware"; export async function arweaveInfoRoute(ctx: Router.RouterContext) { const { logger } = ctx; const result = getCachedNetworkData().cachedNetworkInfo; if (result == null) { - logger.error('Network info not yet available.'); - ctx.status = 500; - ctx.body = { message: 'Network info not yet available.' }; + throw new GatewayError('Network info not yet available.') } else { logger.debug('Returning network info with height', result.height); ctx.body = { @@ -22,9 +21,7 @@ export async function arweaveBlockRoute(ctx: Router.RouterContext) { const result = getCachedNetworkData().cachedBlockInfo; if (result == null) { - logger.error('Block info not yet available.'); - ctx.status = 500; - ctx.body = { message: 'Block info not yet available.' }; + throw new GatewayError('Block info not yet available.'); } else { logger.debug('Returning block info with block height', result.height); ctx.body = { diff --git a/src/gateway/router/routes/contractDataRoute.ts b/src/gateway/router/routes/contractDataRoute.ts deleted file mode 100644 index 34236fc7..00000000 --- a/src/gateway/router/routes/contractDataRoute.ts +++ /dev/null @@ -1,109 +0,0 @@ -import Router from '@koa/router'; -import Arweave from 'arweave'; -import { ArweaveWrapper, Benchmark, Tags, WarpLogger } from 'warp-contracts'; -import { decodeTags, getTagByName, isTxIdValid } from '../../../utils'; -import Transaction from 'arweave/node/lib/transaction'; -import { BUNDLR_NODE1_URL } from '../../../constants'; -import { WarpDeployment } from './deployContractRoute'; - -export async function contractDataRoute(ctx: Router.RouterContext) { - const { logger, dbSource, arweave, arweaveWrapper } = ctx; - - const { id } = ctx.params; - - if (!isTxIdValid(id as string)) { - logger.error('Incorrect contract transaction id.'); - ctx.status = 500; - ctx.body = { message: 'Incorrect contract transaction id.' }; - return; - } - - try { - const benchmark = Benchmark.measure(); - logger.debug('ContractDataRoute id: ', id); - - const result: any = await dbSource.raw( - ` - SELECT bundler_contract_tx_id as "bundlerContractTxId", - contract_tx -> 'tags' as "contractTags", - deployment_type as "deploymentType", - bundler_contract_node as "bundlrContractNode" - FROM contracts - WHERE contract_id = ?; - `, - [id] - ); - if (result?.rows[0] == null || result?.rows[0].bundlerContractTxId == null) { - ctx.status = 500; - ctx.body = { message: 'Contract not indexed as bundled.' }; - } else { - let tags: Tags = []; - if (result?.rows[0].contractTags) { - tags = decodeTags(result?.rows[0].contractTags); - } - - const { data, contentType } = await getContractData( - arweave, - logger, - result?.rows[0].bundlerContractTxId, - tags, - arweaveWrapper, - result?.rows[0].deploymentType, - result.rows[0].bundlrContractNode - ); - ctx.body = data; - ctx.set('Content-Type', contentType); - logger.debug('Contract data loaded in', benchmark.elapsed()); - } - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} - -async function getContractData( - arweave: Arweave, - logger: WarpLogger, - id: string, - tags: { name: string; value: string }[], - arweaveWrapper: ArweaveWrapper, - deploymentType: string, - bundlrContractNode: string -) { - let data: ArrayBuffer | Buffer; - - try { - data = await arweaveWrapper.txData(id); - } catch (e) { - logger.error(`Error from Arweave Gateway while loading data: `, e); - - data = await fetch(`${bundlrContractNode}/tx/${id}/data`).then((res) => { - return res.arrayBuffer(); - }); - } - const strData = arweave.utils.bufferToString(data); - - logger.debug('strData', strData); - - if (deploymentType == WarpDeployment.External) { - const contentType = getTagByName(tags, 'Content-Type'); - logger.debug(`Content type for id: ${id}: `, contentType); - return { data: strData, contentType }; - } else { - const tx = new Transaction({ ...JSON.parse(strData) }); - const txData = Buffer.from(tx.data); - const contentType = getContentTypeFromTx(tx); - logger.debug(`Content type for id: ${id}: `, contentType); - return { data: txData, contentType }; - } -} - -function getContentTypeFromTx(tx: Transaction) { - const tagContentType = tx - .get('tags') - // @ts-ignore - .find((tag: BaseObject) => tag.get('name', { decode: true, string: true }) == 'Content-Type'); - - return tagContentType.get('value', { decode: true, string: true }); -} diff --git a/src/gateway/router/routes/contractRoute.ts b/src/gateway/router/routes/contractRoute.ts deleted file mode 100644 index 48bf9ae2..00000000 --- a/src/gateway/router/routes/contractRoute.ts +++ /dev/null @@ -1,55 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -/** - * @deprecated Following route has been replaced with `contractWithSourceRoute` and is not used in the SDK - * anymore. It should be deleted in the future, leaving due to backwards compatibility of the introduction of - * the new endpoint. - */ - -export async function contractRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { id } = ctx.params; - - if (id?.length != 43) { - ctx.body = {}; - return; - } - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT c.contract_id as "txId", - c.src_tx_id as "srcTxId", - (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, - (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", - c.init_state as "initState", - c.owner as "owner", - c.pst_ticker as "pstTicker", - c.pst_name as "pstName", - s.src_wasm_lang as "srcWasmLang", - c.contract_tx as "contractTx", - s.src_tx as "srcTx", - c.testnet as "testnet" - FROM contracts c - JOIN contracts_src s on c.src_tx_id = s.src_tx_id - WHERE contract_id = ?; - `, - [id] - ); - - if (result?.rows[0].src == null && result?.rows[0].srcBinary == null) { - ctx.status = 500; - ctx.body = { message: 'Contract not properly indexed.' }; - } else { - ctx.body = result?.rows[0]; - logger.debug('Contract data loaded in', benchmark.elapsed()); - } - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/contractSourceRoute.ts b/src/gateway/router/routes/contractSourceRoute.ts deleted file mode 100644 index f66e7339..00000000 --- a/src/gateway/router/routes/contractSourceRoute.ts +++ /dev/null @@ -1,49 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; -import { isTxIdValid } from '../../../utils'; - -export async function contractSourceRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { id } = ctx.query; - - if (!isTxIdValid(id as string)) { - logger.error('Incorrect contract source transaction id.'); - ctx.status = 500; - ctx.body = { message: 'Incorrect contract source transaction id.' }; - return; - } - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT s.src_tx_id as "srcTxId", - (case when not s.owner = 'error' then s.owner else null end) as "owner", - s.src_content_type as "srcContentType", - (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, - (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", - s.src_wasm_lang as "srcWasmLang", - s.bundler_src_tx_id as "bundlerSrcTxId", - s.src_tx as "srcTx" - FROM contracts_src s - WHERE src_tx_id = ? AND src IS DISTINCT FROM 'error'; - `, - [id] - ); - - if (!result?.rows[0]) { - ctx.status = 500; - ctx.body = { message: 'Could not load contract source.' }; - logger.error('Could not load contract source.'); - } else { - ctx.body = result?.rows[0]; - } - - logger.debug('Source loaded in', benchmark.elapsed()); - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/contractWithSourceRoute.ts b/src/gateway/router/routes/contractWithSourceRoute.ts deleted file mode 100644 index e05a68a9..00000000 --- a/src/gateway/router/routes/contractWithSourceRoute.ts +++ /dev/null @@ -1,65 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; -import { isTxIdValid } from '../../../utils'; - -export async function contractWithSourceRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { txId, srcTxId } = ctx.query; - - if (!isTxIdValid(txId as string)) { - logger.error('Incorrect contract transaction id.'); - ctx.status = 500; - ctx.body = { message: 'Incorrect contract transaction id.' }; - return; - } - - if (srcTxId && !isTxIdValid(srcTxId as string)) { - logger.error('Incorrect contract source transaction id.'); - ctx.status = 500; - ctx.body = { message: 'Incorrect contract source transaction id.' }; - return; - } - - const bindings: any[] = []; - srcTxId && bindings.push(srcTxId); - bindings.push(txId); - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT c.contract_id as "txId", - c.bundler_contract_tx_id as "bundlerTxId", - s.src_tx_id as "srcTxId", - (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, - (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", - c.init_state as "initState", - c.owner as "owner", - c.pst_ticker as "pstTicker", - c.pst_name as "pstName", - s.src_wasm_lang as "srcWasmLang", - c.contract_tx as "contractTx", - s.src_tx as "srcTx", - c.testnet as "testnet", - c.manifest as "manifest" - FROM contracts c - ${srcTxId ? 'JOIN contracts_src s on ? = s.src_tx_id' : 'JOIN contracts_src s on c.src_tx_id = s.src_tx_id'} - WHERE contract_id = ?; - `, - bindings - ); - - if (result?.rows[0].src == null && result?.rows[0].srcBinary == null) { - ctx.status = 500; - ctx.body = { message: 'Contract not properly indexed.' }; - } else { - ctx.body = result?.rows[0]; - logger.debug('Contract data loaded in', benchmark.elapsed()); - } - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/contractWithSourceRoute_v2.ts b/src/gateway/router/routes/contractWithSourceRoute_v2.ts deleted file mode 100644 index 6749d3c8..00000000 --- a/src/gateway/router/routes/contractWithSourceRoute_v2.ts +++ /dev/null @@ -1,72 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; -import { isTxIdValid } from '../../../utils'; - -export async function contractWithSourceRoute_v2(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { txId } = ctx.query; - - if (!isTxIdValid(txId as string)) { - logger.error('Incorrect contract transaction id.'); - ctx.status = 500; - ctx.body = { message: 'Incorrect contract transaction id.' }; - return; - } - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT c.contract_id as "txId", - c.bundler_contract_tx_id as "bundlerTxId", - s.src_tx_id as "srcTxId", - (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, - (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", - c.init_state as "initState", - c.owner as "owner", - c.pst_ticker as "pstTicker", - c.pst_name as "pstName", - s.src_wasm_lang as "srcWasmLang", - c.contract_tx as "contractTx", - s.src_tx as "srcTx", - c.testnet as "testnet", - c.manifest as "manifest", - c.block_timestamp as "blockTimestamp" - FROM contracts c - JOIN contracts_src s on c.src_tx_id = s.src_tx_id - WHERE contract_id = ?; - `, - txId - ); - - const srcResult = await dbSource.raw( - ` - SELECT s.src_tx_id as "srcTxId", - i.sort_key as "sortKey", - i.block_timestamp as "blockTimestamp", - (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, - (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", - s.src_wasm_lang as "srcWasmLang" - FROM interactions i - JOIN contracts_src s on s.src_tx_id = i.evolve - WHERE i.evolve IS NOT NULL and i.contract_id = ? ORDER BY i.sort_key DESC;`, - txId - ); - - if (result?.rows[0].src == null && result?.rows[0].srcBinary == null) { - ctx.status = 500; - ctx.body = { message: 'Contract not properly indexed.' }; - } else { - ctx.body = { - ...result?.rows[0], - evolvedSrc: srcResult.rows, - }; - logger.debug('Contract data loaded in', benchmark.elapsed()); - } - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/contracts/contractDataRoute.ts b/src/gateway/router/routes/contracts/contractDataRoute.ts new file mode 100644 index 00000000..1e3a6f0b --- /dev/null +++ b/src/gateway/router/routes/contracts/contractDataRoute.ts @@ -0,0 +1,100 @@ +import Router from '@koa/router'; +import Arweave from 'arweave'; +import {ArweaveWrapper, Benchmark, Tags, WarpLogger} from 'warp-contracts'; +import {decodeTags, getTagByName, isTxIdValid} from '../../../../utils'; +import Transaction from 'arweave/node/lib/transaction'; +import { WarpDeployment } from '../deploy/deployContractRoute'; +import {GatewayError} from "../../../errorHandlerMiddleware"; + +export async function contractDataRoute(ctx: Router.RouterContext) { + const {logger, dbSource, arweave, arweaveWrapper} = ctx; + + const {id} = ctx.params; + + if (!isTxIdValid(id as string)) { + throw new GatewayError('Incorrect contract transaction id.', 403); + } + + const benchmark = Benchmark.measure(); + logger.debug('ContractDataRoute id: ', id); + + const result: any = await dbSource.raw( + ` + SELECT bundler_contract_tx_id as "bundlerContractTxId", + contract_tx -> 'tags' as "contractTags", + deployment_type as "deploymentType", + bundler_contract_node as "bundlrContractNode" + FROM contracts + WHERE contract_id = ?; + `, + [id] + ); + if (result?.rows[0] == null || result?.rows[0].bundlerContractTxId == null) { + throw new GatewayError('Contract not indexed as bundled.'); + } else { + let tags: Tags = []; + if (result?.rows[0].contractTags) { + tags = decodeTags(result?.rows[0].contractTags); + } + + const {data, contentType} = await getContractData( + arweave, + logger, + result?.rows[0].bundlerContractTxId, + tags, + arweaveWrapper, + result?.rows[0].deploymentType, + result.rows[0].bundlrContractNode + ); + ctx.body = data; + ctx.set('Content-Type', contentType); + logger.debug('Contract data loaded in', benchmark.elapsed()); + } + +} + +async function getContractData( + arweave: Arweave, + logger: WarpLogger, + id: string, + tags: { name: string; value: string }[], + arweaveWrapper: ArweaveWrapper, + deploymentType: string, + bundlrContractNode: string +) { + let data: ArrayBuffer | Buffer; + + try { + data = await arweaveWrapper.txData(id); + } catch (e) { + logger.error(`Error from Arweave Gateway while loading data: `, e); + + data = await fetch(`${bundlrContractNode}/tx/${id}/data`).then((res) => { + return res.arrayBuffer(); + }); + } + const strData = arweave.utils.bufferToString(data); + + logger.debug('strData', strData); + + if (deploymentType == WarpDeployment.External) { + const contentType = getTagByName(tags, 'Content-Type'); + logger.debug(`Content type for id: ${id}: `, contentType); + return {data: strData, contentType}; + } else { + const tx = new Transaction({...JSON.parse(strData)}); + const txData = Buffer.from(tx.data); + const contentType = getContentTypeFromTx(tx); + logger.debug(`Content type for id: ${id}: `, contentType); + return {data: txData, contentType}; + } +} + +function getContentTypeFromTx(tx: Transaction) { + const tagContentType = tx + .get('tags') + // @ts-ignore + .find((tag: BaseObject) => tag.get('name', {decode: true, string: true}) == 'Content-Type'); + + return tagContentType.get('value', {decode: true, string: true}); +} diff --git a/src/gateway/router/routes/contracts/contractRoute.ts b/src/gateway/router/routes/contracts/contractRoute.ts new file mode 100644 index 00000000..7c53f02c --- /dev/null +++ b/src/gateway/router/routes/contracts/contractRoute.ts @@ -0,0 +1,48 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; +import {GatewayError} from "../../../errorHandlerMiddleware"; + +/** + * @deprecated Following route has been replaced with `contractWithSourceRoute` and is not used in the SDK + * anymore. It should be deleted in the future, leaving due to backwards compatibility of the introduction of + * the new endpoint. + */ + +export async function contractRoute(ctx: Router.RouterContext) { + const {logger, dbSource} = ctx; + + const {id} = ctx.params; + + if (id?.length != 43) { + throw new GatewayError('Wrong transaction id format', 403); + } + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT c.contract_id as "txId", + c.src_tx_id as "srcTxId", + (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, + (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", + c.init_state as "initState", + c.owner as "owner", + c.pst_ticker as "pstTicker", + c.pst_name as "pstName", + s.src_wasm_lang as "srcWasmLang", + c.contract_tx as "contractTx", + s.src_tx as "srcTx", + c.testnet as "testnet" + FROM contracts c + JOIN contracts_src s on c.src_tx_id = s.src_tx_id + WHERE contract_id = ?; + `, + [id] + ); + + if (result?.rows[0].src == null && result?.rows[0].srcBinary == null) { + throw new GatewayError('Contract not properly indexed.'); + } else { + ctx.body = result?.rows[0]; + logger.debug('Contract data loaded in', benchmark.elapsed()); + } +} diff --git a/src/gateway/router/routes/contracts/contractSourceRoute.ts b/src/gateway/router/routes/contracts/contractSourceRoute.ts new file mode 100644 index 00000000..e58ea19e --- /dev/null +++ b/src/gateway/router/routes/contracts/contractSourceRoute.ts @@ -0,0 +1,40 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; +import {isTxIdValid} from '../../../../utils'; +import {GatewayError} from "../../../errorHandlerMiddleware"; + +export async function contractSourceRoute(ctx: Router.RouterContext) { + const {logger, dbSource} = ctx; + + const {id} = ctx.query; + + if (!isTxIdValid(id as string)) { + throw new GatewayError('Incorrect contract source transaction id.', 403); + } + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT s.src_tx_id as "srcTxId", + (case when not s.owner = 'error' then s.owner else null end) as "owner", + s.src_content_type as "srcContentType", + (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, + (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", + s.src_wasm_lang as "srcWasmLang", + s.bundler_src_tx_id as "bundlerSrcTxId", + s.src_tx as "srcTx" + FROM contracts_src s + WHERE src_tx_id = ? + AND src IS DISTINCT FROM 'error'; + `, + [id] + ); + + if (!result?.rows[0]) { + throw new GatewayError('Could not load contract source.', 400); + } else { + ctx.body = result?.rows[0]; + } + + logger.debug('Source loaded in', benchmark.elapsed()); +} diff --git a/src/gateway/router/routes/contracts/contractWithSourceRoute.ts b/src/gateway/router/routes/contracts/contractWithSourceRoute.ts new file mode 100644 index 00000000..4a4eabe6 --- /dev/null +++ b/src/gateway/router/routes/contracts/contractWithSourceRoute.ts @@ -0,0 +1,54 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; +import {isTxIdValid} from '../../../../utils'; +import {GatewayError} from "../../../errorHandlerMiddleware"; + +export async function contractWithSourceRoute(ctx: Router.RouterContext) { + const {logger, dbSource} = ctx; + + const {txId, srcTxId} = ctx.query; + + if (!isTxIdValid(txId as string)) { + throw new GatewayError('Incorrect contract transaction id.', 403); + } + + if (srcTxId && !isTxIdValid(srcTxId as string)) { + throw new GatewayError('Incorrect contract source transaction id.', 403); + } + + const bindings: any[] = []; + srcTxId && bindings.push(srcTxId); + bindings.push(txId); + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT c.contract_id as "txId", + c.bundler_contract_tx_id as "bundlerTxId", + s.src_tx_id as "srcTxId", + (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, + (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", + c.init_state as "initState", + c.owner as "owner", + c.pst_ticker as "pstTicker", + c.pst_name as "pstName", + s.src_wasm_lang as "srcWasmLang", + c.contract_tx as "contractTx", + s.src_tx as "srcTx", + c.testnet as "testnet", + c.manifest as "manifest" + FROM contracts c + ${srcTxId ? 'JOIN contracts_src s on ? = s.src_tx_id' : 'JOIN contracts_src s on c.src_tx_id = s.src_tx_id'} + WHERE contract_id = ?; + `, + bindings + ); + + if (result?.rows[0].src == null && result?.rows[0].srcBinary == null) { + throw new GatewayError('Contract not properly indexed.'); + } else { + ctx.body = result?.rows[0]; + logger.debug('Contract data loaded in', benchmark.elapsed()); + } + +} diff --git a/src/gateway/router/routes/contracts/contractWithSourceRoute_v2.ts b/src/gateway/router/routes/contracts/contractWithSourceRoute_v2.ts new file mode 100644 index 00000000..60e7040d --- /dev/null +++ b/src/gateway/router/routes/contracts/contractWithSourceRoute_v2.ts @@ -0,0 +1,65 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; +import {isTxIdValid} from '../../../../utils'; +import {GatewayError} from "../../../errorHandlerMiddleware"; + +export async function contractWithSourceRoute_v2(ctx: Router.RouterContext) { + const {logger, dbSource} = ctx; + + const {txId} = ctx.query; + + if (!isTxIdValid(txId as string)) { + throw new GatewayError('Incorrect contract transaction id.', 403); + } + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT c.contract_id as "txId", + c.bundler_contract_tx_id as "bundlerTxId", + s.src_tx_id as "srcTxId", + (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, + (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", + c.init_state as "initState", + c.owner as "owner", + c.pst_ticker as "pstTicker", + c.pst_name as "pstName", + s.src_wasm_lang as "srcWasmLang", + c.contract_tx as "contractTx", + s.src_tx as "srcTx", + c.testnet as "testnet", + c.manifest as "manifest", + c.block_timestamp as "blockTimestamp" + FROM contracts c + JOIN contracts_src s on c.src_tx_id = s.src_tx_id + WHERE contract_id = ?; + `, + txId + ); + + const srcResult = await dbSource.raw( + ` + SELECT s.src_tx_id as "srcTxId", + i.sort_key as "sortKey", + i.block_timestamp as "blockTimestamp", + (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, + (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", + s.src_wasm_lang as "srcWasmLang" + FROM interactions i + JOIN contracts_src s on s.src_tx_id = i.evolve + WHERE i.evolve IS NOT NULL + and i.contract_id = ? + ORDER BY i.sort_key DESC;`, + txId + ); + + if (result?.rows[0].src == null && result?.rows[0].srcBinary == null) { + throw new GatewayError('Contract not properly indexed.'); + } else { + ctx.body = { + ...result?.rows[0], + evolvedSrc: srcResult.rows, + }; + logger.debug('Contract data loaded in', benchmark.elapsed()); + } +} diff --git a/src/gateway/router/routes/contractsBySourceRoute.ts b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts similarity index 71% rename from src/gateway/router/routes/contractsBySourceRoute.ts rename to src/gateway/router/routes/contracts/contractsBySourceRoute.ts index bddf704e..b040c18d 100644 --- a/src/gateway/router/routes/contractsBySourceRoute.ts +++ b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts @@ -1,13 +1,14 @@ import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; -import { isTxIdValid } from '../../../utils'; +import {Benchmark} from 'warp-contracts'; +import {isTxIdValid} from '../../../../utils'; +import {GatewayError} from "../../../errorHandlerMiddleware"; const MAX_INTERACTIONS_PER_PAGE = 5000; export async function contractsBySourceRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; + const {logger, dbSource} = ctx; - const { id, page, limit, sort } = ctx.query; + const {id, page, limit, sort} = ctx.query; const parsedPage = page ? parseInt(page as string) : 1; @@ -17,10 +18,7 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; if (!isTxIdValid(id as string)) { - logger.error('Incorrect contract source transaction id.'); - ctx.status = 500; - ctx.body = { message: 'Incorrect contract source transaction id.' }; - return; + throw new GatewayError('Incorrect contract source transaction id.', 403); } logger.info(`contractsBySourceRoute [ip: ${ctx.request?.ip}, srcId: ${id}]`); @@ -31,8 +29,7 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { parsedPage && bindings.push(offset); id && bindings.push(id); - try { - const benchmark = Benchmark.measure(); + const benchmark = Benchmark.measure(); const result: any = await dbSource.raw( ` @@ -67,23 +64,17 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { bindings ); - console.log(result.rows.length); - const total = result?.rows?.length > 0 ? result?.rows[0].total : 0; + const total = result?.rows?.length > 0 ? result?.rows[0].total : 0; - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - contracts: result?.rows, - }; - logger.debug('Source loaded in', benchmark.elapsed()); - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + contracts: result?.rows, + }; + logger.debug('Source loaded in', benchmark.elapsed()); } diff --git a/src/gateway/router/routes/contracts/contractsRoute.ts b/src/gateway/router/routes/contracts/contractsRoute.ts new file mode 100644 index 00000000..76985fcb --- /dev/null +++ b/src/gateway/router/routes/contracts/contractsRoute.ts @@ -0,0 +1,69 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; + +const MAX_CONTRACTS_PER_PAGE = 100; + +export async function contractsRoute(ctx: Router.RouterContext) { + const {logger, dbSource} = ctx; + + const {contractType, sourceType, page, limit, testnet} = ctx.query; + + logger.debug('Contracts route', {contractType, sourceType, page, limit}); + + const parsedPage = page ? parseInt(page as string) : 1; + const parsedLimit = limit ? Math.min(parseInt(limit as string), MAX_CONTRACTS_PER_PAGE) : MAX_CONTRACTS_PER_PAGE; + const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; + + const bindings: any[] = []; + contractType && bindings.push(contractType); + sourceType && bindings.push(sourceType); + parsedPage && bindings.push(parsedLimit); + parsedPage && bindings.push(offset); + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT c.contract_id AS contract, + c.owner AS owner, + c.type AS contract_type, + c.pst_ticker AS pst_ticker, + c.pst_name AS pst_name, + c.testnet AS testnet, + s.src_content_type AS src_content_type, + s.src_wasm_lang AS src_wasm_lang, + count(i.contract_id) AS interactions, + count(case when i.confirmation_status = 'corrupted' then 1 end) AS corrupted, + count(case when i.confirmation_status = 'confirmed' then 1 end) AS confirmed, + max(i.block_height) AS last_interaction_height, + count(*) OVER () AS total + FROM contracts c + LEFT JOIN interactions i + ON c.contract_id = i.contract_id + LEFT JOIN contracts_src s + ON c.src_tx_id = s.src_tx_id + WHERE c.contract_id != '' + AND c.type != 'error' + ${contractType ? ' AND c.type = ?' : ''} + ${sourceType ? ' AND s.src_content_type = ?' : ''} + ${testnet ? ' AND c.testnet IS NOT NULL' : ''} + GROUP BY c.contract_id, c.owner, c.type, c.pst_ticker, c.pst_name, s.src_content_type, s.src_wasm_lang + ORDER BY last_interaction_height DESC NULLS LAST, interactions DESC NULLS LAST ${ + parsedPage ? ' LIMIT ? OFFSET ?' : '' + }; + `, + bindings + ); + + const total = result?.rows?.length > 0 ? parseInt(result.rows[0].total) : 0; + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + contracts: result?.rows, + }; + logger.debug('Contracts loaded in', benchmark.elapsed()); +} diff --git a/src/gateway/router/routes/contractsRoute.ts b/src/gateway/router/routes/contractsRoute.ts deleted file mode 100644 index 79730490..00000000 --- a/src/gateway/router/routes/contractsRoute.ts +++ /dev/null @@ -1,75 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -const MAX_CONTRACTS_PER_PAGE = 100; - -export async function contractsRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { contractType, sourceType, page, limit, testnet } = ctx.query; - - logger.debug('Contracts route', { contractType, sourceType, page, limit }); - - const parsedPage = page ? parseInt(page as string) : 1; - const parsedLimit = limit ? Math.min(parseInt(limit as string), MAX_CONTRACTS_PER_PAGE) : MAX_CONTRACTS_PER_PAGE; - const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; - - const bindings: any[] = []; - contractType && bindings.push(contractType); - sourceType && bindings.push(sourceType); - parsedPage && bindings.push(parsedLimit); - parsedPage && bindings.push(offset); - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT c.contract_id AS contract, - c.owner AS owner, - c.type AS contract_type, - c.pst_ticker AS pst_ticker, - c.pst_name AS pst_name, - c.testnet AS testnet, - s.src_content_type AS src_content_type, - s.src_wasm_lang AS src_wasm_lang, - count(i.contract_id) AS interactions, - count(case when i.confirmation_status = 'corrupted' then 1 end) AS corrupted, - count(case when i.confirmation_status = 'confirmed' then 1 end) AS confirmed, - max(i.block_height) AS last_interaction_height, - count(*) OVER () AS total - FROM contracts c - LEFT JOIN interactions i - ON c.contract_id = i.contract_id - LEFT JOIN contracts_src s - ON c.src_tx_id = s.src_tx_id - WHERE c.contract_id != '' - AND c.type != 'error' - ${contractType ? ' AND c.type = ?' : ''} - ${sourceType ? ' AND s.src_content_type = ?' : ''} - ${testnet ? ' AND c.testnet IS NOT NULL' : ''} - GROUP BY c.contract_id, c.owner, c.type, c.pst_ticker, c.pst_name, s.src_content_type, s.src_wasm_lang - ORDER BY last_interaction_height DESC NULLS LAST, interactions DESC NULLS LAST ${ - parsedPage ? ' LIMIT ? OFFSET ?' : '' - }; - `, - bindings - ); - - const total = result?.rows?.length > 0 ? parseInt(result.rows[0].total) : 0; - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - contracts: result?.rows, - }; - logger.debug('Contracts loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/creatorRoute.ts b/src/gateway/router/routes/creatorRoute.ts index 50ae9f1f..7da3a30f 100644 --- a/src/gateway/router/routes/creatorRoute.ts +++ b/src/gateway/router/routes/creatorRoute.ts @@ -23,55 +23,49 @@ export async function creatorRoute(ctx: Router.RouterContext) { parsedPage && bindings.push(parsedLimit); parsedPage && bindings.push(offset); - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - WITH all_transactions AS (${ - txType != 'contract' - ? `SELECT - interaction_id AS id, - bundler_tx_id AS bundler_id, - block_height, - interaction->'block'->>'timestamp' AS block_timestamp, - 'interaction' AS type - FROM interactions - where owner = ?` - : '' - } - ${!txType ? 'UNION all' : ''} - ${ - txType != 'interaction' - ? `SELECT - contract_id AS id, - bundler_contract_tx_id AS bundler_id, - block_height, - block_timestamp::text AS block_timestamp, - 'contract' AS type - FROM contracts where owner = ?` - : '' - }) - SELECT *, COUNT(*) OVER() AS total FROM all_transactions ORDER BY all_transactions.block_timestamp DESC LIMIT ? OFFSET ?;`, - bindings - ); + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + WITH all_transactions AS (${ + txType != 'contract' + ? `SELECT + interaction_id AS id, + bundler_tx_id AS bundler_id, + block_height, + interaction->'block'->>'timestamp' AS block_timestamp, + 'interaction' AS type + FROM interactions + where owner = ?` + : '' + } + ${!txType ? 'UNION all' : ''} + ${ + txType != 'interaction' + ? `SELECT + contract_id AS id, + bundler_contract_tx_id AS bundler_id, + block_height, + block_timestamp::text AS block_timestamp, + 'contract' AS type + FROM contracts where owner = ?` + : '' + }) + SELECT *, COUNT(*) OVER() AS total FROM all_transactions ORDER BY all_transactions.block_timestamp DESC LIMIT ? OFFSET ?;`, + bindings + ); - const total = result?.rows?.length > 0 ? parseInt(result.rows[0].total) : 0; + const total = result?.rows?.length > 0 ? parseInt(result.rows[0].total) : 0; - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - transactions: result?.rows, - }; + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + transactions: result?.rows, + }; - logger.debug(`Owner's transactions loaded in ${benchmark.elapsed()}`); - } catch (e: any) { - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + logger.debug(`Owner's transactions loaded in ${benchmark.elapsed()}`); } diff --git a/src/gateway/router/routes/dashboardRoute.ts b/src/gateway/router/routes/dashboardRoute.ts index 0b0f21e3..b268d309 100644 --- a/src/gateway/router/routes/dashboardRoute.ts +++ b/src/gateway/router/routes/dashboardRoute.ts @@ -12,72 +12,66 @@ export async function dashboardRoute(ctx: Router.RouterContext) { contractLimit && bindings.push(contractLimit); interactionLimit && bindings.push(interactionLimit); - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - with contract as (select 'contract' AS contract_or_interaction, - contract_id AS contract_id, - '' AS interaction_id, - owner AS owner, - type AS contract_type, - '' AS function, - block_height AS block_height, - sync_timestamp AS sync_timestamp, - '' AS sort_key, - CASE contracts.deployment_type - WHEN 'warp-external' THEN 'warp' - WHEN 'warp-direct' THEN 'warp' - WHEN 'warp-wrapped' THEN 'warp' - ELSE contracts.deployment_type - END AS source - from contracts + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + with contract as (select 'contract' AS contract_or_interaction, + contract_id AS contract_id, + '' AS interaction_id, + owner AS owner, + type AS contract_type, + '' AS function, + block_height AS block_height, + sync_timestamp AS sync_timestamp, + '' AS sort_key, + CASE contracts.deployment_type + WHEN 'warp-external' THEN 'warp' + WHEN 'warp-direct' THEN 'warp' + WHEN 'warp-wrapped' THEN 'warp' + ELSE contracts.deployment_type + END AS source + from contracts + where contract_id != '' + AND type != 'error' + AND testnet IS ${testnet ? ' NOT NULL ' : ' NULL '} + AND sync_timestamp IS NOT NULL + order by sync_timestamp DESC + LIMIT ${contractLimit ? ' ? ' : ' 100'} + ), + interaction as (select 'interaction' AS contract_or_interaction, + contract_id AS contract_id, + interaction_id AS interaction_id, + owner AS owner, + '' AS contract_type, + function AS function, + block_height AS block_height, + sync_timestamp AS sync_timestamp, + sort_key AS sort_key, + CASE source + WHEN 'redstone-sequencer' THEN 'sequencer' + ELSE source + END AS source + from interactions where contract_id != '' - AND type != 'error' - AND testnet IS ${testnet ? ' NOT NULL ' : ' NULL '} - AND sync_timestamp IS NOT NULL - order by sync_timestamp DESC - LIMIT ${contractLimit ? ' ? ' : ' 100'} - ), - interaction as (select 'interaction' AS contract_or_interaction, - contract_id AS contract_id, - interaction_id AS interaction_id, - owner AS owner, - '' AS contract_type, - function AS function, - block_height AS block_height, - sync_timestamp AS sync_timestamp, - sort_key AS sort_key, - CASE source - WHEN 'redstone-sequencer' THEN 'sequencer' - ELSE source - END AS source - from interactions - where contract_id != '' - AND testnet IS ${testnet ? ' NOT NULL ' : ' NULL '} - AND sync_timestamp IS NOT NULL - order by sync_timestamp desc - LIMIT ${interactionLimit ? ' ? ' : ' 100'} - ) - select * from contract - union all - select * from interaction; - `, - bindings - ); + AND testnet IS ${testnet ? ' NOT NULL ' : ' NULL '} + AND sync_timestamp IS NOT NULL + order by sync_timestamp desc + LIMIT ${interactionLimit ? ' ? ' : ' 100'} + ) + select * from contract + union all + select * from interaction; + `, + bindings + ); - ctx.body = { - summary: { - contractLimit: contractLimit, - interactionLimit: interactionLimit, - itemsCount: result?.rows.length, - }, - contracts: result?.rows, - }; - logger.debug('Contracts loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + ctx.body = { + summary: { + contractLimit: contractLimit, + interactionLimit: interactionLimit, + itemsCount: result?.rows.length, + }, + contracts: result?.rows, + }; + logger.debug('Contracts loaded in', benchmark.elapsed()); } diff --git a/src/gateway/router/routes/deployBundledRoute.ts b/src/gateway/router/routes/deploy/deployBundledRoute.ts similarity index 63% rename from src/gateway/router/routes/deployBundledRoute.ts rename to src/gateway/router/routes/deploy/deployBundledRoute.ts index b3a9192a..f9c3fd2b 100644 --- a/src/gateway/router/routes/deployBundledRoute.ts +++ b/src/gateway/router/routes/deploy/deployBundledRoute.ts @@ -1,43 +1,43 @@ import Router from '@koa/router'; -import { evalType } from '../../tasks/contractsMetadata'; -import { BUNDLR_NODE1_URL } from '../../../constants'; +import { evalType } from '../../../tasks/contractsMetadata'; +import { BUNDLR_NODE1_URL } from '../../../../constants'; import { DataItem } from 'arbundles'; import rawBody from 'raw-body'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; -import { publishContract, sendNotification } from '../../publisher'; -import { evalManifest, WarpDeployment } from './deployContractRoute'; -import { ContractInsert } from '../../../db/insertInterfaces'; +import {getCachedNetworkData} from '../../../tasks/networkInfoCache'; +import {publishContract, sendNotification} from '../../../publisher'; +import {evalManifest, WarpDeployment} from './deployContractRoute'; +import {ContractInsert} from '../../../../db/insertInterfaces'; +import {GatewayError} from "../../../errorHandlerMiddleware"; export async function deployBundledRoute(ctx: Router.RouterContext) { - const { logger, dbSource, arweave, bundlr } = ctx; + const {logger, dbSource, arweave, bundlr} = ctx; let initStateRaw, dataItem; - try { - const rawDataItem: Buffer = await rawBody(ctx.req); - dataItem = new DataItem(rawDataItem); - const isValid = await dataItem.isValid(); - if (!isValid) { - ctx.throw(400, 'Data item binary is not valid.'); - } - - const areContractTagsValid = await verifyContractTags(dataItem, ctx); - if (!areContractTagsValid) { - ctx.throw(400, 'Contract tags are not valid.'); - } - const bundlrResponse = await bundlr.uploader.uploadTransaction(dataItem, { getReceiptSignature: true }); + const rawDataItem: Buffer = await rawBody(ctx.req); + dataItem = new DataItem(rawDataItem); + const isValid = await dataItem.isValid(); + if (!isValid) { + throw new GatewayError('Data item binary is not valid.', 400); + } - if (bundlrResponse.status !== 200 || !bundlrResponse.data.public || !bundlrResponse.data.signature) { - throw new Error( - `Bundlr did not upload transaction correctly. Bundlr responded with status ${bundlrResponse.status}.` - ); - } + const areContractTagsValid = await verifyContractTags(dataItem, ctx); + if (!areContractTagsValid) { + throw new GatewayError('Contract tags are not valid.', 400); + } - logger.debug('Data item successfully bundled.', { - id: bundlrResponse.data.id, - }); + const bundlrResponse = await bundlr.uploader.uploadTransaction(dataItem, {getReceiptSignature: true}); + if (bundlrResponse.status !== 200 || !bundlrResponse.data.public || !bundlrResponse.data.signature) { + throw new GatewayError( + `Bundlr did not upload transaction correctly. Bundlr responded with status ${bundlrResponse.status}.` + ); + } + logger.debug('Data item successfully bundled.', { + id: bundlrResponse.data.id, + }); + try { const srcTxId = dataItem.tags.find((t) => t.name == 'Contract-Src')!.value; initStateRaw = dataItem.tags.find((t) => t.name == 'Init-State')!.value; const initState = JSON.parse(initStateRaw); @@ -61,7 +61,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { block_height: blockHeight, block_timestamp: blockTimestamp, content_type: contentType, - contract_tx: { tags: dataItem.toJSON().tags }, + contract_tx: {tags: dataItem.toJSON().tags}, bundler_contract_tx_id: bundlrResponse.data.id, bundler_contract_node: BUNDLR_NODE1_URL, testnet, @@ -71,7 +71,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { }; await dbSource.insertContract(insert); - sendNotification(ctx, bundlrResponse.data.id, { initState, tags: dataItem.tags }); + sendNotification(ctx, bundlrResponse.data.id, {initState, tags: dataItem.tags}); publishContract( ctx, bundlrResponse.data.id, @@ -92,23 +92,20 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { contractTxId: bundlrResponse.data.id, }; } catch (e: any) { - logger.error('Error while inserting bundled transaction.', { + throw new GatewayError(`Error while inserting bundled transaction.`, 500, { dataItemId: dataItem?.id, contractTx: dataItem?.toJSON(), initStateRaw: initStateRaw, }); - logger.error(e); - ctx.body = e; - ctx.status = e.status ? e.status : 500; } } export async function verifyContractTags(dataItem: DataItem, ctx: Router.RouterContext) { const tags = dataItem.tags; const tagsIncluded = [ - { name: 'App-Name', value: 'SmartWeaveContract' }, - { name: 'App-Version', value: '0.3.0' }, - { name: 'Content-Type', value: 'application/x.arweave-manifest+json' }, + {name: 'App-Name', value: 'SmartWeaveContract'}, + {name: 'App-Version', value: '0.3.0'}, + {name: 'Content-Type', value: 'application/x.arweave-manifest+json'}, ]; const nameTagsIncluded = ['Contract-Src', 'Init-State', 'Title', 'Description', 'Type']; if (tags.some((t) => t.name == tagsIncluded[2].name && t.value != tagsIncluded[2].value)) { diff --git a/src/gateway/router/routes/deployContractRoute.ts b/src/gateway/router/routes/deploy/deployContractRoute.ts similarity index 93% rename from src/gateway/router/routes/deployContractRoute.ts rename to src/gateway/router/routes/deploy/deployContractRoute.ts index 6cafb4b2..b7f0677f 100644 --- a/src/gateway/router/routes/deployContractRoute.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute.ts @@ -2,12 +2,13 @@ import Router, { RouterContext } from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; import Arweave from 'arweave'; import { GQLTagInterface, SmartWeaveTags } from 'warp-contracts'; -import { evalType } from '../../tasks/contractsMetadata'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; -import { BUNDLR_NODE1_URL } from '../../../constants'; -import { uploadToBundlr } from './sequencerRoute'; -import { publishContract, sendNotification } from '../../publisher'; -import { ContractInsert, ContractSourceInsert } from '../../../db/insertInterfaces'; +import { evalType } from '../../../tasks/contractsMetadata'; +import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; +import { BUNDLR_NODE1_URL } from '../../../../constants'; +import { uploadToBundlr } from '../sequencerRoute'; +import { publishContract, sendNotification } from '../../../publisher'; +import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; +import {GatewayError} from "../../../errorHandlerMiddleware"; /* - warp-wrapped - contract or source is wrapped in another transaction - it is posted by Warp Gateway to the Bundlr network and sent @@ -169,10 +170,7 @@ export async function deployContractRoute(ctx: Router.RouterContext) { bundleSrcId: bundlerSrcTxId, }; } catch (e) { - logger.error('Error while inserting bundled transaction'); - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; + throw new GatewayError(`Error while inserting bundled transaction: ${e}`); } } diff --git a/src/gateway/router/routes/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts similarity index 83% rename from src/gateway/router/routes/deployContractRoute_v2.ts rename to src/gateway/router/routes/deploy/deployContractRoute_v2.ts index c47abdd4..db4777c9 100644 --- a/src/gateway/router/routes/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -1,19 +1,20 @@ import Router from '@koa/router'; -import { evalType } from '../../tasks/contractsMetadata'; -import { BUNDLR_NODE1_URL } from '../../../constants'; +import { evalType } from '../../../tasks/contractsMetadata'; +import { BUNDLR_NODE1_URL } from '../../../../constants'; import { Bundle, DataItem } from 'arbundles'; import { ContractSource, sleep, SmartWeaveTags } from 'warp-contracts'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; -import { publishContract, sendNotification } from '../../publisher'; +import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; +import { publishContract, sendNotification } from '../../../publisher'; import { evalManifest, WarpDeployment } from './deployContractRoute'; import Arweave from 'arweave'; -import { SignatureConfig } from 'arbundles/src/constants'; -import { Contract, utils } from 'ethers'; -import { longTo32ByteArray } from 'arbundles/src/utils'; -import { ContractInsert, ContractSourceInsert } from '../../../db/insertInterfaces'; +import {SignatureConfig} from 'arbundles/src/constants'; +import {utils} from 'ethers'; +import {longTo32ByteArray} from 'arbundles/src/utils'; +import {ContractInsert, ContractSourceInsert} from '../../../../db/insertInterfaces'; +import {GatewayError} from "../../../errorHandlerMiddleware"; export async function deployContractRoute_v2(ctx: Router.RouterContext) { - const { logger, arweave, dbSource } = ctx; + const {logger, arweave, dbSource} = ctx; let initStateRaw, contractDataItem, @@ -26,7 +27,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { if (!isContractValid) { ctx.throw(400, 'Contract data item binary is not valid.'); } - const areContractTagsValid = await verifyDeployTags(contractDataItem, { contract: true }); + const areContractTagsValid = await verifyDeployTags(contractDataItem, {contract: true}); if (!areContractTagsValid) { ctx.throw(400, 'Contract tags are not valid.'); } @@ -71,7 +72,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { deployment_type: WarpDeployment.Direct, }; } - const bundlrResponse = await bundleAndUpload({ contract: contractDataItem, src: srcDataItem || null }, ctx); + const bundlrResponse = await bundleAndUpload({contract: contractDataItem, src: srcDataItem || null}, ctx); logger.debug('Contract successfully uploaded to Bundlr.', { contract_id: contractDataItem.id, src_id: srcDataItem?.id, @@ -113,7 +114,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { block_height: blockHeight, block_timestamp: blockTimestamp, content_type: contentType, - contract_tx: { tags: contractDataItem.toJSON().tags }, + contract_tx: {tags: contractDataItem.toJSON().tags}, bundler_contract_tx_id: bundlrResponse.data.id, bundler_contract_node: BUNDLR_NODE1_URL, testnet, @@ -124,7 +125,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { await dbSource.insertContract(insert); - sendNotification(ctx, contractDataItem.id, { initState, tags: contractDataItem.tags }); + sendNotification(ctx, contractDataItem.id, {initState, tags: contractDataItem.tags}); publishContract( ctx, contractDataItem.id, @@ -149,14 +150,11 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { bundlrTxId: bundlrResponse.data.id, }; } catch (e: any) { - logger.error('Error while inserting bundled transaction.', { + throw new GatewayError(`Error while inserting bundled transaction: ${e}.`, 500, { dataItemId: contractDataItem?.id, contract: contractDataItem?.toJSON(), initStateRaw: initStateRaw, }); - logger.error(e); - ctx.body = e; - ctx.status = e.status ? e.status : 500; } } @@ -164,9 +162,9 @@ export async function verifyDeployTags(dataItem: DataItem, opts?: { contract: bo const tags = dataItem.tags; const deployTags = [ - { name: SmartWeaveTags.APP_NAME, value: opts?.contract ? 'SmartWeaveContract' : 'SmartWeaveContractSource' }, - { name: SmartWeaveTags.APP_VERSION, value: '0.3.0' }, - { name: SmartWeaveTags.SDK, value: 'Warp' }, + {name: SmartWeaveTags.APP_NAME, value: opts?.contract ? 'SmartWeaveContract' : 'SmartWeaveContractSource'}, + {name: SmartWeaveTags.APP_VERSION, value: '0.3.0'}, + {name: SmartWeaveTags.SDK, value: 'Warp'}, ]; const contractNameTags = ['Contract-Src', 'Nonce']; @@ -199,8 +197,8 @@ export async function bundleAndUpload( dataItems: { contract: DataItem | null; src: DataItem | null }, ctx: Router.RouterContext ) { - const { bundlr } = ctx; - const { contract, src } = dataItems; + const {bundlr} = ctx; + const {contract, src} = dataItems; const dataItemsToUpload = []; contract && dataItemsToUpload.push(contract); src && dataItemsToUpload.push(src); @@ -208,14 +206,14 @@ export async function bundleAndUpload( const bundlrTx = bundlr.createTransaction(bundle.getRaw(), { tags: [ - { name: 'Bundle-Format', value: 'binary' }, - { name: 'Bundle-Version', value: '2.0.0' }, - { name: 'App-Name', value: 'Warp' }, - { name: 'Action', value: 'WarpContractDeployment' }, + {name: 'Bundle-Format', value: 'binary'}, + {name: 'Bundle-Version', value: '2.0.0'}, + {name: 'App-Name', value: 'Warp'}, + {name: 'Action', value: 'WarpContractDeployment'}, ], }); await bundlrTx.sign(); - const bundlrResponse = await bundlr.uploader.uploadTransaction(bundlrTx, { getReceiptSignature: true }); + const bundlrResponse = await bundlr.uploader.uploadTransaction(bundlrTx, {getReceiptSignature: true}); if ( bundlrResponse.status !== 200 || !bundlrResponse.data.public || diff --git a/src/gateway/router/routes/deploySourceRoute.ts b/src/gateway/router/routes/deploy/deploySourceRoute.ts similarity index 87% rename from src/gateway/router/routes/deploySourceRoute.ts rename to src/gateway/router/routes/deploy/deploySourceRoute.ts index cf350754..cab814cd 100644 --- a/src/gateway/router/routes/deploySourceRoute.ts +++ b/src/gateway/router/routes/deploy/deploySourceRoute.ts @@ -2,10 +2,11 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; import Arweave from 'arweave'; import { SmartWeaveTags } from 'warp-contracts'; -import { BUNDLR_NODE1_URL } from '../../../constants'; -import { uploadToBundlr } from './sequencerRoute'; +import { BUNDLR_NODE1_URL } from '../../../../constants'; +import { uploadToBundlr } from '../sequencerRoute'; import { prepareTags, tagValue, verifyEvmSignature, WarpDeployment } from './deployContractRoute'; -import { ContractSourceInsert } from '../../../db/insertInterfaces'; +import { ContractSourceInsert } from '../../../../db/insertInterfaces'; +import {GatewayError} from "../../../errorHandlerMiddleware"; export async function deploySourceRoute(ctx: Router.RouterContext) { const { logger, arweave, bundlr, dbSource } = ctx; @@ -66,9 +67,6 @@ export async function deploySourceRoute(ctx: Router.RouterContext) { bundlrSrcTxId, }; } catch (e) { - logger.error('Error while inserting bundled source transaction'); - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; + throw new GatewayError(`Error while inserting bundled source transaction ${e}`); } } diff --git a/src/gateway/router/routes/deploySourceRoute_v2.ts b/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts similarity index 65% rename from src/gateway/router/routes/deploySourceRoute_v2.ts rename to src/gateway/router/routes/deploy/deploySourceRoute_v2.ts index fc9fe02b..38cbbba4 100644 --- a/src/gateway/router/routes/deploySourceRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts @@ -1,34 +1,35 @@ import Router from '@koa/router'; import Arweave from 'arweave'; import { SmartWeaveTags } from 'warp-contracts'; -import { BUNDLR_NODE1_URL } from '../../../constants'; +import { BUNDLR_NODE1_URL } from '../../../../constants'; import { WarpDeployment } from './deployContractRoute'; import rawBody from 'raw-body'; -import { DataItem } from 'arbundles'; -import { getTestnetTag } from './deployBundledRoute'; -import { bundleAndUpload, determineOwner, verifyDeployTags } from './deployContractRoute_v2'; -import { ContractSourceInsert } from '../../../db/insertInterfaces'; +import {DataItem} from 'arbundles'; +import {getTestnetTag} from './deployBundledRoute'; +import {bundleAndUpload, determineOwner, verifyDeployTags} from './deployContractRoute_v2'; +import {ContractSourceInsert} from '../../../../db/insertInterfaces'; +import {GatewayError} from "../../../errorHandlerMiddleware"; export async function deploySourceRoute_v2(ctx: Router.RouterContext) { - const { logger, arweave, dbSource } = ctx; + const {logger, arweave, dbSource} = ctx; let dataItem; - try { - const rawDataItem: Buffer = await rawBody(ctx.req); - dataItem = new DataItem(rawDataItem); - logger.debug('New deploy source transaction', dataItem.id); + const rawDataItem: Buffer = await rawBody(ctx.req); + dataItem = new DataItem(rawDataItem); + logger.debug('New deploy source transaction', dataItem.id); - const isValid = await dataItem.isValid(); - if (!isValid) { - ctx.throw(400, 'Source data item binary is not valid.'); - } + const isValid = await dataItem.isValid(); + if (!isValid) { + throw new GatewayError('Source data item binary is not valid.', 400); + } - const areSrcTagsValid = await verifyDeployTags(dataItem); - if (!areSrcTagsValid) { - ctx.throw(400, 'Contract source tags are not valid.'); - } + const areSrcTagsValid = await verifyDeployTags(dataItem); + if (!areSrcTagsValid) { + throw new GatewayError('Contract source tags are not valid.', 400); + } + try { let srcId, srcContentType, src, srcBinary, srcWasmLang, bundlrSrcTxId, srcOwner, srcTestnet, srcBundlrResponse; srcId = dataItem.id; srcOwner = await determineOwner(dataItem, arweave); @@ -41,7 +42,7 @@ export async function deploySourceRoute_v2(ctx: Router.RouterContext) { } else { srcBinary = dataItem.rawData; } - const bundlrResponse = await bundleAndUpload({ contract: null, src: dataItem }, ctx); + const bundlrResponse = await bundleAndUpload({contract: null, src: dataItem}, ctx); bundlrSrcTxId = bundlrResponse.data.id; srcBundlrResponse = bundlrResponse; @@ -75,12 +76,9 @@ export async function deploySourceRoute_v2(ctx: Router.RouterContext) { bundlrSrcTxId, }; } catch (e) { - logger.error('Error while inserting bundled transaction.', { + throw new GatewayError(`Error while inserting bundled transaction: ${e}.`, 500, { dataItemId: dataItem?.id, contractTx: dataItem?.toJSON(), }); - logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; } } diff --git a/src/gateway/router/routes/registerContractRoute.ts b/src/gateway/router/routes/deploy/registerContractRoute.ts similarity index 67% rename from src/gateway/router/routes/registerContractRoute.ts rename to src/gateway/router/routes/deploy/registerContractRoute.ts index 4e2a95e4..fb9a033e 100644 --- a/src/gateway/router/routes/registerContractRoute.ts +++ b/src/gateway/router/routes/deploy/registerContractRoute.ts @@ -1,14 +1,15 @@ import Router from '@koa/router'; -import { evalType } from '../../tasks/contractsMetadata'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; -import { publishContract, sendNotification } from '../../publisher'; -import { evalManifest, WarpDeployment } from './deployContractRoute'; -import { Tag } from 'arweave/node/lib/transaction'; -import { stringToB64Url } from 'arweave/node/lib/utils'; -import { fetch } from 'undici'; -import { backOff } from 'exponential-backoff'; -import { getTestnetTag } from './deployBundledRoute'; -import { ContractInsert } from '../../../db/insertInterfaces'; +import {evalType} from '../../../tasks/contractsMetadata'; +import {getCachedNetworkData} from '../../../tasks/networkInfoCache'; +import {publishContract, sendNotification} from '../../../publisher'; +import {evalManifest, WarpDeployment} from './deployContractRoute'; +import {Tag} from 'arweave/node/lib/transaction'; +import {stringToB64Url} from 'arweave/node/lib/utils'; +import {fetch} from 'undici'; +import {backOff} from 'exponential-backoff'; +import {getTestnetTag} from './deployBundledRoute'; +import {ContractInsert} from '../../../../db/insertInterfaces'; +import {GatewayError} from "../../../errorHandlerMiddleware"; const BUNDLR_QUERY = `query Transactions($ids: [String!]) { transactions(ids: $ids) { @@ -24,43 +25,44 @@ const BUNDLR_NODES = ['node1', 'node2'] as const; type BundlrNodeType = typeof BUNDLR_NODES[number]; export async function registerContractRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; + const {logger, dbSource} = ctx; let initStateRaw = ''; let contractTx = null; let txId = ''; - try { - const bundlrNode = ctx.request.body.bundlrNode; - if (!bundlrNode || !isBundlrNodeType(bundlrNode)) { - throw new Error( - `Invalid Bundlr Node. Should be equal to one of the following values: ${BUNDLR_NODES.map((n) => n).join( - ', ' - )}, found: ${bundlrNode}.` - ); - } - txId = ctx.request.body.id; + const bundlrNode = ctx.request.body.bundlrNode; + if (!bundlrNode || !isBundlrNodeType(bundlrNode)) { + throw new GatewayError( + `Invalid Bundlr Node. Should be equal to one of the following values: ${BUNDLR_NODES.map((n) => n).join( + ', ' + )}, found: ${bundlrNode}.`, 400 + ); + } - const txMetadata = ((await getBundlrGqlMetadata(txId, bundlrNode)) as any).transactions.edges[0].node; + txId = ctx.request.body.id; - const { contractTagsIncluded, tags, signature } = await verifyContractTags(txId, bundlrNode); - if (!contractTagsIncluded) { - ctx.throw(400, 'Bundlr transaction is not valid contract transaction.'); - } + const txMetadata = ((await getBundlrGqlMetadata(txId, bundlrNode)) as any).transactions.edges[0].node; - logger.debug('Bundlr transaction marked as valid contract transaction.'); + const {contractTagsIncluded, tags, signature} = await verifyContractTags(txId, bundlrNode); + if (!contractTagsIncluded) { + throw new GatewayError('Bundlr transaction is not valid contract transaction.', 400); + } - let encodedTags: Tag[] = []; + logger.debug('Bundlr transaction marked as valid contract transaction.'); - for (const tag of tags) { - try { - encodedTags.push(new Tag(stringToB64Url(tag.name), stringToB64Url(tag.value))); - } catch (e: any) { - throw new Error(`Unable to encode tag ${tag.name}: ${e.status}`); - } + let encodedTags: Tag[] = []; + + for (const tag of tags) { + try { + encodedTags.push(new Tag(stringToB64Url(tag.name), stringToB64Url(tag.value))); + } catch (e: any) { + throw new GatewayError(`Unable to encode tag ${tag.name}: ${e.status}`, 400); } + } + try { const srcTxId = tags.find((t: Tag) => t.name == 'Contract-Src')!.value; initStateRaw = tags.find((t: Tag) => t.name == 'Init-State')!.value; const initState = JSON.parse(initStateRaw); @@ -93,7 +95,7 @@ export async function registerContractRoute(ctx: Router.RouterContext) { block_height: blockHeight, block_timestamp: blockTimestamp, content_type: contentType, - contract_tx: { tags: contractTx.tags }, + contract_tx: {tags: contractTx.tags}, bundler_contract_tx_id: txId, bundler_contract_node: `https://${bundlrNode}.bundlr.network`, testnet, @@ -125,14 +127,11 @@ export async function registerContractRoute(ctx: Router.RouterContext) { contractTxId: txId, }; } catch (e: any) { - logger.error('Error while registering bundled transaction.', { + throw new GatewayError(`Error while registering bundled transaction: ${e}.`, 500, { txId, contractTx, initStateRaw, }); - logger.error(e); - ctx.body = e; - ctx.status = e.status ? e.status : 500; } } @@ -155,8 +154,8 @@ export async function verifyContractTags(id: string, bundlrNode: string) { const tags = response.tags; const signature = response.signature; const tagsIncluded = [ - { name: 'App-Name', value: 'SmartWeaveContract' }, - { name: 'App-Version', value: '0.3.0' }, + {name: 'App-Name', value: 'SmartWeaveContract'}, + {name: 'App-Version', value: '0.3.0'}, ]; const nameTagsIncluded = ['Contract-Src', 'Init-State', 'Content-Type']; @@ -165,13 +164,13 @@ export async function verifyContractTags(id: string, bundlrNode: string) { tagsIncluded.every((ti) => tags.some((t: Tag) => t.name == ti.name && t.value == ti.value)) && nameTagsIncluded.every((nti) => tags.some((t: Tag) => t.name == nti)); - return { contractTagsIncluded, tags, signature }; + return {contractTagsIncluded, tags, signature}; } export async function getBundlrGqlMetadata(id: string, bundlrNode: string) { const data = JSON.stringify({ query: BUNDLR_QUERY, - variables: { ids: [id] }, + variables: {ids: [id]}, }); const response = await fetch(`https://${bundlrNode}.bundlr.network/graphql`, { diff --git a/src/gateway/router/routes/interactionRoute.ts b/src/gateway/router/routes/interactionRoute.ts deleted file mode 100644 index 5ed6ad09..00000000 --- a/src/gateway/router/routes/interactionRoute.ts +++ /dev/null @@ -1,43 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -export async function interactionRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { id } = ctx.params; - - if (id?.length != 43) { - ctx.body = {}; - return; - } - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT interaction_id as interactionId, - bundler_tx_id as bundlerTxId, - interaction as interaction, - block_height as blockHeight, - block_id as blockId, - contract_id as contractId, - function as function, - input as input, - confirmation_status as confirmationStatus, - confirming_peer as confirmingPeer, - confirmed_at_height as confirmedAtHeight, - confirmations as confirmations, - sort_key as sortKey - FROM interactions - WHERE interaction_id = ?; - `, - [id] - ); - ctx.body = result?.rows[0]; - logger.debug('Contract data loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/interactions/interactionRoute.ts b/src/gateway/router/routes/interactions/interactionRoute.ts new file mode 100644 index 00000000..0c82c642 --- /dev/null +++ b/src/gateway/router/routes/interactions/interactionRoute.ts @@ -0,0 +1,37 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; +import {GatewayError} from "../../../errorHandlerMiddleware"; + +export async function interactionRoute(ctx: Router.RouterContext) { + const {logger, dbSource} = ctx; + + const {id} = ctx.params; + + if (id?.length != 43) { + throw new GatewayError('Incorrect contract source transaction id.', 403); + } + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT interaction_id as interactionId, + bundler_tx_id as bundlerTxId, + interaction as interaction, + block_height as blockHeight, + block_id as blockId, + contract_id as contractId, + function as function, + input as input, + confirmation_status as confirmationStatus, + confirming_peer as confirmingPeer, + confirmed_at_height as confirmedAtHeight, + confirmations as confirmations, + sort_key as sortKey + FROM interactions + WHERE interaction_id = ?; + `, + [id] + ); + ctx.body = result?.rows[0]; + logger.debug('Contract data loaded in', benchmark.elapsed()); +} diff --git a/src/gateway/router/routes/interactions/interactionsRoute.ts b/src/gateway/router/routes/interactions/interactionsRoute.ts new file mode 100644 index 00000000..affc8d8e --- /dev/null +++ b/src/gateway/router/routes/interactions/interactionsRoute.ts @@ -0,0 +1,110 @@ +import Router from '@koa/router'; + +const MAX_INTERACTIONS_PER_PAGE = 5000; + +export async function interactionsRoute(ctx: Router.RouterContext) { + const {dbSource} = ctx; + + const {contractId, confirmationStatus, page, limit, from, to, totalCount, source, upToTransactionId, minimize} = + ctx.query; + + const parsedPage = page ? parseInt(page as string) : 1; + + const parsedLimit = limit + ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) + : MAX_INTERACTIONS_PER_PAGE; + const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; + + const parsedConfirmationStatus = confirmationStatus + ? confirmationStatus == 'not_corrupted' + ? ['confirmed', 'not_processed'] + : [confirmationStatus] + : undefined; + + const shouldMinimize = minimize === 'true'; + + const bindings: any[] = []; + bindings.push(contractId); + bindings.push(contractId); + // cannot use IN with bindings https://github.com/knex/knex/issues/791 + // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) + from && bindings.push(from as string); + to && bindings.push(to as string); + source && bindings.push(source as string); + upToTransactionId && bindings.push(upToTransactionId as string); + parsedPage && bindings.push(parsedLimit); + parsedPage && bindings.push(offset); + + const result: any = await dbSource.raw( + ` + SELECT interaction, + confirmation_status + ${shouldMinimize ? '' : ',confirming_peer, confirmations, bundler_tx_id '} + ${shouldMinimize ? '' : ',count(*) OVER () AS total'} + FROM interactions + WHERE (contract_id = ? OR interact_write @> ARRAY [?]) + ${ + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' + } ${from ? ' AND block_height >= ?' : ''} ${to ? ' AND block_height <= ?' : ''} ${source ? `AND source = ?` : ''} ${upToTransactionId ? `AND id <= (SELECT id FROM interactions WHERE interaction_id = ?)` : ''} + ORDER BY block_height ${shouldMinimize ? 'ASC' : 'DESC'}, interaction_id DESC ${ + parsedPage ? ' LIMIT ? OFFSET ?' : '' + }; + `, + bindings + ); + + const totalInteractions: any = + totalCount == 'true' && + (await dbSource.raw( + ` + SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, + count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, + count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, + count(case when confirmation_status = 'forked' then 1 else null end) AS forked + FROM interactions + WHERE contract_id = ?; + `, + contractId + )); + + const total = result?.rows?.length > 0 ? result?.rows[0].total : 0; + + const mappedInteractions = shouldMinimize + ? result?.rows?.map((r: any) => ({ + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, + }, + confirmationStatus: r.confirmation_status, + })) + : result?.rows?.map((r: any) => ({ + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, + }, + })); + + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + ...(totalInteractions && { + total: { + confirmed: totalInteractions?.rows[0].confirmed, + corrupted: totalInteractions?.rows[0].corrupted, + not_processed: totalInteractions?.rows[0].not_processed, + forked: totalInteractions?.rows[0].forked, + }, + }), + interactions: mappedInteractions, + }; +} diff --git a/src/gateway/router/routes/interactions/interactionsSonar.ts b/src/gateway/router/routes/interactions/interactionsSonar.ts new file mode 100644 index 00000000..bc4bc847 --- /dev/null +++ b/src/gateway/router/routes/interactions/interactionsSonar.ts @@ -0,0 +1,102 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; + +const MAX_INTERACTIONS_PER_PAGE = 5000; + +export async function interactionsSonar(ctx: Router.RouterContext) { + const {dbSource, logger} = ctx; + + const {contractId, confirmationStatus, page, limit, from, to, source} = ctx.query; + + const parsedPage = page ? parseInt(page as string) : 1; + + const parsedLimit = limit + ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) + : MAX_INTERACTIONS_PER_PAGE; + const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; + + const parsedConfirmationStatus = confirmationStatus + ? confirmationStatus == 'not_corrupted' + ? ['confirmed', 'not_processed'] + : [confirmationStatus] + : undefined; + + const bindings: any[] = []; + bindings.push(contractId); + bindings.push(contractId); + from && bindings.push(from as string); + to && bindings.push(to as string); + source && bindings.push(source as string); + parsedPage && bindings.push(parsedLimit); + parsedPage && bindings.push(offset); + + const query = ` + SELECT interaction, + confirmation_status, + sort_key, + confirming_peer, + confirmations, + bundler_tx_id + FROM interactions + WHERE (contract_id = ? OR interact_write @> ARRAY [?]) + ${ + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' + } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} + ORDER BY sort_key DESC ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; + `; + + const result: any = await dbSource.raw(query, bindings); + + const totalInteractions: any = await dbSource.raw( + ` + SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, + count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, + count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, + count(case when confirmation_status = 'forked' then 1 else null end) AS forked + FROM interactions + WHERE (contract_id = ? OR interact_write @> ARRAY [?]); + `, + [contractId, contractId] + ); + + const total = + parseInt(totalInteractions.rows[0].confirmed) + + parseInt(totalInteractions.rows[0].corrupted) + + parseInt(totalInteractions.rows[0].not_processed) + + parseInt(totalInteractions.rows[0].forked); + + const benchmark = Benchmark.measure(); + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + ...(totalInteractions && { + total: { + confirmed: totalInteractions.rows[0].confirmed, + corrupted: totalInteractions.rows[0].corrupted, + not_processed: totalInteractions.rows[0].not_processed, + forked: totalInteractions.rows[0].forked, + }, + }), + + interactions: result?.rows?.map((r: any) => ({ + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, + sortKey: r.sort_key, + }, + })), + }; + + logger.info('Mapping interactions: ', benchmark.elapsed()); + +} diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts new file mode 100644 index 00000000..db0adfa5 --- /dev/null +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts @@ -0,0 +1,115 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; + +const MAX_INTERACTIONS_PER_PAGE = 5000; + +export async function interactionsSortKeyRoute(ctx: Router.RouterContext) { + const {dbSource, logger} = ctx; + + const {contractId, confirmationStatus, page, limit, from, to, totalCount, source, minimize} = ctx.query; + + const parsedPage = page ? parseInt(page as string) : 1; + + const parsedLimit = limit + ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) + : MAX_INTERACTIONS_PER_PAGE; + const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; + + const parsedConfirmationStatus = confirmationStatus + ? confirmationStatus == 'not_corrupted' + ? ['confirmed', 'not_processed'] + : [confirmationStatus] + : undefined; + + // 'should minimize' means that we're making a call from the SDK + // this affects: + // 1. the amount of returned data (we're trying to minimize amount of data in this case) + // 2. sorting order (SDK requires ASC order, SonAR requires DESC order) + const shouldMinimize = minimize === 'true'; + + const bindings: any[] = []; + bindings.push(contractId); + bindings.push(contractId); + // cannot use IN with bindings https://github.com/knex/knex/issues/791 + // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) + from && bindings.push(from as string); + to && bindings.push(to as string); + source && bindings.push(source as string); + parsedPage && bindings.push(parsedLimit); + parsedPage && bindings.push(offset); + + const query = ` + SELECT interaction, + confirmation_status, + sort_key + ${shouldMinimize ? '' : ',confirming_peer, confirmations, bundler_tx_id '} + ${shouldMinimize ? '' : ',count(*) OVER () AS total'} + FROM interactions + WHERE (contract_id = ? OR interact_write @> ARRAY [?]) + ${ + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' + } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} + ORDER BY sort_key ${shouldMinimize ? 'ASC' : 'DESC'} ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; + `; + + const result: any = await dbSource.raw(query, bindings); + + const totalInteractions: any = + totalCount == 'true' && + (await dbSource.raw( + ` + SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, + count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, + count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, + count(case when confirmation_status = 'forked' then 1 else null end) AS forked + FROM interactions + WHERE contract_id = ?; + `, + contractId + )); + + const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; + + const benchmark = Benchmark.measure(); + const mappedInteractions = shouldMinimize + ? result?.rows?.map((r: any) => ({ + ...r.interaction, + sortKey: r.sort_key, + confirmationStatus: r.confirmation_status, + })) + : result?.rows?.map((r: any) => ({ + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, + sortKey: r.sort_key, + }, + })); + + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + ...(totalInteractions && { + total: { + confirmed: totalInteractions?.rows[0].confirmed, + corrupted: totalInteractions?.rows[0].corrupted, + not_processed: totalInteractions?.rows[0].not_processed, + forked: totalInteractions?.rows[0].forked, + }, + }), + // TODO: this mapping here is kinda dumb. + + interactions: mappedInteractions, + }; + + logger.info('Mapping interactions: ', benchmark.elapsed()); +} diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts new file mode 100644 index 00000000..ea67a60a --- /dev/null +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts @@ -0,0 +1,116 @@ +import Router from '@koa/router'; +import {Benchmark} from 'warp-contracts'; + +const MAX_INTERACTIONS_PER_PAGE = 5000; + +export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { + const {dbSource, logger} = ctx; + + const {contractId, confirmationStatus, page, limit, from, to, totalCount, source, fromSdk} = ctx.query; + + logger.info(`interactionsSortKeyRoute [ip: ${ctx.request?.ip}, contractId: ${contractId}]`); + + const parsedPage = page ? parseInt(page as string) : 1; + + const parsedLimit = limit + ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) + : MAX_INTERACTIONS_PER_PAGE; + const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; + + const parsedConfirmationStatus = confirmationStatus + ? confirmationStatus == 'not_corrupted' + ? ['confirmed', 'not_processed'] + : [confirmationStatus] + : undefined; + + // 'isFromSdk' means that we're making a call from the SDK + // this affects: + // 1. the amount of returned data (we're trying to minimize amount of data in this case) + // 2. sorting order (SDK requires ASC order, SonAR requires DESC order) + const isFromSdk = fromSdk === 'true'; + + const bindings: any[] = []; + bindings.push(contractId); + bindings.push(contractId); + // cannot use IN with bindings https://github.com/knex/knex/issues/791 + // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) + from && bindings.push(from as string); + to && bindings.push(to as string); + source && bindings.push(source as string); + bindings.push(parsedLimit); + bindings.push(offset); + + const query = ` + SELECT interaction, + confirmation_status, + sort_key + ${isFromSdk ? '' : ',confirming_peer, confirmations, bundler_tx_id '} + ${isFromSdk ? '' : ',count(*) OVER () AS total'} + FROM interactions + WHERE (contract_id = ? + OR interact_write @> ARRAY [?]) ${ + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' + } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} + ORDER BY sort_key ${isFromSdk ? 'ASC' : 'DESC'} + LIMIT ? OFFSET ?; + `; + + const result: any = await dbSource.raw(query, bindings); + + const totalInteractions: any = + totalCount == 'true' && + (await dbSource.raw( + ` + SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, + count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, + count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, + count(case when confirmation_status = 'forked' then 1 else null end) AS forked + FROM interactions + WHERE contract_id = ?; + `, + contractId + )); + + const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; + + const benchmark = Benchmark.measure(); + + const mappedInteractions = isFromSdk + ? result?.rows?.map((r: any) => ({ + ...r.interaction, + sortKey: r.sort_key, + confirmationStatus: r.confirmation_status, + })) + : result?.rows?.map((r: any) => ({ + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, + sortKey: r.sort_key, + }, + })); + + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + ...(totalInteractions && { + total: { + confirmed: totalInteractions?.rows[0].confirmed, + corrupted: totalInteractions?.rows[0].corrupted, + not_processed: totalInteractions?.rows[0].not_processed, + forked: totalInteractions?.rows[0].forked, + }, + }), + // TODO: this mapping here is kinda dumb. + interactions: mappedInteractions, + }; +} diff --git a/src/gateway/router/routes/interactionsStreamRoute.ts b/src/gateway/router/routes/interactions/interactionsStreamRoute.ts similarity index 50% rename from src/gateway/router/routes/interactionsStreamRoute.ts rename to src/gateway/router/routes/interactions/interactionsStreamRoute.ts index e1c7fed9..fff83d76 100644 --- a/src/gateway/router/routes/interactionsStreamRoute.ts +++ b/src/gateway/router/routes/interactions/interactionsStreamRoute.ts @@ -1,10 +1,10 @@ import Router from '@koa/router'; -import { stringify } from 'JSONStream'; +import {stringify} from 'JSONStream'; export async function interactionsStreamRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; + const {logger, dbSource} = ctx; - const { contractId, confirmationStatus, from, to } = ctx.query; + const {contractId, confirmationStatus, from, to} = ctx.query; logger.debug('Interactions stream route', { contractId, @@ -24,31 +24,25 @@ export async function interactionsStreamRoute(ctx: Router.RouterContext) { from && bindings.push(from as string); to && bindings.push(to as string); - try { - const result: any = dbSource - .raw( - ` + const result: any = dbSource + .raw( + ` SELECT interaction FROM interactions WHERE contract_id = ? ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' } ${from ? ' AND block_height >= ?' : ''} ${to ? ' AND block_height <= ?' : ''} ORDER BY sort_key ASC; `, - bindings - ) - .stream() // note: https://www.npmjs.com/package/pg-query-stream is required for stream to work - .pipe(stringify()); - - ctx.set('Content-Type', 'application/json; charset=utf-8'); - ctx.set('Transfer-Encoding', 'chunked'); - - ctx.body = result; - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + bindings + ) + .stream() // note: https://www.npmjs.com/package/pg-query-stream is required for stream to work + .pipe(stringify()); + + ctx.set('Content-Type', 'application/json; charset=utf-8'); + ctx.set('Transfer-Encoding', 'chunked'); + + ctx.body = result; } diff --git a/src/gateway/router/routes/interactionsContractGroupsRoute.ts b/src/gateway/router/routes/interactionsContractGroupsRoute.ts deleted file mode 100644 index 63f5cbe7..00000000 --- a/src/gateway/router/routes/interactionsContractGroupsRoute.ts +++ /dev/null @@ -1,172 +0,0 @@ -import Router from '@koa/router'; -import { isTxIdValid } from '../../../utils'; -import { Benchmark } from 'warp-contracts'; -import { DatabaseSource } from '../../../db/databaseSource'; - -const MAX_INTERACTIONS_PER_PAGE = 50000; - -function loadInteractionsForSrcTx( - dbSource: DatabaseSource, - group: string, - fromSortKey: string, - fromBlockHeight: number | null, - limit: number, - offset: number -) { - const bindings: any[] = []; - - const parsedGroup = group.split(','); - - fromSortKey && bindings.push(fromSortKey); - fromBlockHeight && bindings.push(fromBlockHeight); - bindings.push(limit); - bindings.push(offset); - - const query = ` - SELECT c.contract_id as "contractId", - c.block_height as "contractCreation", - c.src_tx_id as "contractSourceId", - (CASE WHEN i.sort_key IS NULL THEN c.init_state END) as "initState", - i.sort_key as "sortKey", - i.interaction as "interaction", - i.confirmation_status as "confirmationStatus" - FROM contracts c - LEFT JOIN interactions i ON c.contract_id = i.contract_id - WHERE c.src_tx_id IN (${parsedGroup.map((group) => `'${group}'`).join(', ')}) - AND ( - (i.sort_key is not null AND i.confirmation_status IN ('confirmed', 'not_processed') - ${fromSortKey ? ' AND i.sort_key > ?' : ''}) - OR (i.sort_key is null ${fromBlockHeight ? ' AND c.block_height >= ?' : ''}) - ) - -- note: there might multiple contracts at same block_height, so to get stable results during pagination - -- - the c.contract_id column is added to sorting - ORDER BY i.sort_key ASC NULLS LAST, c.block_height ASC, c.contract_id ASC - LIMIT ? OFFSET ?; - `; - - return dbSource.raw(query, bindings); -} - -function loadInteractionsForGroup( - dbSource: DatabaseSource, - group: string, - fromSortKey: string, - fromBlockHeight: number | null, - limit: number, - offset: number -) { - const bindings: any[] = []; - if (group != 'all_pst') { - throw new Error(`Unknown group ${group}`); - } - - fromSortKey && bindings.push(fromSortKey); - fromBlockHeight && bindings.push(fromBlockHeight); - bindings.push(limit); - bindings.push(offset); - - const query = ` - SELECT c.contract_id as "contractId", - c.block_height as "contractCreation", - c.src_tx_id as "contractSourceId", - (CASE WHEN i.sort_key IS NULL THEN c.init_state END) as "initState", - i.sort_key as "sortKey", - i.interaction as "interaction", - i.confirmation_status as "confirmationStatus" - FROM contracts c - LEFT JOIN interactions i ON c.contract_id = i.contract_id - JOIN contracts_src s ON s.src_tx_id = c.src_tx_id - WHERE c.type = 'pst' - AND c.content_type = 'application/json' - AND c.contract_id NOT IN ( - 'LkfzZvdl_vfjRXZOPjnov18cGnnK3aDKj0qSQCgkCX8', /* kyve */ - 'l6S4oMyzw_rggjt4yt4LrnRmggHQ2CdM1hna2MK4o_c', /* kyve */ - 'B1SRLyFzWJjeA0ywW41Qu1j7ZpBLHsXSSrWLrT3ebd8', /* kyve */ - 'cETTyJQYxJLVQ6nC3VxzsZf1x2-6TW2LFkGZa91gUWc', /* koi */ - 'QA7AIFVx1KBBmzC7WUNhJbDsHlSJArUT0jWrhZMZPS8', /* koi */ - '8cq1wbjWHNiPg7GwYpoDT2m9HX99LY7tklRQWfh1L6c', /* kyve */ - 'NwaSMGCdz6Yu5vNjlMtCNBmfEkjYfT-dfYkbQQDGn5s', /* koi */ - 'qzVAzvhwr1JFTPE8lIU9ZG_fuihOmBr7ewZFcT3lIUc', /* koi */ - 'OFD4GqQcqp-Y_Iqh8DN_0s3a_68oMvvnekeOEu_a45I', /* kyve */ - 'CdPAQNONoR83Shj3CbI_9seC-LqgI1oLaRJhSwP90-o', /* koi */ - 'dNXaqE_eATp2SRvyFjydcIPHbsXAe9UT-Fktcqs7MDk' /* kyve */) - AND c.src_tx_id NOT IN ('Qa7IR-xvPkBtcYUBZXd8z-Tu611VeJH33uEA5XiFUNA') /* Hoh */ - AND ( - (i.sort_key is not null AND i.confirmation_status IN ('confirmed', 'not_processed') - ${fromSortKey ? ' AND i.sort_key > ?' : ''}) - OR (i.sort_key is null ${fromBlockHeight ? ' AND c.block_height >= ?' : ''}) - ) - AND ((s.src_content_type = 'application/javascript' - AND (s.src NOT LIKE '%readContractState%' AND s.src NOT LIKE '%unsafeClient%')) - OR s.src_content_type = 'application/wasm') - -- note: there might multiple contracts at same block_height, so to get stable results during pagination - -- - the c.contract_id column is added to sorting - ORDER BY i.sort_key ASC NULLS LAST, c.block_height ASC, c.contract_id ASC - LIMIT ? OFFSET ?; - `; - - return dbSource.raw(query, bindings); -} - -export async function interactionsContractGroupsRoute(ctx: Router.RouterContext) { - const { dbSource, logger } = ctx; - const { group, fromSortKey, fromBlockHeight, page, limit } = ctx.query; - const parsedPage = page ? parseInt(page as string) : 1; - const parsedLimit = limit - ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) - : MAX_INTERACTIONS_PER_PAGE; - const offset = (parsedPage - 1) * parsedLimit; - const parsedGroup = group as string; - const parsedBlockHeight = fromBlockHeight ? parseInt(fromBlockHeight as string) : null; - - let result; - - try { - const benchmark = Benchmark.measure(); - result = isTxIdValid(parsedGroup) - ? await loadInteractionsForSrcTx( - dbSource, - parsedGroup, - fromSortKey as string, - parsedBlockHeight, - parsedLimit, - offset - ) - : await loadInteractionsForGroup( - dbSource, - parsedGroup, - fromSortKey as string, - parsedBlockHeight, - parsedLimit, - offset - ); - - logger.info(`Loading contract groups interactions: ${benchmark.elapsed()}`); - - const interactions = []; - for (let row of result?.rows) { - interactions.push({ - contractId: row.contractId, - ...row.interaction, - confirmationStatus: row.confirmationStatus, - sortKey: row.sortKey, - contractCreation: row.contractCreation, - initState: row.initState, - contractSourceId: row.contractSourceId, - }); - } - - ctx.body = { - paging: { - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - }, - interactions, - }; - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/interactionsRoute.ts b/src/gateway/router/routes/interactionsRoute.ts deleted file mode 100644 index 5bd72dc4..00000000 --- a/src/gateway/router/routes/interactionsRoute.ts +++ /dev/null @@ -1,120 +0,0 @@ -import Router from '@koa/router'; - -const MAX_INTERACTIONS_PER_PAGE = 5000; - -export async function interactionsRoute(ctx: Router.RouterContext) { - const { dbSource } = ctx; - - const { contractId, confirmationStatus, page, limit, from, to, totalCount, source, upToTransactionId, minimize } = - ctx.query; - - const parsedPage = page ? parseInt(page as string) : 1; - - const parsedLimit = limit - ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) - : MAX_INTERACTIONS_PER_PAGE; - const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; - - const parsedConfirmationStatus = confirmationStatus - ? confirmationStatus == 'not_corrupted' - ? ['confirmed', 'not_processed'] - : [confirmationStatus] - : undefined; - - const shouldMinimize = minimize === 'true'; - - const bindings: any[] = []; - bindings.push(contractId); - bindings.push(contractId); - // cannot use IN with bindings https://github.com/knex/knex/issues/791 - // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) - from && bindings.push(from as string); - to && bindings.push(to as string); - source && bindings.push(source as string); - upToTransactionId && bindings.push(upToTransactionId as string); - parsedPage && bindings.push(parsedLimit); - parsedPage && bindings.push(offset); - - try { - const result: any = await dbSource.raw( - ` - SELECT interaction, - confirmation_status - ${shouldMinimize ? '' : ',confirming_peer, confirmations, bundler_tx_id '} - ${shouldMinimize ? '' : ',count(*) OVER () AS total'} - FROM interactions - WHERE (contract_id = ? OR interact_write @> ARRAY[?]) - ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' - } - ${from ? ' AND block_height >= ?' : ''} - ${to ? ' AND block_height <= ?' : ''} - ${source ? `AND source = ?` : ''} - ${upToTransactionId ? `AND id <= (SELECT id FROM interactions WHERE interaction_id = ?)` : ''} - ORDER BY block_height ${shouldMinimize ? 'ASC' : 'DESC'}, interaction_id DESC ${ - parsedPage ? ' LIMIT ? OFFSET ?' : '' - }; - `, - bindings - ); - - const totalInteractions: any = - totalCount == 'true' && - (await dbSource.raw( - ` - SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, - count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, - count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, - count(case when confirmation_status = 'forked' then 1 else null end) AS forked - FROM interactions - WHERE contract_id = ?; - `, - contractId - )); - - const total = result?.rows?.length > 0 ? result?.rows[0].total : 0; - - const mappedInteractions = shouldMinimize - ? result?.rows?.map((r: any) => ({ - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - }, - confirmationStatus: r.confirmation_status, - })) - : result?.rows?.map((r: any) => ({ - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - }, - })); - - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - ...(totalInteractions && { - total: { - confirmed: totalInteractions?.rows[0].confirmed, - corrupted: totalInteractions?.rows[0].corrupted, - not_processed: totalInteractions?.rows[0].not_processed, - forked: totalInteractions?.rows[0].forked, - }, - }), - interactions: mappedInteractions, - }; - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/interactionsSonar.ts b/src/gateway/router/routes/interactionsSonar.ts deleted file mode 100644 index 5fff2efc..00000000 --- a/src/gateway/router/routes/interactionsSonar.ts +++ /dev/null @@ -1,110 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -const MAX_INTERACTIONS_PER_PAGE = 5000; - -export async function interactionsSonar(ctx: Router.RouterContext) { - const { dbSource, logger } = ctx; - - const { contractId, confirmationStatus, page, limit, from, to, source } = ctx.query; - - const parsedPage = page ? parseInt(page as string) : 1; - - const parsedLimit = limit - ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) - : MAX_INTERACTIONS_PER_PAGE; - const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; - - const parsedConfirmationStatus = confirmationStatus - ? confirmationStatus == 'not_corrupted' - ? ['confirmed', 'not_processed'] - : [confirmationStatus] - : undefined; - - const bindings: any[] = []; - bindings.push(contractId); - bindings.push(contractId); - from && bindings.push(from as string); - to && bindings.push(to as string); - source && bindings.push(source as string); - parsedPage && bindings.push(parsedLimit); - parsedPage && bindings.push(offset); - - try { - const query = ` - SELECT interaction, - confirmation_status, - sort_key, - confirming_peer, - confirmations, - bundler_tx_id - FROM interactions - WHERE (contract_id = ? OR interact_write @> ARRAY[?]) - ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' - } - ${from ? ' AND sort_key > ?' : ''} - ${to ? ' AND sort_key <= ?' : ''} - ${source ? `AND source = ?` : ''} - ORDER BY sort_key DESC ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; - `; - - const result: any = await dbSource.raw(query, bindings); - - const totalInteractions: any = await dbSource.raw( - ` - SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, - count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, - count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, - count(case when confirmation_status = 'forked' then 1 else null end) AS forked - FROM interactions - WHERE (contract_id = ? OR interact_write @> ARRAY[?]); - `, - [contractId, contractId] - ); - - const total = - parseInt(totalInteractions.rows[0].confirmed) + - parseInt(totalInteractions.rows[0].corrupted) + - parseInt(totalInteractions.rows[0].not_processed) + - parseInt(totalInteractions.rows[0].forked); - - const benchmark = Benchmark.measure(); - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - ...(totalInteractions && { - total: { - confirmed: totalInteractions.rows[0].confirmed, - corrupted: totalInteractions.rows[0].corrupted, - not_processed: totalInteractions.rows[0].not_processed, - forked: totalInteractions.rows[0].forked, - }, - }), - - interactions: result?.rows?.map((r: any) => ({ - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - sortKey: r.sort_key, - }, - })), - }; - - logger.info('Mapping interactions: ', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/interactionsSortKeyRoute.ts b/src/gateway/router/routes/interactionsSortKeyRoute.ts deleted file mode 100644 index 0e829aa4..00000000 --- a/src/gateway/router/routes/interactionsSortKeyRoute.ts +++ /dev/null @@ -1,124 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -const MAX_INTERACTIONS_PER_PAGE = 5000; - -export async function interactionsSortKeyRoute(ctx: Router.RouterContext) { - const { dbSource, logger } = ctx; - - const { contractId, confirmationStatus, page, limit, from, to, totalCount, source, minimize } = ctx.query; - - const parsedPage = page ? parseInt(page as string) : 1; - - const parsedLimit = limit - ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) - : MAX_INTERACTIONS_PER_PAGE; - const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; - - const parsedConfirmationStatus = confirmationStatus - ? confirmationStatus == 'not_corrupted' - ? ['confirmed', 'not_processed'] - : [confirmationStatus] - : undefined; - - // 'should minimize' means that we're making a call from the SDK - // this affects: - // 1. the amount of returned data (we're trying to minimize amount of data in this case) - // 2. sorting order (SDK requires ASC order, SonAR requires DESC order) - const shouldMinimize = minimize === 'true'; - - const bindings: any[] = []; - bindings.push(contractId); - bindings.push(contractId); - // cannot use IN with bindings https://github.com/knex/knex/issues/791 - // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) - from && bindings.push(from as string); - to && bindings.push(to as string); - source && bindings.push(source as string); - parsedPage && bindings.push(parsedLimit); - parsedPage && bindings.push(offset); - - try { - const query = ` - SELECT interaction, - confirmation_status, - sort_key - ${shouldMinimize ? '' : ',confirming_peer, confirmations, bundler_tx_id '} - ${shouldMinimize ? '' : ',count(*) OVER () AS total'} - FROM interactions - WHERE (contract_id = ? OR interact_write @> ARRAY[?]) - ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' - } - ${from ? ' AND sort_key > ?' : ''} - ${to ? ' AND sort_key <= ?' : ''} - ${source ? `AND source = ?` : ''} - ORDER BY sort_key ${shouldMinimize ? 'ASC' : 'DESC'} ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; - `; - - const result: any = await dbSource.raw(query, bindings); - - const totalInteractions: any = - totalCount == 'true' && - (await dbSource.raw( - ` - SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, - count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, - count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, - count(case when confirmation_status = 'forked' then 1 else null end) AS forked - FROM interactions - WHERE contract_id = ?; - `, - contractId - )); - - const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; - - const benchmark = Benchmark.measure(); - const mappedInteractions = shouldMinimize - ? result?.rows?.map((r: any) => ({ - ...r.interaction, - sortKey: r.sort_key, - confirmationStatus: r.confirmation_status, - })) - : result?.rows?.map((r: any) => ({ - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - sortKey: r.sort_key, - }, - })); - - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - ...(totalInteractions && { - total: { - confirmed: totalInteractions?.rows[0].confirmed, - corrupted: totalInteractions?.rows[0].corrupted, - not_processed: totalInteractions?.rows[0].not_processed, - forked: totalInteractions?.rows[0].forked, - }, - }), - // TODO: this mapping here is kinda dumb. - - interactions: mappedInteractions, - }; - - logger.info('Mapping interactions: ', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/interactionsSortKeyRoute_v2.ts b/src/gateway/router/routes/interactionsSortKeyRoute_v2.ts deleted file mode 100644 index 07145318..00000000 --- a/src/gateway/router/routes/interactionsSortKeyRoute_v2.ts +++ /dev/null @@ -1,122 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -const MAX_INTERACTIONS_PER_PAGE = 5000; - -export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { - const { dbSource, logger } = ctx; - - const { contractId, confirmationStatus, page, limit, from, to, totalCount, source, fromSdk } = ctx.query; - - logger.info(`interactionsSortKeyRoute [ip: ${ctx.request?.ip}, contractId: ${contractId}]`); - - const parsedPage = page ? parseInt(page as string) : 1; - - const parsedLimit = limit - ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) - : MAX_INTERACTIONS_PER_PAGE; - const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; - - const parsedConfirmationStatus = confirmationStatus - ? confirmationStatus == 'not_corrupted' - ? ['confirmed', 'not_processed'] - : [confirmationStatus] - : undefined; - - // 'isFromSdk' means that we're making a call from the SDK - // this affects: - // 1. the amount of returned data (we're trying to minimize amount of data in this case) - // 2. sorting order (SDK requires ASC order, SonAR requires DESC order) - const isFromSdk = fromSdk === 'true'; - - const bindings: any[] = []; - bindings.push(contractId); - bindings.push(contractId); - // cannot use IN with bindings https://github.com/knex/knex/issues/791 - // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) - from && bindings.push(from as string); - to && bindings.push(to as string); - source && bindings.push(source as string); - bindings.push(parsedLimit); - bindings.push(offset); - - try { - const query = ` - SELECT interaction, - confirmation_status, - sort_key - ${isFromSdk ? '' : ',confirming_peer, confirmations, bundler_tx_id '} - ${isFromSdk ? '' : ',count(*) OVER () AS total'} - FROM interactions - WHERE (contract_id = ? - OR interact_write @> ARRAY [?]) ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' - } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} - ORDER BY sort_key ${isFromSdk ? 'ASC' : 'DESC'} - LIMIT ? OFFSET ?; - `; - - const result: any = await dbSource.raw(query, bindings); - - const totalInteractions: any = - totalCount == 'true' && - (await dbSource.raw( - ` - SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, - count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, - count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, - count(case when confirmation_status = 'forked' then 1 else null end) AS forked - FROM interactions - WHERE contract_id = ?; - `, - contractId - )); - - const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; - - const benchmark = Benchmark.measure(); - - const mappedInteractions = isFromSdk - ? result?.rows?.map((r: any) => ({ - ...r.interaction, - sortKey: r.sort_key, - confirmationStatus: r.confirmation_status, - })) - : result?.rows?.map((r: any) => ({ - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - sortKey: r.sort_key, - }, - })); - - ctx.body = { - paging: { - total, - limit: parsedLimit, - items: result?.rows.length, - page: parsedPage, - pages: Math.ceil(total / parsedLimit), - }, - ...(totalInteractions && { - total: { - confirmed: totalInteractions?.rows[0].confirmed, - corrupted: totalInteractions?.rows[0].corrupted, - not_processed: totalInteractions?.rows[0].not_processed, - forked: totalInteractions?.rows[0].forked, - }, - }), - // TODO: this mapping here is kinda dumb. - interactions: mappedInteractions, - }; - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/nftsOwnedByAddressRoute.ts b/src/gateway/router/routes/nftsOwnedByAddressRoute.ts index a99b2d89..9636d379 100644 --- a/src/gateway/router/routes/nftsOwnedByAddressRoute.ts +++ b/src/gateway/router/routes/nftsOwnedByAddressRoute.ts @@ -1,6 +1,7 @@ import Router from '@koa/router'; import { Benchmark } from 'warp-contracts'; import { isTxIdValid } from '../../../utils'; +import {GatewayError} from "../../errorHandlerMiddleware"; export async function nftsOwnedByAddressRoute(ctx: Router.RouterContext) { const { logger, dbSource } = ctx; @@ -8,38 +9,28 @@ export async function nftsOwnedByAddressRoute(ctx: Router.RouterContext) { const { address } = ctx.params; if (!isTxIdValid(address)) { - ctx.status = 500; - ctx.body = { message: 'Wrong wallet address format.' }; - return; + throw new GatewayError('Wrong wallet address format.', 412); } const { srcTxId } = ctx.query; if (!isTxIdValid(srcTxId as string)) { - ctx.status = 500; - ctx.body = { message: 'Wrong src tx id address format.' }; - return; + throw new GatewayError('Wrong src tx id address format.', 412); } - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - WITH wallet_balances AS ( - SELECT contract_id as contract, - init_state->'ticker' AS ticker, - init_state->'name' AS name, - (init_state->'balances'->?)::integer AS balance - FROM contracts - WHERE src_tx_id = ?) - SELECT * from wallet_balances WHERE balance = 1; - `, - [address, srcTxId] - ); - ctx.body = result?.rows; - logger.debug('Nfts ownership loaded', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + WITH wallet_balances AS ( + SELECT contract_id as contract, + init_state->'ticker' AS ticker, + init_state->'name' AS name, + (init_state->'balances'->?)::integer AS balance + FROM contracts + WHERE src_tx_id = ?) + SELECT * from wallet_balances WHERE balance = 1; + `, + [address, srcTxId] + ); + ctx.body = result?.rows; + logger.debug('Nfts ownership loaded', benchmark.elapsed()); } diff --git a/src/gateway/router/routes/safeContractsRoute.ts b/src/gateway/router/routes/safeContractsRoute.ts deleted file mode 100644 index cd3d04d9..00000000 --- a/src/gateway/router/routes/safeContractsRoute.ts +++ /dev/null @@ -1,31 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -export async function safeContractsRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT i.contract_id, count(i) AS interactions - FROM contracts c - JOIN interactions i ON i.contract_id = c.contract_id - JOIN contracts_src s ON s.src_tx_id = c.src_tx_id - WHERE - (s.src_content_type = 'application/javascript' - AND (s.src NOT LIKE '%readContractState%' AND s.src NOT LIKE '%unsafeClient%')) - OR s.src_content_type = 'application/wasm' - GROUP BY i.contract_id - HAVING count(i) < 20000 AND count(i) >= 1 - ORDER BY count(i) DESC; - ` - ); - ctx.body = result?.rows; - logger.debug('Safe contracts loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } -} diff --git a/src/gateway/router/routes/searchRoute.ts b/src/gateway/router/routes/searchRoute.ts index 691c2312..60dee5df 100644 --- a/src/gateway/router/routes/searchRoute.ts +++ b/src/gateway/router/routes/searchRoute.ts @@ -19,24 +19,18 @@ export async function searchRoute(ctx: Router.RouterContext) { const isEthWallet = utils.isAddress(phrase); const validTs = isTxIdValid(phrase); - try { - const benchmark = Benchmark.measure(); - let result: any; - if (isEthWallet) { - result = await fetchCreatorOnly(dbSource, phrase); - } else if (validTs) { - result = await fetchTransaction(dbSource, phrase, testnet); - } else { - result = await fetchPst(dbSource, phrase, testnet); - } - - ctx.body = result?.rows; - logger.debug('Contracts loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; + const benchmark = Benchmark.measure(); + let result: any; + if (isEthWallet) { + result = await fetchCreatorOnly(dbSource, phrase); + } else if (validTs) { + result = await fetchTransaction(dbSource, phrase, testnet); + } else { + result = await fetchPst(dbSource, phrase, testnet); } + + ctx.body = result?.rows; + logger.debug('Contracts loaded in', benchmark.elapsed()); } async function fetchCreatorOnly(dbSource: DatabaseSource, wallet: string) { diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 1ffcdbef..ce9c2298 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -7,12 +7,13 @@ import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger } fr import { getCachedNetworkData } from '../../tasks/networkInfoCache'; import Bundlr from '@bundlr-network/client'; import { BlockData } from 'arweave/node/blocks'; -import { VRF } from '../../init'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { publishInteraction, sendNotification } from '../../publisher'; import { Knex } from 'knex'; import { InteractionInsert } from '../../../db/insertInterfaces'; +import {GatewayError} from "../../errorHandlerMiddleware"; +import {VRF} from "../../init"; const { Evaluate } = require('@idena/vrf-js'); @@ -113,15 +114,12 @@ export async function sequencerRoute(ctx: Router.RouterContext) { contractLastSortKey ); - let verified = false; - if (isEvmSigner) { - verified = await signatureVerification.process(interaction); - } else { - verified = await arweave.transactions.verify(transaction); - } + const verified = isEvmSigner + ? await signatureVerification.process(interaction) + : await arweave.transactions.verify(transaction); if (!verified) { - throw new Error('Naughty boy (interaction)!'); + throw new Error('Transaction could not be verified - is it properly signed?'); } else { sLogger.info('Transaction verified properly'); } @@ -197,14 +195,11 @@ export async function sequencerRoute(ctx: Router.RouterContext) { millis, testnetVersion ); - } catch (e) { + } catch (e: any) { if (!trx.isCompleted()) { await trx.rollback(); } - sLogger.error('Error while inserting bundled transaction'); - sLogger.error(e); - ctx.status = 500; - ctx.body = { message: e }; + throw new GatewayError(e?.message || e) } } diff --git a/src/gateway/router/routes/stats/totalTxsRoute.ts b/src/gateway/router/routes/stats/totalTxsRoute.ts index 235d1f52..1bd31354 100644 --- a/src/gateway/router/routes/stats/totalTxsRoute.ts +++ b/src/gateway/router/routes/stats/totalTxsRoute.ts @@ -1,32 +1,27 @@ import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; +import {Benchmark} from 'warp-contracts'; export async function totalTxsRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - const { testnet } = ctx.query; + const {logger, dbSource} = ctx; + const {testnet} = ctx.query; - try { - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` - SELECT 1 AS sort_order, count(i.id) AS total - FROM interactions i - ${testnet ? ' WHERE i.testnet IS NOT NULL' : ''} - UNION - SELECT 2 AS sort_order, count(c.contract_id) AS total - FROM contracts c WHERE c.type != 'error' ${testnet ? ' AND c.testnet IS NOT NULL' : ''} - ORDER BY sort_order; - ` - ); - ctx.body = { - total_interactions: result?.rows[0].total, - total_contracts: result?.rows[1].total, - }; + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT 1 AS sort_order, count(i.id) AS total + FROM interactions i + ${testnet ? ' WHERE i.testnet IS NOT NULL' : ''} + UNION + SELECT 2 AS sort_order, count(c.contract_id) AS total + FROM contracts c + WHERE c.type != 'error' ${testnet ? ' AND c.testnet IS NOT NULL' : ''} + ORDER BY sort_order; + ` + ); + ctx.body = { + total_interactions: result?.rows[0].total, + total_contracts: result?.rows[1].total, + }; - logger.debug('Stats loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + logger.debug('Stats loaded in', benchmark.elapsed()); } diff --git a/src/gateway/router/routes/stats/txsPerDayRoute.ts b/src/gateway/router/routes/stats/txsPerDayRoute.ts index 7f222911..016150aa 100644 --- a/src/gateway/router/routes/stats/txsPerDayRoute.ts +++ b/src/gateway/router/routes/stats/txsPerDayRoute.ts @@ -1,44 +1,38 @@ import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; +import {Benchmark} from 'warp-contracts'; export async function txsPerDayRoute(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - const { testnet } = ctx.query; + const {logger, dbSource} = ctx; + const {testnet} = ctx.query; - try { - const benchmark = Benchmark.measure(); - const contracts: any = await dbSource.raw( - ` - WITH contracts_per_day AS ( - SELECT date(to_timestamp((block_timestamp)::integer)) as date, contract_id as interaction - FROM contracts - WHERE testnet ${testnet ? ' IS NOT NULL' : ' IS NULL'} - ) - SELECT date, count(*) as per_day FROM contracts_per_day + const benchmark = Benchmark.measure(); + const contracts: any = await dbSource.raw( + ` + WITH contracts_per_day AS (SELECT date(to_timestamp((block_timestamp)::integer)) as date, + contract_id as interaction + FROM contracts + WHERE testnet ${testnet ? ' IS NOT NULL' : ' IS NULL'}) + SELECT date, count(*) as per_day + FROM contracts_per_day GROUP BY date ORDER BY date ASC; - ` - ); - const interactions: any = await dbSource.raw( - ` - WITH transactions_per_day AS ( - SELECT date(to_timestamp((block_timestamp)::integer)) as date, interaction_id as interaction - FROM interactions - WHERE testnet ${testnet ? ' IS NOT NULL' : ' IS NULL'} - ) - SELECT date, count(*) as per_day FROM transactions_per_day + ` + ); + const interactions: any = await dbSource.raw( + ` + WITH transactions_per_day AS (SELECT date(to_timestamp((block_timestamp)::integer)) as date, + interaction_id as interaction + FROM interactions + WHERE testnet ${testnet ? ' IS NOT NULL' : ' IS NULL'}) + SELECT date, count(*) as per_day + FROM transactions_per_day GROUP BY date ORDER BY date ASC; - ` - ); - ctx.body = { - contracts_per_day: contracts.rows, - interactions_per_day: interactions.rows, - }; - logger.debug('Contracts stats loaded in', benchmark.elapsed()); - } catch (e: any) { - ctx.logger.error(e); - ctx.status = 500; - ctx.body = { message: e }; - } + ` + ); + ctx.body = { + contracts_per_day: contracts.rows, + interactions_per_day: interactions.rows, + }; + logger.debug('Contracts stats loaded in', benchmark.elapsed()); } diff --git a/src/gateway/runGatewayTasks.ts b/src/gateway/runGatewayTasks.ts index 251a2cad..cc8f9cfd 100644 --- a/src/gateway/runGatewayTasks.ts +++ b/src/gateway/runGatewayTasks.ts @@ -2,7 +2,6 @@ import { runLoadPeersTask } from './tasks/loadPeers'; import { runVerifyInteractionsTask } from './tasks/verifyInteractions'; import { runVerifyCorruptedTransactionsTask } from './tasks/verifyCorruptedTransactions'; import { - runSyncLastSixHoursTransactionsTask, runSyncLastHourTransactionsTask, runSyncRecentTransactionsTask, } from './tasks/syncTransactions'; diff --git a/yarn.lock b/yarn.lock index 1f7586bd..83de8e6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1667,89 +1667,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@opencensus/core@0.0.9": - version "0.0.9" - resolved "https://registry.yarnpkg.com/@opencensus/core/-/core-0.0.9.tgz#b16f775435ee309433e4126af194d37313fc93b3" - integrity sha512-31Q4VWtbzXpVUd2m9JS6HEaPjlKvNMOiF7lWKNmXF84yUcgfAFL5re7/hjDmdyQbOp32oGc+RFV78jXIldVz6Q== - dependencies: - continuation-local-storage "^3.2.1" - log-driver "^1.2.7" - semver "^5.5.0" - shimmer "^1.2.0" - uuid "^3.2.1" - -"@opencensus/core@^0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@opencensus/core/-/core-0.0.8.tgz#df01f200c2d2fbfe14dae129a1a86fb87286db92" - integrity sha512-yUFT59SFhGMYQgX0PhoTR0LBff2BEhPrD9io1jWfF/VDbakRfs6Pq60rjv0Z7iaTav5gQlttJCX2+VPxFWCuoQ== - dependencies: - continuation-local-storage "^3.2.1" - log-driver "^1.2.7" - semver "^5.5.0" - shimmer "^1.2.0" - uuid "^3.2.1" - -"@opencensus/propagation-b3@0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@opencensus/propagation-b3/-/propagation-b3-0.0.8.tgz#0751e6fd75f09400d9d3c419001e9e15a0df68e9" - integrity sha512-PffXX2AL8Sh0VHQ52jJC4u3T0H6wDK6N/4bg7xh4ngMYOIi13aR1kzVvX1sVDBgfGwDOkMbl4c54Xm3tlPx/+A== - dependencies: - "@opencensus/core" "^0.0.8" - uuid "^3.2.1" - -"@pm2/agent@~2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@pm2/agent/-/agent-2.0.1.tgz#0edffc54cd8ee2b12f90136264e7880f3f78c79d" - integrity sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw== - dependencies: - async "~3.2.0" - chalk "~3.0.0" - dayjs "~1.8.24" - debug "~4.3.1" - eventemitter2 "~5.0.1" - fast-json-patch "^3.0.0-1" - fclone "~1.0.11" - nssocket "0.6.0" - pm2-axon "~4.0.1" - pm2-axon-rpc "~0.7.0" - proxy-agent "~5.0.0" - semver "~7.2.0" - ws "~7.4.0" - -"@pm2/io@~5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@pm2/io/-/io-5.0.0.tgz#623cbcaf6fe39375f20ac2e75497477a1b1ec5c5" - integrity sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw== - dependencies: - "@opencensus/core" "0.0.9" - "@opencensus/propagation-b3" "0.0.8" - async "~2.6.1" - debug "~4.3.1" - eventemitter2 "^6.3.1" - require-in-the-middle "^5.0.0" - semver "6.3.0" - shimmer "^1.2.0" - signal-exit "^3.0.3" - tslib "1.9.3" - -"@pm2/js-api@~0.6.7": - version "0.6.7" - resolved "https://registry.yarnpkg.com/@pm2/js-api/-/js-api-0.6.7.tgz#ed28c3b7b6d26f03f826318754fdc5468afa589f" - integrity sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw== - dependencies: - async "^2.6.3" - axios "^0.21.0" - debug "~4.3.1" - eventemitter2 "^6.3.1" - ws "^7.0.0" - -"@pm2/pm2-version-check@latest": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz#cf97fbb14b0eca95430ca05eedccbd2683806e43" - integrity sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA== - dependencies: - debug "^4.3.1" - "@randlabs/communication-bridge@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@randlabs/communication-bridge/-/communication-bridge-1.0.1.tgz#d1ecfc29157afcbb0ca2d73122d67905eecb5bf3" @@ -2310,7 +2227,7 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: +agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -2359,18 +2276,6 @@ amazon-cognito-identity-js@5.2.12: isomorphic-unfetch "^3.0.0" js-cookie "^2.2.1" -amp-message@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/amp-message/-/amp-message-0.1.2.tgz#a78f1c98995087ad36192a41298e4db49e3dfc45" - integrity sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg== - dependencies: - amp "0.3.1" - -amp@0.3.1, amp@~0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/amp/-/amp-0.3.1.tgz#6adf8d58a74f361e82c1fa8d389c079e139fc47d" - integrity sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw== - ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" @@ -2417,7 +2322,7 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -anymatch@^3.0.3, anymatch@~3.1.1, anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@~3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2558,21 +2463,6 @@ asn1.js@^5.4.1: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" -ast-types@^0.13.2: - version "0.13.4" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" - integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== - dependencies: - tslib "^2.0.1" - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - async-retry@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" @@ -2580,14 +2470,7 @@ async-retry@^1.3.3: dependencies: retry "0.13.1" -async@^2.6.3, async@~2.6.1: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - -async@^3.2.0, async@^3.2.3, async@~3.2.0: +async@^3.2.3: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== @@ -2650,7 +2533,7 @@ axios@0.27.2, axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axios@^0.21.0, axios@^0.21.3: +axios@^0.21.3: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== @@ -2783,11 +2666,6 @@ bindings@^1.3.0: dependencies: file-uri-to-path "1.0.0" -bintrees@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" - integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== - bip39-light@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/bip39-light/-/bip39-light-1.0.7.tgz#06a72f251b89389a136d3f177f29b03342adc5ba" @@ -2815,16 +2693,6 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -blessed@0.1.81: - version "0.1.81" - resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129" - integrity sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ== - -bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - bn.js@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" @@ -2840,11 +2708,6 @@ bn.js@^5.0.0, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -bodec@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/bodec/-/bodec-0.1.0.tgz#bc851555430f23c9f7650a75ef64c6a94c3418cc" - integrity sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ== - borsh@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.6.0.tgz#a7c9eeca6a31ca9e0607cb49f329cb659eb791e1" @@ -3073,14 +2936,6 @@ catering@^2.1.0, catering@^2.1.1: resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== -chalk@3.0.0, chalk@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3113,11 +2968,6 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -charm@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296" - integrity sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ== - chokidar@3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" @@ -3133,21 +2983,6 @@ chokidar@3.5.1: optionalDependencies: fsevents "~2.3.1" -chokidar@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - ci-info@^3.2.0: version "3.6.2" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.6.2.tgz#362ea15378f1c39378ba786affbc1c9ef015ecfd" @@ -3205,13 +3040,6 @@ cli-table@0.3.11: dependencies: colors "1.0.3" -cli-tableau@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cli-tableau/-/cli-tableau-2.0.1.tgz#baa78d83e08a2d7ab79b7dad9406f0254977053f" - integrity sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ== - dependencies: - chalk "3.0.0" - cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" @@ -3307,11 +3135,6 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== - commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -3361,14 +3184,6 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" @@ -3438,11 +3253,6 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -croner@~4.1.92: - version "4.1.97" - resolved "https://registry.yarnpkg.com/croner/-/croner-4.1.97.tgz#6e373dc7bb3026fab2deb0d82685feef20796766" - integrity sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ== - cross-argv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/cross-argv/-/cross-argv-2.0.0.tgz#2e7907ba3246f82c967623a3e8525925bbd6c0ad" @@ -3518,16 +3328,6 @@ csv@^6.0.5: csv-stringify "^6.2.2" stream-transform "^3.2.1" -culvert@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/culvert/-/culvert-0.1.2.tgz#9502f5f0154a2d5a22a023e79f71cc936fa6ef6f" - integrity sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg== - -data-uri-to-buffer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" - integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== - data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -3537,22 +3337,7 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -date-fns@^2.29.3: - version "2.29.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" - integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== - -dayjs@~1.11.5: - version "1.11.7" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" - integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== - -dayjs@~1.8.24: - version "1.8.36" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50" - integrity sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw== - -debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1: +debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3566,13 +3351,6 @@ debug@4.3.1: dependencies: ms "2.1.2" -debug@^3.2.6: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" @@ -3610,16 +3388,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -degenerator@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.2.tgz#6a61fcc42a702d6e50ff6023fe17bff435f68235" - integrity sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ== - dependencies: - ast-types "^0.13.2" - escodegen "^1.8.1" - esprima "^4.0.0" - vm2 "^3.9.8" - delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" @@ -3729,13 +3497,6 @@ elliptic@6.5.4, elliptic@^6.5.3, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emittery@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" @@ -3758,7 +3519,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: dependencies: once "^1.4.0" -enquirer@2.3.6, enquirer@^2.3.5: +enquirer@^2.3.5: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -3818,18 +3579,6 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.8.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - escodegen@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" @@ -3952,7 +3701,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -4010,21 +3759,6 @@ ethers@^5.5.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -eventemitter2@5.0.1, eventemitter2@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452" - integrity sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg== - -eventemitter2@^6.3.1: - version "6.4.9" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" - integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== - -eventemitter2@~0.4.14: - version "0.4.14" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" - integrity sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ== - eventemitter3@^4.0.0, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -4122,11 +3856,6 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-patch@^3.0.0-1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.1.1.tgz#85064ea1b1ebf97a3f7ad01e23f9337e72c66947" - integrity sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ== - fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -4161,11 +3890,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fclone@1.0.11, fclone@~1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640" - integrity sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw== - figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -4185,11 +3909,6 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -file-uri-to-path@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" - integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -4271,33 +3990,16 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.1, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -ftp@^0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - integrity sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ== - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -4337,34 +4039,12 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-uri@3: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" - integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== - dependencies: - "@tootallnate/once" "1" - data-uri-to-buffer "3" - debug "4" - file-uri-to-path "2" - fs-extra "^8.1.0" - ftp "^0.3.10" - getopts@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA== -git-node-fs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/git-node-fs/-/git-node-fs-1.0.0.tgz#49b215e242ebe43aa4c7561bbba499521752080f" - integrity sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ== - -git-sha1@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/git-sha1/-/git-sha1-0.1.2.tgz#599ac192b71875825e13a445f3a6e05118c2f745" - integrity sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg== - -glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4390,7 +4070,7 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4433,11 +4113,6 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.6: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -4584,7 +4259,7 @@ http-parser-js@^0.5.2: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== -http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: +http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== @@ -4593,7 +4268,7 @@ http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: agent-base "6" debug "4" -https-proxy-agent@5, https-proxy-agent@^5.0.0: +https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -4614,7 +4289,7 @@ hyperid@^3.0.0: uuid "^8.3.2" uuid-parse "^1.1.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4670,16 +4345,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - inquirer@^8.2.0: version "8.2.5" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" @@ -4721,16 +4391,6 @@ ioredis@^5.2.4: redis-parser "^3.0.0" standard-as-callback "^2.1.0" -ip@^1.1.5: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" - integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== - -ip@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" - integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== - is-arguments@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -4848,11 +4508,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5347,16 +5002,6 @@ js-cookie@^2.2.1: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== -js-git@^0.7.8: - version "0.7.8" - resolved "https://registry.yarnpkg.com/js-git/-/js-git-0.7.8.tgz#52fa655ab61877d6f1079efc6534b554f31e5444" - integrity sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA== - dependencies: - bodec "^0.1.0" - culvert "^0.1.2" - git-sha1 "^0.1.2" - pako "^0.2.5" - js-sha256@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" @@ -5492,13 +5137,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -5545,10 +5183,10 @@ knex@2.4.2: tarn "^3.0.2" tildify "2.0.0" -koa-bodyparser@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.3.0.tgz#274c778555ff48fa221ee7f36a9fbdbace22759a" - integrity sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw== +koa-bodyparser@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.4.0.tgz#2271cd7d603a08c47a47e82d2c00630379672e6c" + integrity sha512-AXPY7wwKZUmbgb8VkTEUFoRNOlx6aWRJwEnQD+zfNf33/7KSAkN4Oo9BqlIk80D+5TvuqlhpQT5dPVcyxl5Zsw== dependencies: co-body "^6.0.0" copy-to "^2.0.1" @@ -5611,11 +5249,6 @@ koa@2.14.1: type-is "^1.6.16" vary "^1.1.2" -lazy@~1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" - integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== - lazystream@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" @@ -5742,16 +5375,11 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== -lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-driver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" - integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== - log-symbols@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" @@ -5767,13 +5395,6 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -5904,11 +5525,6 @@ minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== -mkdirp@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - mocha@^8.1.2: version "8.4.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" @@ -5940,11 +5556,6 @@ mocha@^8.1.2: yargs-parser "20.2.4" yargs-unparser "2.0.0" -module-details-from-path@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" - integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== - module-error@^1.0.1, module-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" @@ -5955,7 +5566,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5973,7 +5584,7 @@ mustache@^4.0.0: resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== -mute-stream@0.0.8, mute-stream@~0.0.4: +mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== @@ -6029,25 +5640,11 @@ near-seed-phrase@^0.2.0: near-hd-key "^1.2.1" tweetnacl "^1.0.2" -needle@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -netmask@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== - node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" @@ -6092,14 +5689,6 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -nssocket@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/nssocket/-/nssocket-0.6.0.tgz#59f96f6ff321566f33c70f7dbeeecdfdc07154fa" - integrity sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w== - dependencies: - eventemitter2 "~0.4.14" - lazy "~1.0.11" - nwsapi@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" @@ -6225,30 +5814,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pac-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz#b718f76475a6a5415c2efbe256c1c971c84f635e" - integrity sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - get-uri "3" - http-proxy-agent "^4.0.1" - https-proxy-agent "5" - pac-resolver "^5.0.0" - raw-body "^2.2.0" - socks-proxy-agent "5" - -pac-resolver@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-5.0.1.tgz#c91efa3a9af9f669104fa2f51102839d01cde8e7" - integrity sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q== - dependencies: - degenerator "^3.0.2" - ip "^1.1.5" - netmask "^2.0.2" - packet-reader@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" @@ -6259,11 +5824,6 @@ paho-mqtt@^1.1.0: resolved "https://registry.yarnpkg.com/paho-mqtt/-/paho-mqtt-1.1.0.tgz#8c10e29eb162e966fb15188d965c3dce505de9d9" integrity sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA== -pako@^0.2.5: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== - pako@^1.0.3: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -6415,20 +5975,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pidusage@^2.0.21: - version "2.0.21" - resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-2.0.21.tgz#7068967b3d952baea73e57668c98b9eaa876894e" - integrity sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA== - dependencies: - safe-buffer "^5.2.1" - -pidusage@~3.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-3.0.2.tgz#6faa5402b2530b3af2cf93d13bcf202889724a53" - integrity sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w== - dependencies: - safe-buffer "^5.2.1" - pirates@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" @@ -6441,86 +5987,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pm2-axon-rpc@~0.7.0, pm2-axon-rpc@~0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz#2daec5383a63135b3f18babb70266dacdcbc429a" - integrity sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw== - dependencies: - debug "^4.3.1" - -pm2-axon@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pm2-axon/-/pm2-axon-4.0.1.tgz#a7b4bb586e9aeb35b1042b488cde15b60cabafd2" - integrity sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg== - dependencies: - amp "~0.3.1" - amp-message "~0.1.1" - debug "^4.3.1" - escape-string-regexp "^4.0.0" - -pm2-deploy@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pm2-deploy/-/pm2-deploy-1.0.2.tgz#98d8385553a3a4dca11c7b3116deb519bc5961a7" - integrity sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg== - dependencies: - run-series "^1.1.8" - tv4 "^1.3.0" - -pm2-multimeter@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz#1a1e55153d41a05534cea23cfe860abaa0eb4ace" - integrity sha512-S+wT6XfyKfd7SJIBqRgOctGxaBzUOmVQzTAS+cg04TsEUObJVreha7lvCfX8zzGVr871XwCSnHUU7DQQ5xEsfA== - dependencies: - charm "~0.1.1" - -pm2-sysmonit@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz#eddea34a53fd8c8d7c3efb73b97a3c548686e24d" - integrity sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA== - dependencies: - async "^3.2.0" - debug "^4.3.1" - pidusage "^2.0.21" - systeminformation "^5.7" - tx2 "~1.0.4" - -pm2@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/pm2/-/pm2-5.3.0.tgz#06850810f77cd98495ae1c66fbdd028a8fb5899e" - integrity sha512-xscmQiAAf6ArVmKhjKTeeN8+Td7ZKnuZFFPw1DGkdFPR/0Iyx+m+1+OpCdf9+HQopX3VPc9/wqPQHqVOfHum9w== - dependencies: - "@pm2/agent" "~2.0.0" - "@pm2/io" "~5.0.0" - "@pm2/js-api" "~0.6.7" - "@pm2/pm2-version-check" latest - async "~3.2.0" - blessed "0.1.81" - chalk "3.0.0" - chokidar "^3.5.3" - cli-tableau "^2.0.0" - commander "2.15.1" - croner "~4.1.92" - dayjs "~1.11.5" - debug "^4.3.1" - enquirer "2.3.6" - eventemitter2 "5.0.1" - fclone "1.0.11" - mkdirp "1.0.4" - needle "2.4.0" - pidusage "~3.0" - pm2-axon "~4.0.1" - pm2-axon-rpc "~0.7.1" - pm2-deploy "~1.0.2" - pm2-multimeter "^0.1.2" - promptly "^2" - semver "^7.2" - source-map-support "0.5.21" - sprintf-js "1.1.2" - vizion "~2.2.1" - yamljs "0.3.0" - optionalDependencies: - pm2-sysmonit "^1.2.8" - postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -6587,20 +6053,6 @@ progress@^2.0.0, progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@12: - version "12.0.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-12.0.0.tgz#9689379b19bd3f6ab88a9866124db9da3d76c6ed" - integrity sha512-JbzzHnw0VDwCvoqf8y1WDtq4wSBAbthMB1pcVI/0lzdqHGJI3KBJDXle70XK+c7Iv93Gihqo0a5LlOn+g8+DrQ== - dependencies: - tdigest "^0.1.1" - -promptly@^2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/promptly/-/promptly-2.2.0.tgz#2a13fa063688a2a5983b161fff0108a07d26fc74" - integrity sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA== - dependencies: - read "^1.0.4" - prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -6609,25 +6061,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -proxy-agent@~5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-5.0.0.tgz#d31405c10d6e8431fde96cba7a0c027ce01d633b" - integrity sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g== - dependencies: - agent-base "^6.0.0" - debug "4" - http-proxy-agent "^4.0.0" - https-proxy-agent "^5.0.0" - lru-cache "^5.1.1" - pac-proxy-agent "^5.0.0" - proxy-from-env "^1.0.0" - socks-proxy-agent "^5.0.0" - -proxy-from-env@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -6680,16 +6113,6 @@ randombytes@^2.0.1, randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -raw-body@^2.2.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - raw-body@^2.3.3, raw-body@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" @@ -6712,23 +6135,6 @@ react-native-get-random-values@^1.4.0: dependencies: fast-base64-decode "^1.0.0" -read@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ== - dependencies: - mute-stream "~0.0.4" - -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.3.3: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -6765,13 +6171,6 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - rechoir@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" @@ -6846,15 +6245,6 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -require-in-the-middle@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz#4b71e3cc7f59977100af9beb76bf2d056a5a6de2" - integrity sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg== - dependencies: - debug "^4.1.1" - module-details-from-path "^1.0.3" - resolve "^1.22.1" - requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -6882,7 +6272,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.20.0, resolve@^1.22.1: +resolve@^1.20.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -6961,11 +6351,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -run-series@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.9.tgz#15ba9cb90e6a6c054e67c98e1dc063df0ecc113a" - integrity sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g== - rxjs@^7.5.5: version "7.5.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" @@ -6973,7 +6358,7 @@ rxjs@^7.5.5: dependencies: tslib "^2.1.0" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -6993,11 +6378,6 @@ safe-stable-stringify@2.4.1, safe-stable-stringify@^2.4.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -7019,27 +6399,17 @@ secp256k1@^4.0.2: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -semver@6.3.0, semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@7.x, semver@^7.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: +semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== dependencies: lru-cache "^6.0.0" -semver@^5.3.0, semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@~7.2.0: - version "7.2.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.2.3.tgz#3641217233c6382173c76bf2c7ecd1e1c16b0d8a" - integrity sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig== +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== serialize-javascript@5.0.1: version "5.0.1" @@ -7073,11 +6443,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -7102,29 +6467,7 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -smart-buffer@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" - integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== - -socks-proxy-agent@5, socks-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" - integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== - dependencies: - agent-base "^6.0.2" - debug "4" - socks "^2.3.3" - -socks@^2.3.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" - integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== - dependencies: - ip "^2.0.0" - smart-buffer "^4.2.0" - -source-map-support@0.5.21, source-map-support@^0.5.6: +source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -7147,11 +6490,6 @@ split2@^4.1.0: resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== -sprintf-js@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" - integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -7226,11 +6564,6 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -7323,11 +6656,6 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -systeminformation@^5.7: - version "5.17.12" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.17.12.tgz#5b3e1bfcd5c2c5b459f1a88e61fed27cf9668ba8" - integrity sha512-I3pfMW2vue53u+X08BNxaJieaHkRoMMKjWetY9lbYJeWFaeWPO6P4FkNc4XOCX8F9vbQ0HqQ25RJoz3U/B7liw== - tar-stream@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" @@ -7344,13 +6672,6 @@ tarn@^3.0.2: resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693" integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ== -tdigest@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" - integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA== - dependencies: - bintrees "1.0.2" - terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -7506,11 +6827,6 @@ tsconfig-paths@^3.10.1: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@1.9.3: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== - tslib@^1.11.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -7521,11 +6837,6 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== -tslib@^2.0.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -7538,23 +6849,11 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -tv4@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.3.0.tgz#d020c846fadd50c855abb25ebaecc68fc10f7963" - integrity sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw== - tweetnacl@1.0.3, tweetnacl@^1.0.1, tweetnacl@^1.0.2, tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== -tx2@~1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tx2/-/tx2-1.0.5.tgz#ee0b0e5e2c351f8d23e54bdf46dd60afa3bbc73d" - integrity sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg== - dependencies: - json-stringify-safe "^5.0.1" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -7609,10 +6908,10 @@ u3@^0.1.1: resolved "https://registry.yarnpkg.com/u3/-/u3-0.1.1.tgz#5f52044f42ee76cd8de33148829e14528494b73b" integrity sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w== -undici@5.14.0: - version "5.14.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.14.0.tgz#1169d0cdee06a4ffdd30810f6228d57998884d00" - integrity sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ== +undici@5.21.0: + version "5.21.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.21.0.tgz#b00dfc381f202565ab7f52023222ab862bb2494f" + integrity sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA== dependencies: busboy "^1.6.0" @@ -7641,11 +6940,6 @@ universal-cookie@^4.0.4: "@types/cookie" "^0.3.3" cookie "^0.4.0" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - universalify@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" @@ -7732,6 +7026,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + uzip-module@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/uzip-module/-/uzip-module-1.0.3.tgz#6bbabe2a3efea5d5a4a47479f523a571de3427ce" @@ -7761,16 +7060,6 @@ vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vizion@~2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/vizion/-/vizion-2.2.1.tgz#04201ea45ffd145d5b5210e385a8f35170387fb2" - integrity sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww== - dependencies: - async "^2.6.3" - git-node-fs "^1.0.0" - ini "^1.3.5" - js-git "^0.7.8" - vlq@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/vlq/-/vlq-2.0.4.tgz#6057b85729245b9829e3cc7755f95b228d4fe041" @@ -7784,14 +7073,6 @@ vm2@3.9.11: acorn "^8.7.0" acorn-walk "^8.2.0" -vm2@^3.9.8: - version "3.9.14" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.14.tgz#964042b474cf1e6e4f475a39144773cdb9deb734" - integrity sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA== - dependencies: - acorn "^8.7.0" - acorn-walk "^8.2.0" - w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -8030,12 +7311,12 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@7.4.6, ws@~7.4.0: +ws@7.4.6: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@^7.0.0, ws@^7.4.5, ws@^7.4.6: +ws@^7.4.5, ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== @@ -8055,11 +7336,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA== - xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -8070,24 +7346,11 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yamljs@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/yamljs/-/yamljs-0.3.0.tgz#dc060bf267447b39f7304e9b2bfbe8b5a7ddb03b" - integrity sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ== - dependencies: - argparse "^1.0.7" - glob "^7.0.5" - yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" From 255054dea132a899f861d84cc22c2bd4844271e7 Mon Sep 17 00:00:00 2001 From: ppe Date: Thu, 13 Apr 2023 16:52:23 +0200 Subject: [PATCH 15/95] do not log arweave/info --- src/gateway/accessLogMiddleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts index f47cc6e7..ac5e53a1 100644 --- a/src/gateway/accessLogMiddleware.ts +++ b/src/gateway/accessLogMiddleware.ts @@ -9,7 +9,7 @@ export async function accessLogMiddleware(ctx: ParameterizedContext Date: Thu, 13 Apr 2023 17:20:39 +0200 Subject: [PATCH 16/95] remove logging --- src/gateway/router/routes/contracts/contractsBySourceRoute.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gateway/router/routes/contracts/contractsBySourceRoute.ts b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts index b040c18d..913be9c9 100644 --- a/src/gateway/router/routes/contracts/contractsBySourceRoute.ts +++ b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts @@ -21,8 +21,6 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { throw new GatewayError('Incorrect contract source transaction id.', 403); } - logger.info(`contractsBySourceRoute [ip: ${ctx.request?.ip}, srcId: ${id}]`); - const bindings: any = []; id && bindings.push(id); parsedPage && bindings.push(parsedLimit); From 4fc8c1b46c651c21a18aa527c238ea1fc9406631 Mon Sep 17 00:00:00 2001 From: ppe Date: Tue, 18 Apr 2023 15:53:28 +0200 Subject: [PATCH 17/95] logging fix --- src/gateway/errorHandlerMiddleware.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/errorHandlerMiddleware.ts b/src/gateway/errorHandlerMiddleware.ts index 3ed52d9e..4bf070c2 100644 --- a/src/gateway/errorHandlerMiddleware.ts +++ b/src/gateway/errorHandlerMiddleware.ts @@ -22,7 +22,7 @@ export async function errorHandlerMiddleware(ctx: ParameterizedContext Date: Mon, 27 Feb 2023 12:35:29 +0100 Subject: [PATCH 18/95] feat: async bundling --- src/gateway/init.ts | 2 +- src/gateway/router/routes/sequencerRoute.ts | 168 +++++++++++--------- tools/nakurwiaj.js | 87 ++++++++++ 3 files changed, 181 insertions(+), 76 deletions(-) create mode 100644 tools/nakurwiaj.js diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 99ca0b0b..2afdedee 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -78,7 +78,7 @@ export interface GatewayContext { LoggerFactory.INST.logLevel('info'); LoggerFactory.INST.logLevel('info', 'gateway'); - LoggerFactory.INST.logLevel('debug', 'sequencer'); + LoggerFactory.INST.logLevel('info', 'sequencer'); LoggerFactory.INST.logLevel('debug', 'LastTxSync'); LoggerFactory.INST.logLevel('debug', 'access'); const logger = LoggerFactory.INST.create('gateway'); diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index ce9c2298..80433a9d 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -1,21 +1,20 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; -import { parseFunctionName } from '../../tasks/syncTransactions'; +import {parseFunctionName} from '../../tasks/syncTransactions'; import Arweave from 'arweave'; -import { JWKInterface } from 'arweave/node/lib/wallet'; -import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; +import {JWKInterface} from 'arweave/node/lib/wallet'; +import {arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger} from 'warp-contracts'; +import {getCachedNetworkData} from '../../tasks/networkInfoCache'; import Bundlr from '@bundlr-network/client'; import { BlockData } from 'arweave/node/blocks'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { publishInteraction, sendNotification } from '../../publisher'; import { Knex } from 'knex'; -import { InteractionInsert } from '../../../db/insertInterfaces'; import {GatewayError} from "../../errorHandlerMiddleware"; import {VRF} from "../../init"; -const { Evaluate } = require('@idena/vrf-js'); +const {Evaluate} = require('@idena/vrf-js'); export type VrfData = { index: string; @@ -25,15 +24,17 @@ export type VrfData = { }; export async function sequencerRoute(ctx: Router.RouterContext) { - const { sLogger, arweave, bundlr, jwk, vrf, lastTxSync, dbSource, signatureVerification } = ctx; - const trx: Knex.Transaction = await dbSource.primaryDb.transaction(); + const {sLogger, arweave, jwk, vrf, lastTxSync, dbSource, signatureVerification} = ctx; + + let trx: Knex.Transaction | null = null; try { + const initialBenchmark = Benchmark.measure(); const cachedNetworkData = getCachedNetworkData(); const benchmark = Benchmark.measure(); - const transaction: Transaction = new Transaction({ ...ctx.request.body }); + const transaction: Transaction = new Transaction({...ctx.request.body}); sLogger.debug('New sequencer tx', transaction.id); const originalSignature = transaction.signature; @@ -80,18 +81,18 @@ export async function sequencerRoute(ctx: Router.RouterContext) { arweave ); - // note: contractLastSortKey will be null for the very first interaction with a given contract - const contractLastSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); - + const trx = await dbSource.primaryDb.transaction(); + const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); const millis = Date.now(); const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, transaction.id, currentHeight); - if (contractLastSortKey !== null && sortKey.localeCompare(contractLastSortKey) <= 0) { - throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractLastSortKey})!`); + if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { + throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); } - tags.push({ name: 'Sequencer-Mills', value: '' + millis }); - tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); - tags.push({ name: 'Sequencer-Last-Sort-Key', value: contractLastSortKey || 'null' }); + tags.push({name: 'Sequencer-Mills', value: '' + millis}); + tags.push({name: 'Sequencer-Sort-Key', value: sortKey}); + tags.push({name: "Sequencer-Prev-Sort-Key", value: contractPrevSortKey || 'null'}); + let vrfData = null; if (requestVrfTag !== '') { const vrfGen = generateVrfTags(sortKey, vrf, arweave); @@ -99,7 +100,6 @@ export async function sequencerRoute(ctx: Router.RouterContext) { vrfData = vrfGen.vrfData; } - sLogger.info('Original address before create interaction', originalAddress); const interaction = createInteraction( transaction, originalAddress, @@ -111,50 +111,71 @@ export async function sequencerRoute(ctx: Router.RouterContext) { vrfData, isEvmSigner ? originalSignature : null, testnetVersion, - contractLastSortKey + contractPrevSortKey ); const verified = isEvmSigner - ? await signatureVerification.process(interaction) - : await arweave.transactions.verify(transaction); - + ? await signatureVerification.process(interaction) + : await arweave.transactions.verify(transaction); if (!verified) { - throw new Error('Transaction could not be verified - is it properly signed?'); - } else { - sLogger.info('Transaction verified properly'); + throw new Error('Could not properly verify transaction.'); } - // TODO: add fallback to other bundlr nodes. - const { bTx, bundlrResponse } = await uploadToBundlr(transaction, bundlr, tags, sLogger); - const parsedInput = JSON.parse(inputTag); const functionName = parseFunctionName(inputTag, sLogger); let evolve: string | null; evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; - if (isEvmSigner) { - sLogger.info(`Interaction for ${transaction.id}`, JSON.stringify(interaction)); - } - - const sequencerInsert = { - original_sig: originalSignature, - original_owner: originalOwner, - original_address: originalAddress, - sequence_block_id: currentBlockId, - sequence_block_height: currentHeight, - sequence_transaction_id: transaction.id, - sequence_millis: '' + millis, - sequence_sort_key: sortKey, - bundler_tx_id: bTx.id, - bundler_response: JSON.stringify(bundlrResponse.data), - last_sort_key: contractLastSortKey, - }; - - const interactionsInsert: InteractionInsert = { + sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); + sLogger.debug('inserting into tables'); + + await trx.raw(` + WITH ins_interaction AS ( + INSERT INTO interactions (interaction_id, + interaction, + block_height, + block_id, + contract_id, + function, + input, + confirmation_status, + confirming_peer, + source, + block_timestamp, + interact_write, + sort_key, + evolve, + testnet, + last_sort_key, + owner, + sync_timestamp) + VALUES (:interaction_id, + :interaction, + :block_height, + :block_id, + :contract_id, + :function, + :input, + :confirmation_status, + :confirming_peer, + :source, + :block_timestamp, + :interact_write, + :sort_key, + :evolve, + :testnet, + :prev_sort_key, + :owner, + :sync_timestamp) + RETURNING id) + INSERT + INTO bundle_items (interaction_id, state, transaction, tags) + SELECT i.id, 'PENDING', :original_transaction, :tags + FROM ins_interaction i; + `, { interaction_id: transaction.id, - interaction: JSON.stringify(interaction), + interaction: interaction, block_height: currentHeight, - block_timestamp: currentBlockTimestamp, block_id: currentBlockId, contract_id: contractTag, function: functionName, @@ -162,42 +183,40 @@ export async function sequencerRoute(ctx: Router.RouterContext) { confirmation_status: 'confirmed', confirming_peer: BUNDLR_NODE1_URL, source: 'redstone-sequencer', - bundler_tx_id: bTx.id, + block_timestamp: currentBlockTimestamp, interact_write: internalWrites, sort_key: sortKey, evolve: evolve, testnet: testnetVersion, - last_sort_key: contractLastSortKey, + prev_sort_key: contractPrevSortKey, owner: originalOwner, - sync_timestamp: millis, - }; - - await dbSource.insertSequencerAndInteraction(sequencerInsert, interactionsInsert, trx, sLogger); - - sLogger.debug('Transaction successfully bundled', { - id: transaction.id, - bundled_tx_id: bTx.id, + original_transaction: ctx.request.body, + tags: JSON.stringify(tags), + sync_timestamp: millis }); - ctx.body = bundlrResponse.data; - + await trx.commit(); sLogger.info('Total sequencer processing', benchmark.elapsed()); + ctx.body = { + id: transaction.id + }; + sendNotification(ctx, contractTag, undefined, interaction); publishInteraction( ctx, contractTag, interaction, sortKey, - contractLastSortKey, + contractPrevSortKey, functionName, 'redstone-sequencer', millis, testnetVersion ); } catch (e: any) { - if (!trx.isCompleted()) { - await trx.rollback(); + if (trx != null) { + await (trx as Knex.Transaction).rollback(); } throw new GatewayError(e?.message || e) } @@ -218,7 +237,7 @@ function createInteraction( ) { const interaction: any = { id: transaction.id, - owner: { address: originalAddress }, + owner: {address: originalAddress}, recipient: transaction.target, tags: decodedTags, block: { @@ -236,7 +255,6 @@ function createInteraction( source: 'redstone-sequencer', vrf: vrfData, testnet: testnetVersion, - lastSortKey, }; if (signature) { @@ -260,10 +278,10 @@ function generateVrfTags(sortKey: string, vrf: VRF, arweave: Arweave) { return { vrfTags: [ - { name: 'vrf-index', value: vrfData.index }, - { name: 'vrf-proof', value: vrfData.proof }, - { name: 'vrf-bigint', value: vrfData.bigint }, - { name: 'vrf-pubkey', value: vrfData.pubkey }, + {name: 'vrf-index', value: vrfData.index}, + {name: 'vrf-proof', value: vrfData.proof}, + {name: 'vrf-bigint', value: vrfData.bigint}, + {name: 'vrf-pubkey', value: vrfData.pubkey}, ], vrfData, }; @@ -305,8 +323,8 @@ async function prepareTags( const internalWrites: string[] = []; for (const tag of transaction.tags) { - const key = tag.get('name', { decode: true, string: true }); - const value = tag.get('value', { decode: true, string: true }); + const key = tag.get('name', {decode: true, string: true}); + const value = tag.get('value', {decode: true, string: true}); if (key == SmartWeaveTags.CONTRACT_TX_ID) { contractTag = value; } @@ -369,9 +387,9 @@ export async function uploadToBundlr( ) { const uploadBenchmark = Benchmark.measure(); - const bTx = bundlr.createTransaction(JSON.stringify(transaction), { tags }); + const bTx = bundlr.createTransaction(JSON.stringify(transaction), {tags}); await bTx.sign(); - const bundlrResponse = await bundlr.uploader.uploadTransaction(bTx, { getReceiptSignature: true }); + const bundlrResponse = await bundlr.uploader.uploadTransaction(bTx, {getReceiptSignature: true}); logger.debug('Uploading to bundlr', { elapsed: uploadBenchmark.elapsed(), @@ -385,7 +403,7 @@ export async function uploadToBundlr( ); } - return { bTx, bundlrResponse }; + return {bTx, bundlrResponse}; } async function createSortKey( diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js new file mode 100644 index 00000000..9e98cd66 --- /dev/null +++ b/tools/nakurwiaj.js @@ -0,0 +1,87 @@ +const fs = require("fs"); + +const warpContracts = require("warp-contracts"); +const warp = warpContracts.WarpFactory.forTestnet(); +const wallet = readJSON('./.secrets/33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA.json'); + +warpContracts.LoggerFactory.INST.logLevel('error'); + +const contractA = warp.contract("IBrkOF0A8XqlZHVFtZXy7jfCJFcaLJ2XYp94xL1-yUc") + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/' + }) + .connect(wallet); + +const contractB = warp.contract("1LsbT8HH8SbldveeZcZZwgmuLn0ueJ6pN7ZSrbTqeVU") + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/' + }) + .connect(wallet); + +const contractC = warp.contract("o-QYGKa6rkWj5i0Vx0VQy99myCkPNeCAJi6-UZnhIVU") + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/' + }) + .connect(wallet); + +const contractD = warp.contract("Y8ngFNyfGo17FeSvB7NEzLxdjl-qpFlE1YIPM8Sa6fo") + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/' + }) + .connect(wallet); + +const contractE = warp.contract("pxna6TxgVFaESLNu0uZvxeUMOSqoYL1n-RRLtk7mGjY") + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/' + }) + .connect(wallet); + + +setInterval(async () => { + console.log('sending...'); + await Promise.all([ + contractA.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractB.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractC.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractD.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractE.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }) + + ]); +}, 75); + +function readJSON(path) { + const content = fs.readFileSync(path, 'utf-8'); + try { + return JSON.parse(content); + } catch (e) { + throw new Error(`File "${path}" does not contain a valid JSON`); + } +} + +process.on('uncaughtException', () => { + console.error('uncaughtException'); +}); + +process.on('unhandledRejection', (e) => { + console.error('unhandledRejection'); +}); \ No newline at end of file From 807c314683b64083c898bafc8529e69733b35711 Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 27 Apr 2023 13:06:33 +0200 Subject: [PATCH 19/95] feat: remove data from data item when logging error --- src/gateway/errorHandlerMiddleware.ts | 46 +++++++++-------- .../routes/deploy/deployBundledRoute.ts | 28 +++++----- .../routes/deploy/deployContractRoute_v2.ts | 51 +++++++++++-------- .../routes/deploy/deploySourceRoute_v2.ts | 16 +++--- 4 files changed, 78 insertions(+), 63 deletions(-) diff --git a/src/gateway/errorHandlerMiddleware.ts b/src/gateway/errorHandlerMiddleware.ts index 4bf070c2..f009465b 100644 --- a/src/gateway/errorHandlerMiddleware.ts +++ b/src/gateway/errorHandlerMiddleware.ts @@ -1,41 +1,47 @@ -import * as util from "util"; -import {DefaultState, Next, ParameterizedContext} from "koa"; -import {GatewayContext} from "./init"; +import * as util from 'util'; +import { DefaultState, Next, ParameterizedContext } from 'koa'; +import { GatewayContext } from './init'; const ERROR_LOG_FORMAT = '[%s][%s]: %s %s'; export class GatewayError extends Error { constructor(message: string, readonly status: number = 500, readonly properties: any = null, readonly log = true) { super(message); - this.name = 'GatewayError' + this.name = 'GatewayError'; } } -export async function errorHandlerMiddleware(ctx: ParameterizedContext, next: Next): Promise { +export async function errorHandlerMiddleware( + ctx: ParameterizedContext, + next: Next +): Promise { try { await next(); } catch (err: any) { if (err.name == 'GatewayError') { ctx.status = err.status; - ctx.message = `[${ctx.state.requestId}]: ${err.message}`; + ctx.message = `[${ctx.state.requestId}]: ${err.message.replace(/\r?\n|\r/, '')}`; if (err.log) { - ctx.logger.error(util.format( - ERROR_LOG_FORMAT, - ctx.state.requestId, - `${ctx.path}${ctx.search}`, - err.message, - err.properties ? JSON.stringify(err.properties): '' - ), err); + ctx.logger.error( + util.format( + ERROR_LOG_FORMAT, + ctx.state.requestId, + `${ctx.path}${ctx.search}`, + err.message, + err.properties ? JSON.stringify(err.properties) : '' + ), + err + ); } } else { ctx.status = 500; - ctx.message = `Unknown gateway error ${err?.message || err}`; - ctx.logger.error(util.format( - ERROR_LOG_FORMAT, - ctx.state.requestId, - `${ctx.path}${ctx.search}`, - err.message || err - ), err); + ctx.message = `[${ctx.state.requestId}]${ + err?.message ? `: ${err.message.replace(/\r?\n|\r/, '')}` : `Unknown gateway error.` + }`; + ctx.logger.error( + util.format(ERROR_LOG_FORMAT, ctx.state.requestId, `${ctx.path}${ctx.search}`, err.message || err), + err + ); } } } diff --git a/src/gateway/router/routes/deploy/deployBundledRoute.ts b/src/gateway/router/routes/deploy/deployBundledRoute.ts index f9c3fd2b..a7c637d4 100644 --- a/src/gateway/router/routes/deploy/deployBundledRoute.ts +++ b/src/gateway/router/routes/deploy/deployBundledRoute.ts @@ -3,18 +3,18 @@ import { evalType } from '../../../tasks/contractsMetadata'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { DataItem } from 'arbundles'; import rawBody from 'raw-body'; -import {getCachedNetworkData} from '../../../tasks/networkInfoCache'; -import {publishContract, sendNotification} from '../../../publisher'; -import {evalManifest, WarpDeployment} from './deployContractRoute'; -import {ContractInsert} from '../../../../db/insertInterfaces'; -import {GatewayError} from "../../../errorHandlerMiddleware"; +import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; +import { publishContract, sendNotification } from '../../../publisher'; +import { evalManifest, WarpDeployment } from './deployContractRoute'; +import { ContractInsert } from '../../../../db/insertInterfaces'; +import { GatewayError } from '../../../errorHandlerMiddleware'; +import { getDataItemWithoutData } from './deployContractRoute_v2'; export async function deployBundledRoute(ctx: Router.RouterContext) { - const {logger, dbSource, arweave, bundlr} = ctx; + const { logger, dbSource, arweave, bundlr } = ctx; let initStateRaw, dataItem; - const rawDataItem: Buffer = await rawBody(ctx.req); dataItem = new DataItem(rawDataItem); const isValid = await dataItem.isValid(); @@ -27,7 +27,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { throw new GatewayError('Contract tags are not valid.', 400); } - const bundlrResponse = await bundlr.uploader.uploadTransaction(dataItem, {getReceiptSignature: true}); + const bundlrResponse = await bundlr.uploader.uploadTransaction(dataItem, { getReceiptSignature: true }); if (bundlrResponse.status !== 200 || !bundlrResponse.data.public || !bundlrResponse.data.signature) { throw new GatewayError( @@ -61,7 +61,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { block_height: blockHeight, block_timestamp: blockTimestamp, content_type: contentType, - contract_tx: {tags: dataItem.toJSON().tags}, + contract_tx: { tags: dataItem.toJSON().tags }, bundler_contract_tx_id: bundlrResponse.data.id, bundler_contract_node: BUNDLR_NODE1_URL, testnet, @@ -71,7 +71,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { }; await dbSource.insertContract(insert); - sendNotification(ctx, bundlrResponse.data.id, {initState, tags: dataItem.tags}); + sendNotification(ctx, bundlrResponse.data.id, { initState, tags: dataItem.tags }); publishContract( ctx, bundlrResponse.data.id, @@ -94,7 +94,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { } catch (e: any) { throw new GatewayError(`Error while inserting bundled transaction.`, 500, { dataItemId: dataItem?.id, - contractTx: dataItem?.toJSON(), + contractTx: getDataItemWithoutData(dataItem), initStateRaw: initStateRaw, }); } @@ -103,9 +103,9 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { export async function verifyContractTags(dataItem: DataItem, ctx: Router.RouterContext) { const tags = dataItem.tags; const tagsIncluded = [ - {name: 'App-Name', value: 'SmartWeaveContract'}, - {name: 'App-Version', value: '0.3.0'}, - {name: 'Content-Type', value: 'application/x.arweave-manifest+json'}, + { name: 'App-Name', value: 'SmartWeaveContract' }, + { name: 'App-Version', value: '0.3.0' }, + { name: 'Content-Type', value: 'application/x.arweave-manifest+json' }, ]; const nameTagsIncluded = ['Contract-Src', 'Init-State', 'Title', 'Description', 'Type']; if (tags.some((t) => t.name == tagsIncluded[2].name && t.value != tagsIncluded[2].value)) { diff --git a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts index db4777c9..a71d70d0 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -7,14 +7,14 @@ import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { publishContract, sendNotification } from '../../../publisher'; import { evalManifest, WarpDeployment } from './deployContractRoute'; import Arweave from 'arweave'; -import {SignatureConfig} from 'arbundles/src/constants'; -import {utils} from 'ethers'; -import {longTo32ByteArray} from 'arbundles/src/utils'; -import {ContractInsert, ContractSourceInsert} from '../../../../db/insertInterfaces'; -import {GatewayError} from "../../../errorHandlerMiddleware"; +import { SignatureConfig } from 'arbundles/src/constants'; +import { utils } from 'ethers'; +import { longTo32ByteArray } from 'arbundles/src/utils'; +import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; +import { GatewayError } from '../../../errorHandlerMiddleware'; export async function deployContractRoute_v2(ctx: Router.RouterContext) { - const {logger, arweave, dbSource} = ctx; + const { logger, arweave, dbSource } = ctx; let initStateRaw, contractDataItem, @@ -27,7 +27,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { if (!isContractValid) { ctx.throw(400, 'Contract data item binary is not valid.'); } - const areContractTagsValid = await verifyDeployTags(contractDataItem, {contract: true}); + const areContractTagsValid = await verifyDeployTags(contractDataItem, { contract: true }); if (!areContractTagsValid) { ctx.throw(400, 'Contract tags are not valid.'); } @@ -72,7 +72,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { deployment_type: WarpDeployment.Direct, }; } - const bundlrResponse = await bundleAndUpload({contract: contractDataItem, src: srcDataItem || null}, ctx); + const bundlrResponse = await bundleAndUpload({ contract: contractDataItem, src: srcDataItem || null }, ctx); logger.debug('Contract successfully uploaded to Bundlr.', { contract_id: contractDataItem.id, src_id: srcDataItem?.id, @@ -114,7 +114,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { block_height: blockHeight, block_timestamp: blockTimestamp, content_type: contentType, - contract_tx: {tags: contractDataItem.toJSON().tags}, + contract_tx: { tags: contractDataItem.toJSON().tags }, bundler_contract_tx_id: bundlrResponse.data.id, bundler_contract_node: BUNDLR_NODE1_URL, testnet, @@ -125,7 +125,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { await dbSource.insertContract(insert); - sendNotification(ctx, contractDataItem.id, {initState, tags: contractDataItem.tags}); + sendNotification(ctx, contractDataItem.id, { initState, tags: contractDataItem.tags }); publishContract( ctx, contractDataItem.id, @@ -152,7 +152,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { } catch (e: any) { throw new GatewayError(`Error while inserting bundled transaction: ${e}.`, 500, { dataItemId: contractDataItem?.id, - contract: contractDataItem?.toJSON(), + contract: getDataItemWithoutData(contractDataItem), initStateRaw: initStateRaw, }); } @@ -162,9 +162,9 @@ export async function verifyDeployTags(dataItem: DataItem, opts?: { contract: bo const tags = dataItem.tags; const deployTags = [ - {name: SmartWeaveTags.APP_NAME, value: opts?.contract ? 'SmartWeaveContract' : 'SmartWeaveContractSource'}, - {name: SmartWeaveTags.APP_VERSION, value: '0.3.0'}, - {name: SmartWeaveTags.SDK, value: 'Warp'}, + { name: SmartWeaveTags.APP_NAME, value: opts?.contract ? 'SmartWeaveContract' : 'SmartWeaveContractSource' }, + { name: SmartWeaveTags.APP_VERSION, value: '0.3.0' }, + { name: SmartWeaveTags.SDK, value: 'Warp' }, ]; const contractNameTags = ['Contract-Src', 'Nonce']; @@ -197,8 +197,8 @@ export async function bundleAndUpload( dataItems: { contract: DataItem | null; src: DataItem | null }, ctx: Router.RouterContext ) { - const {bundlr} = ctx; - const {contract, src} = dataItems; + const { bundlr } = ctx; + const { contract, src } = dataItems; const dataItemsToUpload = []; contract && dataItemsToUpload.push(contract); src && dataItemsToUpload.push(src); @@ -206,14 +206,14 @@ export async function bundleAndUpload( const bundlrTx = bundlr.createTransaction(bundle.getRaw(), { tags: [ - {name: 'Bundle-Format', value: 'binary'}, - {name: 'Bundle-Version', value: '2.0.0'}, - {name: 'App-Name', value: 'Warp'}, - {name: 'Action', value: 'WarpContractDeployment'}, + { name: 'Bundle-Format', value: 'binary' }, + { name: 'Bundle-Version', value: '2.0.0' }, + { name: 'App-Name', value: 'Warp' }, + { name: 'Action', value: 'WarpContractDeployment' }, ], }); await bundlrTx.sign(); - const bundlrResponse = await bundlr.uploader.uploadTransaction(bundlrTx, {getReceiptSignature: true}); + const bundlrResponse = await bundlr.uploader.uploadTransaction(bundlrTx, { getReceiptSignature: true }); if ( bundlrResponse.status !== 200 || !bundlrResponse.data.public || @@ -253,3 +253,12 @@ export async function bundleData(dataItems: DataItem[]): Promise { return new Bundle(buffer); } + +export function getDataItemWithoutData(dataItem: DataItem | undefined) { + if (dataItem) { + const { data, ...dataItemWithoutData } = dataItem.toJSON(); + return JSON.stringify(dataItemWithoutData); + } else { + return undefined; + } +} diff --git a/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts b/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts index 38cbbba4..15e83317 100644 --- a/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts @@ -4,14 +4,14 @@ import { SmartWeaveTags } from 'warp-contracts'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { WarpDeployment } from './deployContractRoute'; import rawBody from 'raw-body'; -import {DataItem} from 'arbundles'; -import {getTestnetTag} from './deployBundledRoute'; -import {bundleAndUpload, determineOwner, verifyDeployTags} from './deployContractRoute_v2'; -import {ContractSourceInsert} from '../../../../db/insertInterfaces'; -import {GatewayError} from "../../../errorHandlerMiddleware"; +import { DataItem } from 'arbundles'; +import { getTestnetTag } from './deployBundledRoute'; +import { bundleAndUpload, determineOwner, getDataItemWithoutData, verifyDeployTags } from './deployContractRoute_v2'; +import { ContractSourceInsert } from '../../../../db/insertInterfaces'; +import { GatewayError } from '../../../errorHandlerMiddleware'; export async function deploySourceRoute_v2(ctx: Router.RouterContext) { - const {logger, arweave, dbSource} = ctx; + const { logger, arweave, dbSource } = ctx; let dataItem; @@ -42,7 +42,7 @@ export async function deploySourceRoute_v2(ctx: Router.RouterContext) { } else { srcBinary = dataItem.rawData; } - const bundlrResponse = await bundleAndUpload({contract: null, src: dataItem}, ctx); + const bundlrResponse = await bundleAndUpload({ contract: null, src: dataItem }, ctx); bundlrSrcTxId = bundlrResponse.data.id; srcBundlrResponse = bundlrResponse; @@ -78,7 +78,7 @@ export async function deploySourceRoute_v2(ctx: Router.RouterContext) { } catch (e) { throw new GatewayError(`Error while inserting bundled transaction: ${e}.`, 500, { dataItemId: dataItem?.id, - contractTx: dataItem?.toJSON(), + contractTx: getDataItemWithoutData(dataItem), }); } } From d24b141b39a16a74ceb71bd9d4311efbaefca5cf Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 27 Apr 2023 15:05:48 +0200 Subject: [PATCH 20/95] access log fix --- src/gateway/accessLogMiddleware.ts | 9 ++++++--- .../routes/interactions/interactionsSortKeyRoute_v2.ts | 2 -- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts index ac5e53a1..3e872162 100644 --- a/src/gateway/accessLogMiddleware.ts +++ b/src/gateway/accessLogMiddleware.ts @@ -3,11 +3,13 @@ import { v4 as uuidv4 } from 'uuid'; import {DefaultState, Next, ParameterizedContext} from "koa"; import {GatewayContext} from "./init"; -const LOG_FORMAT = '%s %s "%s %s HTTP/%s" %d %s'; +const LOG_FORMAT = '%s %s "%s %s HTTP/%s" %d %s %d[ms]'; export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { ctx.state.requestId = uuidv4(); + const t0 = performance.now(); await next(); + const t1 = performance.now(); try { if (ctx.path == '/gateway/gcp/alive' || ctx.path == '/gateway/arweave/info') { return; @@ -17,10 +19,11 @@ export async function accessLogMiddleware(ctx: ParameterizedContext Date: Thu, 27 Apr 2023 15:16:30 +0200 Subject: [PATCH 21/95] log format --- src/gateway/accessLogMiddleware.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/accessLogMiddleware.ts b/src/gateway/accessLogMiddleware.ts index 3e872162..a50a3590 100644 --- a/src/gateway/accessLogMiddleware.ts +++ b/src/gateway/accessLogMiddleware.ts @@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid'; import {DefaultState, Next, ParameterizedContext} from "koa"; import {GatewayContext} from "./init"; -const LOG_FORMAT = '%s %s "%s %s HTTP/%s" %d %s %d[ms]'; +const LOG_FORMAT = '%s %s "%s %s HTTP/%s" %d %s %s[ms]'; export async function accessLogMiddleware(ctx: ParameterizedContext, next: Next): Promise { ctx.state.requestId = uuidv4(); @@ -23,7 +23,7 @@ export async function accessLogMiddleware(ctx: ParameterizedContext Date: Thu, 27 Apr 2023 18:06:02 +0200 Subject: [PATCH 22/95] fix: change new line regex --- src/gateway/errorHandlerMiddleware.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/errorHandlerMiddleware.ts b/src/gateway/errorHandlerMiddleware.ts index f009465b..2e7d882a 100644 --- a/src/gateway/errorHandlerMiddleware.ts +++ b/src/gateway/errorHandlerMiddleware.ts @@ -20,7 +20,7 @@ export async function errorHandlerMiddleware( } catch (err: any) { if (err.name == 'GatewayError') { ctx.status = err.status; - ctx.message = `[${ctx.state.requestId}]: ${err.message.replace(/\r?\n|\r/, '')}`; + ctx.message = `[${ctx.state.requestId}]: ${err.message.replace(/\n/g, '')}`; if (err.log) { ctx.logger.error( util.format( @@ -36,7 +36,7 @@ export async function errorHandlerMiddleware( } else { ctx.status = 500; ctx.message = `[${ctx.state.requestId}]${ - err?.message ? `: ${err.message.replace(/\r?\n|\r/, '')}` : `Unknown gateway error.` + err?.message ? `: ${err.message.replace(/\n/g, '')}` : `Unknown gateway error.` }`; ctx.logger.error( util.format(ERROR_LOG_FORMAT, ctx.state.requestId, `${ctx.path}${ctx.search}`, err.message || err), From fa97e6309c7d30e071cd6af716b6ba1ae15572e6 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Fri, 28 Apr 2023 12:26:05 +0200 Subject: [PATCH 23/95] trx ooops --- src/gateway/router/routes/sequencerRoute.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 80433a9d..5a028ea7 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -81,7 +81,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { arweave ); - const trx = await dbSource.primaryDb.transaction(); + trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); const millis = Date.now(); const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, transaction.id, currentHeight); @@ -216,7 +216,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { ); } catch (e: any) { if (trx != null) { - await (trx as Knex.Transaction).rollback(); + await trx.rollback(); } throw new GatewayError(e?.message || e) } From 4b4be53cd6bdce496f34aa53bbbd5f62e129cdbc Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Tue, 25 Apr 2023 15:01:55 +0200 Subject: [PATCH 24/95] extending endpoint /gcp/alive to include some database connection status --- src/db/databaseSource.ts | 47 +++++++++++++++++----- src/gateway/init.ts | 26 ++++++------ src/gateway/router/routes/gcpAliveRoute.ts | 28 ++++++++++++- 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/db/databaseSource.ts b/src/db/databaseSource.ts index 0beeef54..70e5da5a 100644 --- a/src/db/databaseSource.ts +++ b/src/db/databaseSource.ts @@ -19,11 +19,13 @@ interface DbData { ssl?: { ca: string | Buffer; cert: string | Buffer; key: string | Buffer; rejectUnauthorized: boolean }; options?: Partial; primaryDb?: boolean; + healthCheckConnection?: boolean; } export class DatabaseSource { public db: Knex[] = []; public primaryDb: Knex | null = null; + public healthCheckConnection: Knex | null = null; private mailClient: Transporter; constructor(dbData: DbData[]) { @@ -34,6 +36,11 @@ export class DatabaseSource { throw new Error('Only one db can be set primary!'); } this.primaryDb = this.db[i]; + } else if (dbData[i].healthCheckConnection) { + if (this.healthCheckConnection != null) { + throw new Error('Can set only one health check connection'); + } + this.healthCheckConnection = this.db[i]; } } if (this.primaryDb == null) { @@ -251,6 +258,10 @@ export class DatabaseSource { return db.raw(query, bindings); } + public healthCheck(query: string, bindings?: any) { + return this.healthCheckConnection!!.raw(query, bindings); + } + public async loopThroughDb(callback: any, recordName: string): Promise { let result: any; try { @@ -276,21 +287,37 @@ export class DatabaseSource { ...(dbData.ssl ? { ssl: dbData.ssl } : ''), }, useNullAsDefault: true, - pool: { - min: 5, - max: 30, - createTimeoutMillis: 3000, - acquireTimeoutMillis: 30000, - idleTimeoutMillis: 30000, - reapIntervalMillis: 1000, - createRetryIntervalMillis: 100, - propagateCreateError: false, - }, + pool: this.connectionPool(dbData), ...dbData.options, }; return knex(options); } + private connectionPool(dbData: DbData) { + if (dbData.healthCheckConnection) { + return { + min: 1, + max: 2, + createTimeoutMillis: 500, + acquireTimeoutMillis: 500, + idleTimeoutMillis: 500, + reapIntervalMillis: 500, + createRetryIntervalMillis: 100, + propagateCreateError: false, + } + } + return { + min: 5, + max: 30, + createTimeoutMillis: 3000, + acquireTimeoutMillis: 30000, + idleTimeoutMillis: 30000, + reapIntervalMillis: 1000, + createRetryIntervalMillis: 100, + propagateCreateError: false, + } + } + private currentLocalDateWithTime(): string { const tzoffset = new Date().getTimezoneOffset() * 60000; return new Date(Date.now() - tzoffset).toISOString().substring(0, 19); diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 2afdedee..931b6522 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -90,19 +90,21 @@ export interface GatewayContext { const arweave = initArweave(); const {bundlr, jwk} = initBundlr(logger); - const dbSource = new DatabaseSource([ - { - client: 'pg', - url: process.env.DB_URL_GCP as string, - ssl: localEnv ? undefined : { - rejectUnauthorized: false, - ca: fs.readFileSync('.secrets/ca.pem'), - cert: fs.readFileSync('.secrets/cert.pem'), - key: fs.readFileSync('.secrets/key.pem'), - }, - primaryDb: true, + const gcpDataOptions = { + client: 'pg' as 'pg', + url: process.env.DB_URL_GCP as string, + ssl: localEnv ? undefined : { + rejectUnauthorized: false, + ca: fs.readFileSync('.secrets/ca.pem'), + cert: fs.readFileSync('.secrets/cert.pem'), + key: fs.readFileSync('.secrets/key.pem'), }, - ]); + primaryDb: true, + healthCheckConnection: false + } + + const dbSource = new DatabaseSource( + [gcpDataOptions, {...gcpDataOptions, primaryDb: false, healthCheckConnection: true}]); const app = new Koa(); diff --git a/src/gateway/router/routes/gcpAliveRoute.ts b/src/gateway/router/routes/gcpAliveRoute.ts index 6df87eab..91f232c1 100644 --- a/src/gateway/router/routes/gcpAliveRoute.ts +++ b/src/gateway/router/routes/gcpAliveRoute.ts @@ -1,5 +1,31 @@ import Router from '@koa/router'; +import {getCachedNetworkData} from "../../tasks/networkInfoCache"; export async function gcpAliveRoute(ctx: Router.RouterContext) { - ctx.body = 'ok'; + const cachedNetworkData = getCachedNetworkData(); + const arBlockHeight = cachedNetworkData.cachedBlockInfo.height; + + ctx.body = { + 'gateway': 'ok', + 'ar_block_height': arBlockHeight, + 'db': await dbAccessible(ctx, arBlockHeight) + } +} + +async function dbAccessible(ctx: Router.RouterContext, arBlockHeight: number) { + const { dbSource } = ctx; + + try { + const result = await dbSource.healthCheck(`select max(block_height) as l1_max_bh from interactions where source = 'arweave';`).timeout(500, { cancel: true }); + return { + status: 'ok', + l1_last_interaction_height: result.rows[0].l1_max_bh, + l1_interaction_height_diff: arBlockHeight - result.rows[0].l1_max_bh + } + } catch (e: any) { + return { + status: 'failed', + error: e.message + } + } } From afef47897a73326c8206c40446837aa43b182979 Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Tue, 25 Apr 2023 15:01:55 +0200 Subject: [PATCH 25/95] extending endpoint /gcp/alive to include some database connection status - fix the multi insert --- src/db/databaseSource.ts | 51 ++++++++-------------- src/gateway/init.ts | 23 ++++++++-- src/gateway/router/routes/gcpAliveRoute.ts | 29 +++++++----- 3 files changed, 55 insertions(+), 48 deletions(-) diff --git a/src/db/databaseSource.ts b/src/db/databaseSource.ts index 70e5da5a..c1fbcf83 100644 --- a/src/db/databaseSource.ts +++ b/src/db/databaseSource.ts @@ -19,7 +19,6 @@ interface DbData { ssl?: { ca: string | Buffer; cert: string | Buffer; key: string | Buffer; rejectUnauthorized: boolean }; options?: Partial; primaryDb?: boolean; - healthCheckConnection?: boolean; } export class DatabaseSource { @@ -28,7 +27,7 @@ export class DatabaseSource { public healthCheckConnection: Knex | null = null; private mailClient: Transporter; - constructor(dbData: DbData[]) { + constructor(dbData: DbData[], healthCheckConnection?: DbData) { for (let i = 0; i < dbData.length; i++) { this.db[i] = this.connectDb(dbData[i]); if (dbData[i].primaryDb) { @@ -36,16 +35,14 @@ export class DatabaseSource { throw new Error('Only one db can be set primary!'); } this.primaryDb = this.db[i]; - } else if (dbData[i].healthCheckConnection) { - if (this.healthCheckConnection != null) { - throw new Error('Can set only one health check connection'); - } - this.healthCheckConnection = this.db[i]; } } if (this.primaryDb == null) { throw new Error('Exactly one db must be set as primary'); } + if (healthCheckConnection != null) { + this.healthCheckConnection = this.connectDb(healthCheckConnection); + } this.mailClient = client(); } @@ -258,6 +255,10 @@ export class DatabaseSource { return db.raw(query, bindings); } + public healthCheckEnabled(): boolean { + return this.healthCheckConnection != null; + } + public healthCheck(query: string, bindings?: any) { return this.healthCheckConnection!!.raw(query, bindings); } @@ -287,37 +288,21 @@ export class DatabaseSource { ...(dbData.ssl ? { ssl: dbData.ssl } : ''), }, useNullAsDefault: true, - pool: this.connectionPool(dbData), + pool: { + min: 5, + max: 30, + createTimeoutMillis: 3000, + acquireTimeoutMillis: 30000, + idleTimeoutMillis: 30000, + reapIntervalMillis: 1000, + createRetryIntervalMillis: 100, + propagateCreateError: false, + }, ...dbData.options, }; return knex(options); } - private connectionPool(dbData: DbData) { - if (dbData.healthCheckConnection) { - return { - min: 1, - max: 2, - createTimeoutMillis: 500, - acquireTimeoutMillis: 500, - idleTimeoutMillis: 500, - reapIntervalMillis: 500, - createRetryIntervalMillis: 100, - propagateCreateError: false, - } - } - return { - min: 5, - max: 30, - createTimeoutMillis: 3000, - acquireTimeoutMillis: 30000, - idleTimeoutMillis: 30000, - reapIntervalMillis: 1000, - createRetryIntervalMillis: 100, - propagateCreateError: false, - } - } - private currentLocalDateWithTime(): string { const tzoffset = new Date().getTimezoneOffset() * 60000; return new Date(Date.now() - tzoffset).toISOString().substring(0, 19); diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 931b6522..55c8c78b 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -99,12 +99,27 @@ export interface GatewayContext { cert: fs.readFileSync('.secrets/cert.pem'), key: fs.readFileSync('.secrets/key.pem'), }, - primaryDb: true, - healthCheckConnection: false + primaryDb: true } - const dbSource = new DatabaseSource( - [gcpDataOptions, {...gcpDataOptions, primaryDb: false, healthCheckConnection: true}]); + const healthCheckOptions = { + ...gcpDataOptions, + primaryDb: false, + options: { + pool: { + min: 1, + max: 2, + createTimeoutMillis: 500, + acquireTimeoutMillis: 500, + idleTimeoutMillis: 500, + reapIntervalMillis: 500, + createRetryIntervalMillis: 100, + propagateCreateError: false, + } + } + } + + const dbSource = new DatabaseSource([gcpDataOptions], healthCheckOptions); const app = new Koa(); diff --git a/src/gateway/router/routes/gcpAliveRoute.ts b/src/gateway/router/routes/gcpAliveRoute.ts index 91f232c1..582289f6 100644 --- a/src/gateway/router/routes/gcpAliveRoute.ts +++ b/src/gateway/router/routes/gcpAliveRoute.ts @@ -15,17 +15,24 @@ export async function gcpAliveRoute(ctx: Router.RouterContext) { async function dbAccessible(ctx: Router.RouterContext, arBlockHeight: number) { const { dbSource } = ctx; - try { - const result = await dbSource.healthCheck(`select max(block_height) as l1_max_bh from interactions where source = 'arweave';`).timeout(500, { cancel: true }); - return { - status: 'ok', - l1_last_interaction_height: result.rows[0].l1_max_bh, - l1_interaction_height_diff: arBlockHeight - result.rows[0].l1_max_bh - } - } catch (e: any) { - return { - status: 'failed', - error: e.message + if (dbSource.healthCheckEnabled()) { + try { + const result = await dbSource.healthCheck( + `select max(block_height) as l1_max_bh + from interactions + where source = 'arweave';`).timeout(500, {cancel: true}); + return { + up: 1, + l1_last_interaction_height: result.rows[0].l1_max_bh, + l1_interaction_height_diff: arBlockHeight - result.rows[0].l1_max_bh + } + } catch (e: any) { + return { + up: 0, + error: e.message + } } } + + return 'health check disabled'; } From fcaa31652d4bf8c71ee5829cf1c668604c35a1d6 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 22 May 2023 17:15:19 +0200 Subject: [PATCH 26/95] feat: interaction tags size limit verification --- package.json | 2 +- .../routes/deploy/deployContractRoute_v2.ts | 4 +- src/gateway/router/routes/sequencerRoute.ts | 108 ++++++++++-------- yarn.lock | 30 ++++- 4 files changed, 89 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 605cfb66..08622bc2 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@koa/cors": "3.2.0", "@koa/router": "10.1.1", "JSONStream": "^1.3.5", - "arbundles": "^0.7.0", + "arbundles": "^0.9.6", "arweave": "1.11.8", "axios": "^0.26.1", "dotenv": "16.0.3", diff --git a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts index a71d70d0..2d74622f 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -7,9 +7,9 @@ import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { publishContract, sendNotification } from '../../../publisher'; import { evalManifest, WarpDeployment } from './deployContractRoute'; import Arweave from 'arweave'; -import { SignatureConfig } from 'arbundles/src/constants'; +import { SignatureConfig } from 'arbundles'; import { utils } from 'ethers'; -import { longTo32ByteArray } from 'arbundles/src/utils'; +import { longTo32ByteArray } from 'arbundles'; import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; import { GatewayError } from '../../../errorHandlerMiddleware'; diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 5a028ea7..41551dcd 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -1,20 +1,21 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; -import {parseFunctionName} from '../../tasks/syncTransactions'; +import { parseFunctionName } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; -import {JWKInterface} from 'arweave/node/lib/wallet'; -import {arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger} from 'warp-contracts'; -import {getCachedNetworkData} from '../../tasks/networkInfoCache'; +import { JWKInterface } from 'arweave/node/lib/wallet'; +import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; +import { getCachedNetworkData } from '../../tasks/networkInfoCache'; import Bundlr from '@bundlr-network/client'; import { BlockData } from 'arweave/node/blocks'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { publishInteraction, sendNotification } from '../../publisher'; import { Knex } from 'knex'; -import {GatewayError} from "../../errorHandlerMiddleware"; -import {VRF} from "../../init"; +import { GatewayError } from '../../errorHandlerMiddleware'; +import { VRF } from '../../init'; +import { serializeTags } from 'arbundles'; -const {Evaluate} = require('@idena/vrf-js'); +const { Evaluate } = require('@idena/vrf-js'); export type VrfData = { index: string; @@ -24,7 +25,7 @@ export type VrfData = { }; export async function sequencerRoute(ctx: Router.RouterContext) { - const {sLogger, arweave, jwk, vrf, lastTxSync, dbSource, signatureVerification} = ctx; + const { sLogger, arweave, jwk, vrf, lastTxSync, dbSource, signatureVerification } = ctx; let trx: Knex.Transaction | null = null; @@ -34,7 +35,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { const benchmark = Benchmark.measure(); - const transaction: Transaction = new Transaction({...ctx.request.body}); + const transaction: Transaction = new Transaction({ ...ctx.request.body }); sLogger.debug('New sequencer tx', transaction.id); const originalSignature = transaction.signature; @@ -89,9 +90,9 @@ export async function sequencerRoute(ctx: Router.RouterContext) { throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); } - tags.push({name: 'Sequencer-Mills', value: '' + millis}); - tags.push({name: 'Sequencer-Sort-Key', value: sortKey}); - tags.push({name: "Sequencer-Prev-Sort-Key", value: contractPrevSortKey || 'null'}); + tags.push({ name: 'Sequencer-Mills', value: '' + millis }); + tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); + tags.push({ name: 'Sequencer-Prev-Sort-Key', value: contractPrevSortKey || 'null' }); let vrfData = null; if (requestVrfTag !== '') { @@ -115,8 +116,8 @@ export async function sequencerRoute(ctx: Router.RouterContext) { ); const verified = isEvmSigner - ? await signatureVerification.process(interaction) - : await arweave.transactions.verify(transaction); + ? await signatureVerification.process(interaction) + : await arweave.transactions.verify(transaction); if (!verified) { throw new Error('Could not properly verify transaction.'); } @@ -129,7 +130,14 @@ export async function sequencerRoute(ctx: Router.RouterContext) { sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); sLogger.debug('inserting into tables'); - await trx.raw(` + try { + serializeTags(tags); + } catch (e) { + throw new Error(`Tags could not be serialized properly. It may be due to the big input size.`); + } + + await trx.raw( + ` WITH ins_interaction AS ( INSERT INTO interactions (interaction_id, interaction, @@ -172,34 +180,36 @@ export async function sequencerRoute(ctx: Router.RouterContext) { INTO bundle_items (interaction_id, state, transaction, tags) SELECT i.id, 'PENDING', :original_transaction, :tags FROM ins_interaction i; - `, { - interaction_id: transaction.id, - interaction: interaction, - block_height: currentHeight, - block_id: currentBlockId, - contract_id: contractTag, - function: functionName, - input: inputTag, - confirmation_status: 'confirmed', - confirming_peer: BUNDLR_NODE1_URL, - source: 'redstone-sequencer', - block_timestamp: currentBlockTimestamp, - interact_write: internalWrites, - sort_key: sortKey, - evolve: evolve, - testnet: testnetVersion, - prev_sort_key: contractPrevSortKey, - owner: originalOwner, - original_transaction: ctx.request.body, - tags: JSON.stringify(tags), - sync_timestamp: millis - }); + `, + { + interaction_id: transaction.id, + interaction: interaction, + block_height: currentHeight, + block_id: currentBlockId, + contract_id: contractTag, + function: functionName, + input: inputTag, + confirmation_status: 'confirmed', + confirming_peer: BUNDLR_NODE1_URL, + source: 'redstone-sequencer', + block_timestamp: currentBlockTimestamp, + interact_write: internalWrites, + sort_key: sortKey, + evolve: evolve, + testnet: testnetVersion, + prev_sort_key: contractPrevSortKey, + owner: originalOwner, + original_transaction: ctx.request.body, + tags: JSON.stringify(tags), + sync_timestamp: millis, + } + ); await trx.commit(); sLogger.info('Total sequencer processing', benchmark.elapsed()); ctx.body = { - id: transaction.id + id: transaction.id, }; sendNotification(ctx, contractTag, undefined, interaction); @@ -218,7 +228,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { if (trx != null) { await trx.rollback(); } - throw new GatewayError(e?.message || e) + throw new GatewayError(e?.message || e); } } @@ -237,7 +247,7 @@ function createInteraction( ) { const interaction: any = { id: transaction.id, - owner: {address: originalAddress}, + owner: { address: originalAddress }, recipient: transaction.target, tags: decodedTags, block: { @@ -278,10 +288,10 @@ function generateVrfTags(sortKey: string, vrf: VRF, arweave: Arweave) { return { vrfTags: [ - {name: 'vrf-index', value: vrfData.index}, - {name: 'vrf-proof', value: vrfData.proof}, - {name: 'vrf-bigint', value: vrfData.bigint}, - {name: 'vrf-pubkey', value: vrfData.pubkey}, + { name: 'vrf-index', value: vrfData.index }, + { name: 'vrf-proof', value: vrfData.proof }, + { name: 'vrf-bigint', value: vrfData.bigint }, + { name: 'vrf-pubkey', value: vrfData.pubkey }, ], vrfData, }; @@ -323,8 +333,8 @@ async function prepareTags( const internalWrites: string[] = []; for (const tag of transaction.tags) { - const key = tag.get('name', {decode: true, string: true}); - const value = tag.get('value', {decode: true, string: true}); + const key = tag.get('name', { decode: true, string: true }); + const value = tag.get('value', { decode: true, string: true }); if (key == SmartWeaveTags.CONTRACT_TX_ID) { contractTag = value; } @@ -387,9 +397,9 @@ export async function uploadToBundlr( ) { const uploadBenchmark = Benchmark.measure(); - const bTx = bundlr.createTransaction(JSON.stringify(transaction), {tags}); + const bTx = bundlr.createTransaction(JSON.stringify(transaction), { tags }); await bTx.sign(); - const bundlrResponse = await bundlr.uploader.uploadTransaction(bTx, {getReceiptSignature: true}); + const bundlrResponse = await bundlr.uploader.uploadTransaction(bTx, { getReceiptSignature: true }); logger.debug('Uploading to bundlr', { elapsed: uploadBenchmark.elapsed(), @@ -403,7 +413,7 @@ export async function uploadToBundlr( ); } - return {bTx, bundlrResponse}; + return { bTx, bundlrResponse }; } async function createSortKey( diff --git a/yarn.lock b/yarn.lock index 83de8e6a..b1dd81b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1160,7 +1160,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2": +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -1268,7 +1268,7 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/wallet@5.7.0": +"@ethersproject/wallet@5.7.0", "@ethersproject/wallet@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== @@ -2364,6 +2364,30 @@ arbundles@^0.7.0: secp256k1 "^4.0.2" tmp-promise "^3.0.2" +arbundles@^0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/arbundles/-/arbundles-0.9.6.tgz#7964653d91c87ce3fad232c38d08ace85ac3f004" + integrity sha512-YtNVHLJ99utKgwu7ss4N6A4tUHSitMho85DGLlHjlTMWlninL8QU6Cczjp8luOzG0ong3V3OQ3QsMHRe+GYrKw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/providers" "^5.7.2" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wallet" "^5.7.0" + "@noble/ed25519" "^1.6.1" + arweave "=1.11.8" + base64url "^3.0.1" + bs58 "^4.0.1" + keccak "^3.0.2" + secp256k1 "^4.0.2" + optionalDependencies: + "@randlabs/myalgo-connect" "^1.1.2" + algosdk "^1.13.1" + arweave-stream-tx "^1.1.0" + multistream "^4.1.0" + tmp-promise "^3.0.2" + archiver-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" @@ -2441,7 +2465,7 @@ arweave@1.11.6, arweave@^1.10.13, arweave@^1.11.4, arweave@^1.11.6: bignumber.js "^9.0.2" util "^0.12.4" -arweave@1.11.8: +arweave@1.11.8, arweave@=1.11.8: version "1.11.8" resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.11.8.tgz#09376e0c6cec40a661cbb27a306cb11c0a663cd8" integrity sha512-58ODeNPIC4OjaOCl2bXjKbOFGsiVZFs+DkQg3BvQGvFWNqw1zTJ4Jp01xGUz+GbdOaDyJcCC0g3l0HwdJfFPyw== From 40bde13282d0ea73c25491351f5062b674bcad6d Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Mon, 5 Jun 2023 17:34:21 +0200 Subject: [PATCH 27/95] fix: set lastSortKey in interaction --- src/gateway/router/routes/sequencerRoute.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 41551dcd..40453cb6 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -265,6 +265,7 @@ function createInteraction( source: 'redstone-sequencer', vrf: vrfData, testnet: testnetVersion, + lastSortKey }; if (signature) { From 93e44c1c327bb16c5435ff0ed63c4a79cf786a87 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 19 Jun 2023 12:17:27 +0200 Subject: [PATCH 28/95] fix: contract data for nested bundle contracts (#170) --- .../routes/contracts/contractDataRoute.ts | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/gateway/router/routes/contracts/contractDataRoute.ts b/src/gateway/router/routes/contracts/contractDataRoute.ts index 1e3a6f0b..190a0557 100644 --- a/src/gateway/router/routes/contracts/contractDataRoute.ts +++ b/src/gateway/router/routes/contracts/contractDataRoute.ts @@ -1,15 +1,15 @@ import Router from '@koa/router'; import Arweave from 'arweave'; -import {ArweaveWrapper, Benchmark, Tags, WarpLogger} from 'warp-contracts'; -import {decodeTags, getTagByName, isTxIdValid} from '../../../../utils'; +import { ArweaveWrapper, Benchmark, Tags, WarpLogger } from 'warp-contracts'; +import { decodeTags, getTagByName, isTxIdValid } from '../../../../utils'; import Transaction from 'arweave/node/lib/transaction'; import { WarpDeployment } from '../deploy/deployContractRoute'; -import {GatewayError} from "../../../errorHandlerMiddleware"; +import { GatewayError } from '../../../errorHandlerMiddleware'; export async function contractDataRoute(ctx: Router.RouterContext) { - const {logger, dbSource, arweave, arweaveWrapper} = ctx; + const { logger, dbSource, arweave, arweaveWrapper } = ctx; - const {id} = ctx.params; + const { id } = ctx.params; if (!isTxIdValid(id as string)) { throw new GatewayError('Incorrect contract transaction id.', 403); @@ -23,7 +23,8 @@ export async function contractDataRoute(ctx: Router.RouterContext) { SELECT bundler_contract_tx_id as "bundlerContractTxId", contract_tx -> 'tags' as "contractTags", deployment_type as "deploymentType", - bundler_contract_node as "bundlrContractNode" + bundler_contract_node as "bundlrContractNode", + contract_id as "contractId" FROM contracts WHERE contract_id = ?; `, @@ -37,9 +38,10 @@ export async function contractDataRoute(ctx: Router.RouterContext) { tags = decodeTags(result?.rows[0].contractTags); } - const {data, contentType} = await getContractData( + const { data, contentType } = await getContractData( arweave, logger, + result?.rows[0].contractId, result?.rows[0].bundlerContractTxId, tags, arweaveWrapper, @@ -50,13 +52,13 @@ export async function contractDataRoute(ctx: Router.RouterContext) { ctx.set('Content-Type', contentType); logger.debug('Contract data loaded in', benchmark.elapsed()); } - } async function getContractData( arweave: Arweave, logger: WarpLogger, id: string, + bundlrId: string, tags: { name: string; value: string }[], arweaveWrapper: ArweaveWrapper, deploymentType: string, @@ -64,29 +66,28 @@ async function getContractData( ) { let data: ArrayBuffer | Buffer; + const effectiveId = deploymentType == WarpDeployment.Wrapped ? bundlrId : id; try { - data = await arweaveWrapper.txData(id); + data = await arweaveWrapper.txData(effectiveId); } catch (e) { logger.error(`Error from Arweave Gateway while loading data: `, e); - data = await fetch(`${bundlrContractNode}/tx/${id}/data`).then((res) => { + data = await fetch(`${bundlrContractNode}/tx/${effectiveId}/data`).then((res) => { return res.arrayBuffer(); }); } - const strData = arweave.utils.bufferToString(data); - - logger.debug('strData', strData); - if (deploymentType == WarpDeployment.External) { + if (deploymentType == WarpDeployment.External || deploymentType == WarpDeployment.Direct) { const contentType = getTagByName(tags, 'Content-Type'); logger.debug(`Content type for id: ${id}: `, contentType); - return {data: strData, contentType}; + return { data, contentType }; } else { - const tx = new Transaction({...JSON.parse(strData)}); + const strData = arweave.utils.bufferToString(data); + const tx = new Transaction({ ...JSON.parse(strData) }); const txData = Buffer.from(tx.data); const contentType = getContentTypeFromTx(tx); logger.debug(`Content type for id: ${id}: `, contentType); - return {data: txData, contentType}; + return { data: txData, contentType }; } } @@ -94,7 +95,7 @@ function getContentTypeFromTx(tx: Transaction) { const tagContentType = tx .get('tags') // @ts-ignore - .find((tag: BaseObject) => tag.get('name', {decode: true, string: true}) == 'Content-Type'); + .find((tag: BaseObject) => tag.get('name', { decode: true, string: true }) == 'Content-Type'); - return tagContentType.get('value', {decode: true, string: true}); + return tagContentType.get('value', { decode: true, string: true }); } From c4461bb10c821c8ab1d7e9fd1a55939960f2df66 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 19 Jun 2023 13:42:41 +0200 Subject: [PATCH 29/95] fix: get chached network info only if not in replica (#171) --- src/gateway/init.ts | 72 ++++++++++++---------- src/gateway/router/routes/gcpAliveRoute.ts | 32 +++++----- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 55c8c78b..5b826728 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -1,27 +1,27 @@ import yargs from 'yargs'; -import {hideBin} from 'yargs/helpers'; +import { hideBin } from 'yargs/helpers'; import Koa from 'koa'; import Application from 'koa'; import bodyParser from 'koa-bodyparser'; -import {ArweaveWrapper, LexicographicalInteractionsSorter, LoggerFactory, WarpLogger} from 'warp-contracts'; +import { ArweaveWrapper, LexicographicalInteractionsSorter, LoggerFactory, WarpLogger } from 'warp-contracts'; import Arweave from 'arweave'; -import {runGatewayTasks} from './runGatewayTasks'; +import { runGatewayTasks } from './runGatewayTasks'; import gatewayRouter from './router/gatewayRouter'; import * as fs from 'fs'; import cluster from 'cluster'; import welcomeRouter from './router/welcomeRouter'; import Bundlr from '@bundlr-network/client'; -import {initBundlr} from '../bundlr/connect'; -import {JWKInterface} from 'arweave/node/lib/wallet'; -import {runNetworkInfoCacheTask} from './tasks/networkInfoCache'; +import { initBundlr } from '../bundlr/connect'; +import { JWKInterface } from 'arweave/node/lib/wallet'; +import { runNetworkInfoCacheTask } from './tasks/networkInfoCache'; import Redis from 'ioredis'; -import {LastTxSync} from './LastTxSyncer'; -import {initPubSub} from 'warp-contracts-pubsub'; +import { LastTxSync } from './LastTxSyncer'; +import { initPubSub } from 'warp-contracts-pubsub'; // @ts-ignore -import {EvmSignatureVerificationServerPlugin} from 'warp-signature/server'; -import {DatabaseSource} from '../db/databaseSource'; -import {accessLogMiddleware} from "./accessLogMiddleware"; -import {errorHandlerMiddleware} from "./errorHandlerMiddleware"; +import { EvmSignatureVerificationServerPlugin } from 'warp-signature/server'; +import { DatabaseSource } from '../db/databaseSource'; +import { accessLogMiddleware } from './accessLogMiddleware'; +import { errorHandlerMiddleware } from './errorHandlerMiddleware'; const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; @@ -53,6 +53,7 @@ export interface GatewayContext { localEnv: boolean; appSync?: string; signatureVerification: EvmSignatureVerificationServerPlugin; + replica: boolean; } (async () => { @@ -88,19 +89,21 @@ export interface GatewayContext { logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode. noSync = ${noSync}`); const arweave = initArweave(); - const {bundlr, jwk} = initBundlr(logger); + const { bundlr, jwk } = initBundlr(logger); - const gcpDataOptions = { + const gcpDataOptions = { client: 'pg' as 'pg', url: process.env.DB_URL_GCP as string, - ssl: localEnv ? undefined : { - rejectUnauthorized: false, - ca: fs.readFileSync('.secrets/ca.pem'), - cert: fs.readFileSync('.secrets/cert.pem'), - key: fs.readFileSync('.secrets/key.pem'), - }, - primaryDb: true - } + ssl: localEnv + ? undefined + : { + rejectUnauthorized: false, + ca: fs.readFileSync('.secrets/ca.pem'), + cert: fs.readFileSync('.secrets/cert.pem'), + key: fs.readFileSync('.secrets/key.pem'), + }, + primaryDb: true, + }; const healthCheckOptions = { ...gcpDataOptions, @@ -115,9 +118,9 @@ export interface GatewayContext { reapIntervalMillis: 500, createRetryIntervalMillis: 100, propagateCreateError: false, - } - } - } + }, + }, + }; const dbSource = new DatabaseSource([gcpDataOptions], healthCheckOptions); @@ -131,18 +134,21 @@ export interface GatewayContext { app.context.bundlr = bundlr; app.context.jwk = jwk; app.context.arweaveWrapper = new ArweaveWrapper(arweave); - app.context.arweaveWrapperGqlGoldsky = new ArweaveWrapper(Arweave.init({ - host: 'arweave-search.goldsky.com', - port: 443, - protocol: 'https', - timeout: 20000, - logging: false, - })); + app.context.arweaveWrapperGqlGoldsky = new ArweaveWrapper( + Arweave.init({ + host: 'arweave-search.goldsky.com', + port: 443, + protocol: 'https', + timeout: 20000, + logging: false, + }) + ); app.context.sorter = new LexicographicalInteractionsSorter(arweave); app.context.lastTxSync = new LastTxSync(); app.context.localEnv = localEnv; app.context.appSync = appSync; app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); + app.context.replica = replica; app.use(errorHandlerMiddleware); app.use(accessLogMiddleware); @@ -233,7 +239,7 @@ export interface GatewayContext { logger.info(`Creating lock file for ${cluster.worker?.id}`); // note: if another process in cluster have already created the file - writing here // will fail thanks to wx flags. https://stackoverflow.com/a/31777314 - fs.writeFileSync('gateway.lock', '' + cluster.worker?.id, {flag: 'wx'}); + fs.writeFileSync('gateway.lock', '' + cluster.worker?.id, { flag: 'wx' }); removeLock = true; // note: only one worker in cluster runs the gateway tasks diff --git a/src/gateway/router/routes/gcpAliveRoute.ts b/src/gateway/router/routes/gcpAliveRoute.ts index 582289f6..9dcfee11 100644 --- a/src/gateway/router/routes/gcpAliveRoute.ts +++ b/src/gateway/router/routes/gcpAliveRoute.ts @@ -1,36 +1,38 @@ import Router from '@koa/router'; -import {getCachedNetworkData} from "../../tasks/networkInfoCache"; +import { getCachedNetworkData } from '../../tasks/networkInfoCache'; export async function gcpAliveRoute(ctx: Router.RouterContext) { - const cachedNetworkData = getCachedNetworkData(); - const arBlockHeight = cachedNetworkData.cachedBlockInfo.height; + const arBlockHeight = ctx.replica ? null : getCachedNetworkData().cachedBlockInfo.height; ctx.body = { - 'gateway': 'ok', - 'ar_block_height': arBlockHeight, - 'db': await dbAccessible(ctx, arBlockHeight) - } + gateway: 'ok', + db: await dbAccessible(ctx, arBlockHeight), + ...(arBlockHeight && { ar_block_height: arBlockHeight }), + }; } -async function dbAccessible(ctx: Router.RouterContext, arBlockHeight: number) { +async function dbAccessible(ctx: Router.RouterContext, arBlockHeight: number | null) { const { dbSource } = ctx; if (dbSource.healthCheckEnabled()) { try { - const result = await dbSource.healthCheck( - `select max(block_height) as l1_max_bh + const result = await dbSource + .healthCheck( + `select max(block_height) as l1_max_bh from interactions - where source = 'arweave';`).timeout(500, {cancel: true}); + where source = 'arweave';` + ) + .timeout(500, { cancel: true }); return { up: 1, l1_last_interaction_height: result.rows[0].l1_max_bh, - l1_interaction_height_diff: arBlockHeight - result.rows[0].l1_max_bh - } + ...(arBlockHeight && { l1_interaction_height_diff: arBlockHeight - result.rows[0].l1_max_bh }), + }; } catch (e: any) { return { up: 0, - error: e.message - } + error: e.message, + }; } } From fa9b45190d7fe978982a06e5a74aaa12dbfa28f0 Mon Sep 17 00:00:00 2001 From: Asia Date: Wed, 28 Jun 2023 10:10:30 +0200 Subject: [PATCH 30/95] feat: interaction data items endpoint (#172) --- package.json | 1 + src/gateway/publisher.ts | 2 +- src/gateway/router/gatewayRouter.ts | 5 +- .../routes/deploy/deployContractRoute_v2.ts | 4 +- src/gateway/router/routes/sequencerRoute.ts | 61 +++-- .../router/routes/sequencerRoute_v2.ts | 222 ++++++++++++++++++ src/gateway/tasks/syncTransactions.ts | 14 +- tsconfig.json | 2 +- yarn.lock | 28 +++ 9 files changed, 310 insertions(+), 29 deletions(-) create mode 100644 src/gateway/router/routes/sequencerRoute_v2.ts diff --git a/package.json b/package.json index 08622bc2..6dbab556 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "raw-body": "^2.5.1", "undici": "5.21.0", "uuid": "^9.0.0", + "warp-arbundles": "1.0.0", "warp-contracts": "1.2.48", "warp-contracts-pubsub": "^1.0.3", "warp-contracts-subscription-plugin": "1.0.4", diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index 72694bce..65f49802 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -61,7 +61,7 @@ export function publishInteraction( ) { const { logger, appSync } = ctx; - if (!appSync || ctx.localEnv) { + if (!appSync) { logger.warn('App sync key not set'); return; } diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index cf54597e..b50f8177 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -8,6 +8,7 @@ import { contractWithSourceRoute } from './routes/contracts/contractWithSourceRo import { contractWithSourceRoute_v2 } from './routes/contracts/contractWithSourceRoute_v2'; import { interactionRoute } from './routes/interactions/interactionRoute'; import { sequencerRoute } from './routes/sequencerRoute'; +import { sequencerRoute_v2 } from './routes/sequencerRoute_v2'; import { interactionsStreamRoute } from './routes/interactions/interactionsStreamRoute'; import { deployContractRoute } from './routes/deploy/deployContractRoute'; import { arweaveBlockRoute, arweaveInfoRoute } from './routes/arweaveInfoRoute'; @@ -26,7 +27,7 @@ import { deploySourceRoute_v2 } from './routes/deploy/deploySourceRoute_v2'; import { deployContractRoute_v2 } from './routes/deploy/deployContractRoute_v2'; import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; -import {gcpAliveRoute} from "./routes/gcpAliveRoute"; +import { gcpAliveRoute } from './routes/gcpAliveRoute'; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -60,7 +61,7 @@ const gatewayRouter = (replica: boolean): Router => { // post if (!replica) { router.post('/sequencer/register', sequencerRoute); - + router.post('/v2/sequencer/register', sequencerRoute_v2); router.post('/contracts/deploy', deployContractRoute); router.post('/contracts/deploy-bundled', deployBundledRoute); router.post('/sources/deploy', deploySourceRoute); diff --git a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts index 2d74622f..e8f07579 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -185,11 +185,13 @@ export function getTestnetTag(tags: { name: string; value: string }[]) { } } -export async function determineOwner(dataItem: DataItem, arweave: Arweave) { +export async function determineOwner(dataItem: DataItem, arweave: Arweave): Promise { if (dataItem.signatureType == SignatureConfig.ARWEAVE) { return await arweave.wallets.ownerToAddress(dataItem.owner); } else if (dataItem.signatureType == SignatureConfig.ETHEREUM) { return utils.computeAddress(utils.hexlify(dataItem.rawOwner)); + } else { + throw new Error(`Signature type: ${dataItem.signatureType} is not supported.`); } } diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 40453cb6..ae2ebc2b 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -1,6 +1,6 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; -import { parseFunctionName } from '../../tasks/syncTransactions'; +import { parseFunctionName, safeParseInput } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; @@ -14,6 +14,7 @@ import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { VRF } from '../../init'; import { serializeTags } from 'arbundles'; +import { DataItem } from 'arbundles'; const { Evaluate } = require('@idena/vrf-js'); @@ -232,8 +233,8 @@ export async function sequencerRoute(ctx: Router.RouterContext) { } } -function createInteraction( - transaction: Transaction, +export function createInteraction( + transactionOrDataItem: Transaction | DataItem, originalAddress: string, decodedTags: GQLTagInterface[], currentHeight: number, @@ -246,9 +247,9 @@ function createInteraction( lastSortKey: string | null ) { const interaction: any = { - id: transaction.id, + id: transactionOrDataItem.id, owner: { address: originalAddress }, - recipient: transaction.target, + recipient: transactionOrDataItem.target, tags: decodedTags, block: { height: currentHeight, @@ -256,16 +257,16 @@ function createInteraction( timestamp: blockInfo.timestamp, }, fee: { - winston: transaction.reward, + winston: isTransaction(transactionOrDataItem) ? transactionOrDataItem.reward : '0', }, quantity: { - winston: transaction.quantity, + winston: isTransaction(transactionOrDataItem) ? transactionOrDataItem.quantity : '', }, sortKey: sortKey, source: 'redstone-sequencer', vrf: vrfData, testnet: testnetVersion, - lastSortKey + lastSortKey, }; if (signature) { @@ -275,7 +276,11 @@ function createInteraction( return interaction; } -function generateVrfTags(sortKey: string, vrf: VRF, arweave: Arweave) { +function isTransaction(transactionOrDataItem: Transaction | DataItem): transactionOrDataItem is Transaction { + return (transactionOrDataItem as Transaction).last_tx != undefined; +} + +export function generateVrfTags(sortKey: string, vrf: VRF, arweave: Arweave) { const privateKey = vrf.privKey.toArray(); const data = arweave.utils.stringToBuffer(sortKey); const [index, proof] = Evaluate(privateKey, data); @@ -367,15 +372,14 @@ async function prepareTags( originalAddress = await arweave.wallets.ownerToAddress(originalOwner); } - const tags = [ - { name: 'Sequencer', value: 'RedStone' }, - { name: 'Sequencer-Owner', value: originalAddress }, - { name: 'Sequencer-Tx-Id', value: transaction.id }, - { name: 'Sequencer-Block-Height', value: '' + currentHeight }, - { name: 'Sequencer-Block-Id', value: currentBlockId }, - { name: 'Sequencer-Block-Timestamp', value: '' + currentBlockTimestamp }, - ...decodedTags, - ]; + const tags = getUploaderTags( + originalAddress, + transaction.id, + currentHeight, + currentBlockId, + currentBlockTimestamp, + decodedTags + ); return { contractTag, @@ -390,6 +394,25 @@ async function prepareTags( }; } +export function getUploaderTags( + originalAddress: string, + id: string, + currentHeight: number, + currentBlockId: string, + currentBlockTimestamp: number, + decodedTags: GQLTagInterface[] +): GQLTagInterface[] { + return [ + { name: 'Sequencer', value: 'RedStone' }, + { name: 'Sequencer-Owner', value: originalAddress }, + { name: 'Sequencer-Tx-Id', value: id }, + { name: 'Sequencer-Block-Height', value: '' + currentHeight }, + { name: 'Sequencer-Block-Id', value: currentBlockId }, + { name: 'Sequencer-Block-Timestamp', value: '' + currentBlockTimestamp }, + ...decodedTags, + ]; +} + export async function uploadToBundlr( transaction: Transaction, bundlr: Bundlr, @@ -417,7 +440,7 @@ export async function uploadToBundlr( return { bTx, bundlrResponse }; } -async function createSortKey( +export async function createSortKey( arweave: Arweave, jwk: JWKInterface, blockId: string, diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts new file mode 100644 index 00000000..b23e877a --- /dev/null +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -0,0 +1,222 @@ +import Router from '@koa/router'; +import { parseFunctionName, safeParseInput } from '../../tasks/syncTransactions'; +import { Benchmark, SmartWeaveTags, VrfData } from 'warp-contracts'; +import { getCachedNetworkData } from '../../tasks/networkInfoCache'; +import { isTxIdValid } from '../../../utils'; +import { BUNDLR_NODE1_URL } from '../../../constants'; +import { publishInteraction, sendNotification } from '../../publisher'; +import { Knex } from 'knex'; +import { GatewayError } from '../../errorHandlerMiddleware'; +import { DataItem } from 'arbundles'; +import { createInteraction, generateVrfTags, getUploaderTags } from './sequencerRoute'; +import { createSortKey } from './sequencerRoute'; +import { tagsExceedLimit } from 'warp-arbundles'; +import rawBody from 'raw-body'; +import { b64UrlToString } from 'arweave/node/lib/utils'; +import { determineOwner } from './deploy/deployContractRoute_v2'; + +export async function sequencerRoute_v2(ctx: Router.RouterContext) { + const { sLogger, arweave, jwk, vrf, lastTxSync, dbSource, bundlr } = ctx; + + let trx: Knex.Transaction | null = null; + + try { + const initialBenchmark = Benchmark.measure(); + const cachedNetworkData = getCachedNetworkData(); + if (cachedNetworkData == null) { + throw new Error('Network or block info not yet cached.'); + } + const benchmark = Benchmark.measure(); + + const rawDataItem: Buffer = await rawBody(ctx.req); + const interactionDataItem = new DataItem(rawDataItem); + + if (tagsExceedLimit(interactionDataItem.tags)) { + throw new Error(`Interaction data item tags exceed limit.`); + } + + if (b64UrlToString(interactionDataItem.data).length > 4) { + throw new Error("Interaction data item's data field exceeds 4 bytes limit."); + } + + sLogger.debug('New sequencer data item', interactionDataItem.id); + + const isInteractionDataItemValid = await interactionDataItem.isValid(); + if (!isInteractionDataItemValid) { + ctx.throw(400, 'Interaction data item binary is not valid.'); + } + + const currentHeight = cachedNetworkData.cachedBlockInfo.height; + sLogger.debug(`Sequencer height: ${interactionDataItem.id}: ${currentHeight}`); + + if (!currentHeight) { + throw new Error('Current height not set'); + } + + const currentBlockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; + if (!currentBlockTimestamp) { + throw new Error('Current block timestamp not set'); + } + + const currentBlockId = cachedNetworkData.cachedNetworkInfo.current; + if (!currentBlockId) { + throw new Error('Current block not set'); + } + + const originalSignature = interactionDataItem.signature; + const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; + const originalAddress = await determineOwner(interactionDataItem, arweave); + const testnetVersion = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET)?.value || null; + const internalWrites: string[] = []; + interactionDataItem.tags + .filter((t) => t.name == SmartWeaveTags.INTERACT_WRITE) + .forEach((t) => internalWrites.push(t.value)); + const trx = await dbSource.primaryDb.transaction(); + const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); + const millis = Date.now(); + const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, interactionDataItem.id, currentHeight); + if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { + throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); + } + + const tags = getUploaderTags( + originalAddress, + interactionDataItem.id, + currentHeight, + currentBlockId, + currentBlockTimestamp, + interactionDataItem.tags + ); + tags.push({ name: 'Sequencer-Mills', value: '' + millis }); + tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); + tags.push({ name: 'Sequencer-Prev-Sort-Key', value: contractPrevSortKey || 'null' }); + + let vrfData: VrfData | null = null; + const requestVrfTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.REQUEST_VRF)?.value || null; + if (requestVrfTag) { + const vrfGen = generateVrfTags(sortKey, vrf, arweave); + tags.push(...vrfGen.vrfTags); + vrfData = vrfGen.vrfData; + } + + const inputTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.INPUT)?.value || ''; + + const parsedInput = safeParseInput(inputTag, sLogger); + const functionName = parseFunctionName(inputTag, sLogger); + let evolve: string | null; + evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; + + sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); + + const interaction = createInteraction( + interactionDataItem, + originalAddress, + interactionDataItem.tags, + currentHeight, + currentBlockId, + cachedNetworkData.cachedBlockInfo, + sortKey, + vrfData, + originalSignature, + testnetVersion, + parsedInput + ); + + sLogger.debug('inserting into tables'); + + await trx.raw( + ` + WITH ins_interaction AS ( + INSERT INTO interactions (interaction_id, + interaction, + block_height, + block_id, + contract_id, + function, + input, + confirmation_status, + confirming_peer, + source, + block_timestamp, + interact_write, + sort_key, + evolve, + testnet, + last_sort_key, + owner, + sync_timestamp) + VALUES (:interaction_id, + :interaction, + :block_height, + :block_id, + :contract_id, + :function, + :input, + :confirmation_status, + :confirming_peer, + :source, + :block_timestamp, + :interact_write, + :sort_key, + :evolve, + :testnet, + :prev_sort_key, + :owner, + :sync_timestamp) + RETURNING id) + INSERT + INTO bundle_items (interaction_id, state, transaction, tags, data_item) + SELECT i.id, 'PENDING', :original_transaction, :tags, :data_item + FROM ins_interaction i; + `, + { + interaction_id: interactionDataItem.id, + interaction: interaction, + block_height: currentHeight, + block_id: currentBlockId, + contract_id: contractTag, + function: functionName, + input: inputTag, + confirmation_status: 'confirmed', + confirming_peer: BUNDLR_NODE1_URL, + source: 'redstone-sequencer', + block_timestamp: currentBlockTimestamp, + interact_write: internalWrites, + sort_key: sortKey, + evolve: evolve, + testnet: testnetVersion, + prev_sort_key: contractPrevSortKey, + owner: originalAddress, + original_transaction: ctx.request.body, + tags: JSON.stringify(tags), + sync_timestamp: millis, + data_item: interactionDataItem.getRaw(), + } + ); + + await trx.commit(); + sLogger.info('Total sequencer processing', benchmark.elapsed()); + + ctx.body = { + id: interactionDataItem.id, + }; + + sendNotification(ctx, contractTag, undefined, interaction); + publishInteraction( + ctx, + contractTag, + interaction, + sortKey, + contractPrevSortKey, + functionName, + 'redstone-sequencer', + millis, + testnetVersion + ); + } catch (e: any) { + if (trx != null) { + await (trx as Knex.Transaction).rollback(); + } + throw new GatewayError(e?.message || e); + } +} diff --git a/src/gateway/tasks/syncTransactions.ts b/src/gateway/tasks/syncTransactions.ts index cf932631..993efa6a 100644 --- a/src/gateway/tasks/syncTransactions.ts +++ b/src/gateway/tasks/syncTransactions.ts @@ -152,7 +152,7 @@ async function syncTransactions(context: GatewayContext, pastBlocksAmount: numbe // note: publish is set to true only for the main syncing task - and also only this task should // store info about last processed height if (publish) { - fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({lastProcessedBlockHeight: heightTo}), 'utf-8'); + fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: heightTo }), 'utf-8'); } return; } @@ -255,12 +255,12 @@ async function syncTransactions(context: GatewayContext, pastBlocksAmount: numbe return; } finally { if (publish) { - fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({lastProcessedBlockHeight: heightTo}), 'utf-8'); + fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: heightTo }), 'utf-8'); } } } else { if (publish) { - fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({lastProcessedBlockHeight: heightTo}), 'utf-8'); + fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: heightTo }), 'utf-8'); } } @@ -320,7 +320,11 @@ async function load(context: GatewayContext, from: number, to: number): Promise< }; const { logger, arweaveWrapperGqlGoldsky } = context; - return await loadPages({ logger, arweaveWrapper: arweaveWrapperGqlGoldsky }, INTERACTIONS_QUERY, mainTransactionsVariables); + return await loadPages( + { logger, arweaveWrapper: arweaveWrapperGqlGoldsky }, + INTERACTIONS_QUERY, + mainTransactionsVariables + ); } export function testnetVersion(tx: GQLEdgeInterface): string | null { @@ -338,7 +342,7 @@ export function parseFunctionName(input: string, logger: WarpLogger) { } } -function safeParseInput(input: string, logger: WarpLogger) { +export function safeParseInput(input: string, logger: WarpLogger) { try { return JSON.parse(input); } catch (e) { diff --git a/tsconfig.json b/tsconfig.json index ddd525be..5a0ca0fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,5 @@ "ts-node": { "files": true }, - "files": ["src/TsLogFactory.d.ts", "src/JSONStream.d.ts", "src/gateway/init.ts"], + "files": ["src/TsLogFactory.d.ts", "src/JSONStream.d.ts", "src/gateway/init.ts"] } diff --git a/yarn.lock b/yarn.lock index b1dd81b7..ea360dd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2477,6 +2477,16 @@ arweave@1.11.8, arweave@=1.11.8: bignumber.js "^9.0.2" util "^0.12.4" +arweave@^1.13.7: + version "1.13.7" + resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.13.7.tgz#cda8534c833baec372a7052c61f53b4e39a886d7" + integrity sha512-Hv+x2bSI6UyBHpuVbUDMMpMje1ETfpJWj52kKfz44O0IqDRi/LukOkkDUptup1p6OT6KP1/DdpnUnsNHoskFeA== + dependencies: + arconnect "^0.4.2" + asn1.js "^5.4.1" + base64-js "^1.5.1" + bignumber.js "^9.0.2" + asn1.js@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -7118,6 +7128,16 @@ walker@^1.0.7: dependencies: makeerror "1.0.12" +warp-arbundles@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/warp-arbundles/-/warp-arbundles-1.0.0.tgz#167f112d15ba0da698c22c5268a40a01a503b3d9" + integrity sha512-MC+NvottS+D/gdwP8tPZfqH1ob7sD5pFYhM/E0ZqP6KyRRAOdr7+WyuwB93265w8M+4OFTnQx8bgpEIqTTYPgw== + dependencies: + arweave "^1.13.7" + base64url "^3.0.1" + buffer "^6.0.3" + warp-isomorphic "^1.0.4" + warp-contracts-pubsub@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/warp-contracts-pubsub/-/warp-contracts-pubsub-1.0.3.tgz#5d2636b3da95c7b2a31b51668b70b9c3fb3685a6" @@ -7176,6 +7196,14 @@ warp-contracts@1.2.48: vm2 "3.9.11" warp-wasm-metering "1.0.0" +warp-isomorphic@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/warp-isomorphic/-/warp-isomorphic-1.0.4.tgz#1017eba260e0f0228b33b94b9e36a1afe54e09d8" + integrity sha512-W77IoLjq/eu5bY1uRrlmVt5lLDoIHeZ0ozJ/j67FTnxvZRXu887biEnom1nx8q1UgOKyJh8eQYFQaE2FLlKhFg== + dependencies: + buffer "^6.0.3" + undici "^5.8.0" + warp-signature@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/warp-signature/-/warp-signature-1.0.4.tgz#34868050192e10b3d2577db13fe1c2ec5242086f" From c19c82a47212faf0dbb5dd858fb86943595b38e8 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Fri, 21 Jul 2023 12:09:46 +0200 Subject: [PATCH 31/95] temp interaction conf. status --- .../router/routes/interactions/interactionsSortKeyRoute_v2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts index 46f5eb67..d02aefbd 100644 --- a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts @@ -17,7 +17,7 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { const parsedConfirmationStatus = confirmationStatus ? confirmationStatus == 'not_corrupted' - ? ['confirmed', 'not_processed'] + ? undefined// ['confirmed', 'not_processed'] : [confirmationStatus] : undefined; From 089b085fab6c4a37cd0ff55c443076156de324b3 Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 27 Jul 2023 14:39:30 +0200 Subject: [PATCH 32/95] fix: block height should be get after locking transaction (#174) --- src/gateway/router/routes/sequencerRoute.ts | 94 ++++++++----------- .../router/routes/sequencerRoute_v2.ts | 44 +++------ 2 files changed, 54 insertions(+), 84 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index ae2ebc2b..a67ffb9b 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -1,6 +1,6 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; -import { parseFunctionName, safeParseInput } from '../../tasks/syncTransactions'; +import { parseFunctionName } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; @@ -32,8 +32,6 @@ export async function sequencerRoute(ctx: Router.RouterContext) { try { const initialBenchmark = Benchmark.measure(); - const cachedNetworkData = getCachedNetworkData(); - const benchmark = Benchmark.measure(); const transaction: Transaction = new Transaction({ ...ctx.request.body }); @@ -41,56 +39,38 @@ export async function sequencerRoute(ctx: Router.RouterContext) { const originalSignature = transaction.signature; const originalOwner = transaction.owner; - - if (cachedNetworkData == null) { - throw new Error('Network or block info not yet cached.'); - } - - const currentHeight = cachedNetworkData.cachedBlockInfo.height; - sLogger.debug(`Sequencer height: ${transaction.id}: ${currentHeight}`); - - if (!currentHeight) { - throw new Error('Current height not set'); - } - - const currentBlockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; - if (!currentBlockTimestamp) { - throw new Error('Current block timestamp not set'); - } - - const currentBlockId = cachedNetworkData.cachedNetworkInfo.current; - if (!currentBlockId) { - throw new Error('Current block not set'); - } - let { contractTag, inputTag, requestVrfTag, internalWrites, decodedTags, - tags, originalAddress, isEvmSigner, testnetVersion, - } = await prepareTags( - sLogger, - transaction, - originalOwner, - currentHeight, - currentBlockId, - currentBlockTimestamp, - arweave - ); + } = await prepareTags(sLogger, transaction, originalOwner, arweave); trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); const millis = Date.now(); + const { currentHeight, currentBlockTimestamp, currentBlockId, cachedBlockInfo } = getBlockInfo( + transaction.id, + sLogger + ); const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, transaction.id, currentHeight); if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); } + const tags = getUploaderTags( + originalAddress, + transaction.id, + currentHeight, + currentBlockId, + currentBlockTimestamp, + decodedTags + ); + tags.push({ name: 'Sequencer-Mills', value: '' + millis }); tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); tags.push({ name: 'Sequencer-Prev-Sort-Key', value: contractPrevSortKey || 'null' }); @@ -108,7 +88,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { decodedTags, currentHeight, currentBlockId, - cachedNetworkData.cachedBlockInfo, + cachedBlockInfo, sortKey, vrfData, isEvmSigner ? originalSignature : null, @@ -318,15 +298,7 @@ function bufToBn(buf: Array) { return BigInt('0x' + hex.join('')); } -async function prepareTags( - logger: any, - transaction: Transaction, - originalOwner: string, - currentHeight: number, - currentBlockId: string, - currentBlockTimestamp: number, - arweave: Arweave -) { +async function prepareTags(logger: any, transaction: Transaction, originalOwner: string, arweave: Arweave) { let contractTag: string = '', inputTag: string = '', requestVrfTag = '', @@ -372,22 +344,12 @@ async function prepareTags( originalAddress = await arweave.wallets.ownerToAddress(originalOwner); } - const tags = getUploaderTags( - originalAddress, - transaction.id, - currentHeight, - currentBlockId, - currentBlockTimestamp, - decodedTags - ); - return { contractTag, inputTag, requestVrfTag, internalWrites, decodedTags, - tags, originalAddress, isEvmSigner, testnetVersion, @@ -458,3 +420,25 @@ export async function createSortKey( return `${blockHeightString},${mills},${hashed}`; } + +export function getBlockInfo(id: string, sLogger: any) { + const cachedNetworkData = getCachedNetworkData(); + if (cachedNetworkData == null) { + throw new Error('Network or block info not yet cached.'); + } + const currentHeight = cachedNetworkData.cachedBlockInfo.height; + sLogger.debug(`Sequencer height: ${id}: ${currentHeight}`); + if (!currentHeight) { + throw new Error('Current height not set'); + } + const currentBlockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; + if (!currentBlockTimestamp) { + throw new Error('Current block timestamp not set'); + } + const currentBlockId = cachedNetworkData.cachedNetworkInfo.current; + if (!currentBlockId) { + throw new Error('Current block not set'); + } + + return { currentHeight, currentBlockTimestamp, currentBlockId, cachedBlockInfo: cachedNetworkData.cachedBlockInfo }; +} diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index b23e877a..f71453b8 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -1,14 +1,13 @@ import Router from '@koa/router'; import { parseFunctionName, safeParseInput } from '../../tasks/syncTransactions'; import { Benchmark, SmartWeaveTags, VrfData } from 'warp-contracts'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { publishInteraction, sendNotification } from '../../publisher'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { DataItem } from 'arbundles'; -import { createInteraction, generateVrfTags, getUploaderTags } from './sequencerRoute'; +import { createInteraction, generateVrfTags, getBlockInfo, getUploaderTags } from './sequencerRoute'; import { createSortKey } from './sequencerRoute'; import { tagsExceedLimit } from 'warp-arbundles'; import rawBody from 'raw-body'; @@ -16,16 +15,12 @@ import { b64UrlToString } from 'arweave/node/lib/utils'; import { determineOwner } from './deploy/deployContractRoute_v2'; export async function sequencerRoute_v2(ctx: Router.RouterContext) { - const { sLogger, arweave, jwk, vrf, lastTxSync, dbSource, bundlr } = ctx; + const { sLogger, arweave, jwk, vrf, lastTxSync, dbSource } = ctx; let trx: Knex.Transaction | null = null; try { const initialBenchmark = Benchmark.measure(); - const cachedNetworkData = getCachedNetworkData(); - if (cachedNetworkData == null) { - throw new Error('Network or block info not yet cached.'); - } const benchmark = Benchmark.measure(); const rawDataItem: Buffer = await rawBody(ctx.req); @@ -46,38 +41,29 @@ export async function sequencerRoute_v2(ctx: Router.RouterContext) { ctx.throw(400, 'Interaction data item binary is not valid.'); } - const currentHeight = cachedNetworkData.cachedBlockInfo.height; - sLogger.debug(`Sequencer height: ${interactionDataItem.id}: ${currentHeight}`); + const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; - if (!currentHeight) { - throw new Error('Current height not set'); - } + const trx = await dbSource.primaryDb.transaction(); + const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); + const millis = Date.now(); - const currentBlockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; - if (!currentBlockTimestamp) { - throw new Error('Current block timestamp not set'); - } + const { currentHeight, currentBlockTimestamp, currentBlockId, cachedBlockInfo } = getBlockInfo( + interactionDataItem.id, + sLogger + ); - const currentBlockId = cachedNetworkData.cachedNetworkInfo.current; - if (!currentBlockId) { - throw new Error('Current block not set'); + const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, interactionDataItem.id, currentHeight); + if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { + throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); } const originalSignature = interactionDataItem.signature; - const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; const originalAddress = await determineOwner(interactionDataItem, arweave); const testnetVersion = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET)?.value || null; const internalWrites: string[] = []; interactionDataItem.tags .filter((t) => t.name == SmartWeaveTags.INTERACT_WRITE) .forEach((t) => internalWrites.push(t.value)); - const trx = await dbSource.primaryDb.transaction(); - const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); - const millis = Date.now(); - const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, interactionDataItem.id, currentHeight); - if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { - throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); - } const tags = getUploaderTags( originalAddress, @@ -114,12 +100,12 @@ export async function sequencerRoute_v2(ctx: Router.RouterContext) { interactionDataItem.tags, currentHeight, currentBlockId, - cachedNetworkData.cachedBlockInfo, + cachedBlockInfo, sortKey, vrfData, originalSignature, testnetVersion, - parsedInput + contractPrevSortKey ); sLogger.debug('inserting into tables'); From a242edaa6f95a108c34b6c37941aacf17fc1bac6 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Fri, 4 Aug 2023 14:57:10 +0200 Subject: [PATCH 33/95] feat: add srcTxId to register contract messages --- src/gateway/publisher.ts | 1 + src/gateway/router/routes/deploy/deployBundledRoute.ts | 2 +- src/gateway/router/routes/deploy/deployContractRoute.ts | 2 +- src/gateway/router/routes/deploy/deployContractRoute_v2.ts | 2 +- src/gateway/router/routes/deploy/registerContractRoute.ts | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index 65f49802..6716467e 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -10,6 +10,7 @@ export function sendNotification( contractTxId: string, contractData?: { initState: any; + srcTxId: string; tags: { name: string; value: string; diff --git a/src/gateway/router/routes/deploy/deployBundledRoute.ts b/src/gateway/router/routes/deploy/deployBundledRoute.ts index a7c637d4..ad12f4bf 100644 --- a/src/gateway/router/routes/deploy/deployBundledRoute.ts +++ b/src/gateway/router/routes/deploy/deployBundledRoute.ts @@ -71,7 +71,7 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { }; await dbSource.insertContract(insert); - sendNotification(ctx, bundlrResponse.data.id, { initState, tags: dataItem.tags }); + sendNotification(ctx, bundlrResponse.data.id, { initState, tags: dataItem.tags, srcTxId }); publishContract( ctx, bundlrResponse.data.id, diff --git a/src/gateway/router/routes/deploy/deployContractRoute.ts b/src/gateway/router/routes/deploy/deployContractRoute.ts index b7f0677f..66bf994b 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute.ts @@ -148,7 +148,7 @@ export async function deployContractRoute(ctx: Router.RouterContext) { await dbSource.insertContractSource(contracts_src_insert); } - sendNotification(ctx, contractTx.id, { initState, tags: contractTags }); + sendNotification(ctx, contractTx.id, { initState, tags: contractTags, srcTxId }); publishContract( ctx, contractTx.id, diff --git a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts index e8f07579..15c1e5cf 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -125,7 +125,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { await dbSource.insertContract(insert); - sendNotification(ctx, contractDataItem.id, { initState, tags: contractDataItem.tags }); + sendNotification(ctx, contractDataItem.id, { initState, tags: contractDataItem.tags, srcTxId: srcId }); publishContract( ctx, contractDataItem.id, diff --git a/src/gateway/router/routes/deploy/registerContractRoute.ts b/src/gateway/router/routes/deploy/registerContractRoute.ts index fb9a033e..b3a7a06b 100644 --- a/src/gateway/router/routes/deploy/registerContractRoute.ts +++ b/src/gateway/router/routes/deploy/registerContractRoute.ts @@ -106,7 +106,7 @@ export async function registerContractRoute(ctx: Router.RouterContext) { await dbSource.insertContract(insert); - sendNotification(ctx, txId, { initState, tags }); + sendNotification(ctx, txId, { initState, tags, srcTxId }); publishContract( ctx, txId, From a8633015efa5662b1be6e11431e839a7118c0f4f Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Fri, 4 Aug 2023 15:02:21 +0200 Subject: [PATCH 34/95] fix: srcTxId in contractsMetadata --- src/gateway/tasks/contractsMetadata.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/tasks/contractsMetadata.ts b/src/gateway/tasks/contractsMetadata.ts index aa0349d8..a0c87e6b 100644 --- a/src/gateway/tasks/contractsMetadata.ts +++ b/src/gateway/tasks/contractsMetadata.ts @@ -251,7 +251,7 @@ async function loadContractsMetadata(context: GatewayContext) { await dbSource.updateContractSrc(contracts_src_insert); // TODO: add tags to ContractDefinition type in the SDK - sendNotification(context, definition.txId, { initState: definition.initState, tags: [] }); + sendNotification(context, definition.txId, { initState: definition.initState, tags: [], srcTxId: definition.srcTxId }); publishContract( context, contractId, From cbdbe0fa196dc0ab5fff5b91406e908c94008c3b Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Fri, 4 Aug 2023 15:07:17 +0200 Subject: [PATCH 35/95] fix: pass srcTxId to a published message --- src/gateway/publisher.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index 6716467e..0742dfc1 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -33,6 +33,7 @@ export function sendNotification( if (contractData) { message.initialState = contractData.initState; message.tags = contractData.tags; + message.srcTxId = contractData.srcTxId; } if (interaction) { message.interaction = interaction; From 00bf41c181f0148279cc1e221a27576bb096aea6 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Mon, 5 Jun 2023 11:12:12 +0200 Subject: [PATCH 36/95] temp --- src/gateway/router/routes/sequencerRoute.ts | 2 +- src/gateway/tasks/verifyInteractions.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index a67ffb9b..c7a1fdfe 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -3,7 +3,7 @@ import Transaction from 'arweave/node/lib/transaction'; import { parseFunctionName } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; -import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; +import { arrayToHex, Benchmark, GQLNodeInterface, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; import { getCachedNetworkData } from '../../tasks/networkInfoCache'; import Bundlr from '@bundlr-network/client'; import { BlockData } from 'arweave/node/blocks'; diff --git a/src/gateway/tasks/verifyInteractions.ts b/src/gateway/tasks/verifyInteractions.ts index 82db1c18..c35ffee1 100644 --- a/src/gateway/tasks/verifyInteractions.ts +++ b/src/gateway/tasks/verifyInteractions.ts @@ -87,9 +87,7 @@ async function verifyInteractions(context: GatewayContext) { 'l6S4oMyzw_rggjt4yt4LrnRmggHQ2CdM1hna2MK4o_c', /* kyve */ 'B1SRLyFzWJjeA0ywW41Qu1j7ZpBLHsXSSrWLrT3ebd8', /* kyve */ 'cETTyJQYxJLVQ6nC3VxzsZf1x2-6TW2LFkGZa91gUWc', /* koi */ - /* 'QA7AIFVx1KBBmzC7WUNhJbDsHlSJArUT0jWrhZMZPS8', koi */ '8cq1wbjWHNiPg7GwYpoDT2m9HX99LY7tklRQWfh1L6c', /* kyve */ - /* 'NwaSMGCdz6Yu5vNjlMtCNBmfEkjYfT-dfYkbQQDGn5s', koi */ 'qzVAzvhwr1JFTPE8lIU9ZG_fuihOmBr7ewZFcT3lIUc', /* koi */ 'OFD4GqQcqp-Y_Iqh8DN_0s3a_68oMvvnekeOEu_a45I', /* kyve */ 'CdPAQNONoR83Shj3CbI_9seC-LqgI1oLaRJhSwP90-o', /* koi */ From 1532c7d99a1c23d12749bc352a53410d27428471 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Mon, 5 Jun 2023 17:06:46 +0200 Subject: [PATCH 37/95] feat: new L1 syncer --- src/gateway/LastTxSyncer.ts | 55 +++- src/gateway/router/routes/sequencerRoute.ts | 348 ++++++++++---------- 2 files changed, 214 insertions(+), 189 deletions(-) diff --git a/src/gateway/LastTxSyncer.ts b/src/gateway/LastTxSyncer.ts index 5bf0a713..90067139 100644 --- a/src/gateway/LastTxSyncer.ts +++ b/src/gateway/LastTxSyncer.ts @@ -1,21 +1,27 @@ -import {Knex} from "knex"; -import {Benchmark, LoggerFactory} from "warp-contracts"; -import { createHash } from 'crypto' +import { Knex } from "knex"; +import { Benchmark, LoggerFactory } from "warp-contracts"; +import { createHash } from "crypto"; + +export type AcquireMutexResult = { + lastSortKey: string | null, + blockHeight: number, + blockHash: string, + blockTimestamp: number +} export class LastTxSync { private readonly logger = LoggerFactory.INST.create(LastTxSync.name); - async acquireMutex(contractTxId: string, trx: Knex.Transaction): Promise { + async acquireMutex(contractTxId: string, trx: Knex.Transaction): Promise { const lockId = this.strToKey(contractTxId); - this.logger.debug('Locking for', { + this.logger.debug("Locking for", { contractTxId, lockId }); // https://stackoverflow.com/a/20963803 - - await trx.raw(`SET LOCAL lock_timeout = '5s';`) + await trx.raw(`SET LOCAL lock_timeout = '5s';`); const benchmark = Benchmark.measure(); await trx.raw(` SELECT pg_advisory_xact_lock(?, ?); @@ -25,25 +31,42 @@ export class LastTxSync { return this.loadLastSortKey(contractTxId, trx); } - private async loadLastSortKey(contractTxId: string, trx: Knex.Transaction): Promise { + private async loadLastSortKey(contractTxId: string, trx: Knex.Transaction): Promise { const benchmark = Benchmark.measure(); + this.logger.debug("Loading lastSortKey", benchmark.elapsed()); + const result = await trx.raw( - `SELECT max(sort_key) AS "lastSortKey" + `SELECT 'sort_key' as type, + max(sort_key) AS "lastSortKey", + null as finishedBlockHeight, + null as finishedBlockHash, + null as finishedTimestamp FROM interactions - WHERE contract_id = ?`, - [contractTxId] + WHERE contract_id = ? + UNION ALL + SELECT 'finished_block' as type, null, finished_block_height, finished_block_hash, finished_timestamp + FROM sync_state + WHERE name = 'Contracts'`, [contractTxId] ); - this.logger.debug("Loading lastSortKey", benchmark.elapsed()); + if (result?.rows.length !== 2) { + throw new Error("Acquire mutex result should have exactly 2 rows in result"); + } + const sortKeyRow = result?.rows[0].type === "sort_key" ? 0 : 1; + const finishedBlockRow = result?.rows[0].type === "finished_block" ? 0 : 1; - // note: this will return null if we're registering the very first tx for the contract - return result?.rows[0].lastSortKey; + return { + lastSortKey: result?.rows[sortKeyRow].lastSortKey, // note: this will return null if we're registering the very first tx for the contract + blockHeight: result?.rows[finishedBlockRow].finishedBlockHeight, + blockHash: result?.rows[finishedBlockRow].finishedBlockHash, + blockTimestamp: 0 // TODO + }; } // https://github.com/binded/advisory-lock/blob/master/src/index.js#L8 private strToKey(id: string) { - const buf = createHash('sha256').update(id).digest() + const buf = createHash("sha256").update(id).digest(); // Read the first 4 bytes and the next 4 bytes // The parameter here is the byte offset, not the sizeof(int32) offset - return [buf.readInt32LE(0), buf.readInt32LE(4)] + return [buf.readInt32LE(0), buf.readInt32LE(4)]; } } diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index c7a1fdfe..5e391385 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -3,18 +3,22 @@ import Transaction from 'arweave/node/lib/transaction'; import { parseFunctionName } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; -import { arrayToHex, Benchmark, GQLNodeInterface, GQLTagInterface, SmartWeaveTags, WarpLogger } from 'warp-contracts'; -import { getCachedNetworkData } from '../../tasks/networkInfoCache'; +import { + arrayToHex, + Benchmark, + GQLNodeInterface, + GQLTagInterface, + SmartWeaveTags, + timeout, + WarpLogger, +} from 'warp-contracts'; import Bundlr from '@bundlr-network/client'; -import { BlockData } from 'arweave/node/blocks'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; -import { publishInteraction, sendNotification } from '../../publisher'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { VRF } from '../../init'; -import { serializeTags } from 'arbundles'; -import { DataItem } from 'arbundles'; +import { DataItem, serializeTags } from 'arbundles'; const { Evaluate } = require('@idena/vrf-js'); @@ -26,200 +30,189 @@ export type VrfData = { }; export async function sequencerRoute(ctx: Router.RouterContext) { - const { sLogger, arweave, jwk, vrf, lastTxSync, dbSource, signatureVerification } = ctx; + const { dbSource } = ctx; + const trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; - let trx: Knex.Transaction | null = null; + const { timeoutId, timeoutPromise } = timeout(0.5); try { - const initialBenchmark = Benchmark.measure(); - const benchmark = Benchmark.measure(); - - const transaction: Transaction = new Transaction({ ...ctx.request.body }); - sLogger.debug('New sequencer tx', transaction.id); - - const originalSignature = transaction.signature; - const originalOwner = transaction.owner; - let { - contractTag, - inputTag, - requestVrfTag, - internalWrites, - decodedTags, - originalAddress, - isEvmSigner, - testnetVersion, - } = await prepareTags(sLogger, transaction, originalOwner, arweave); - - trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; - const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); - const millis = Date.now(); - const { currentHeight, currentBlockTimestamp, currentBlockId, cachedBlockInfo } = getBlockInfo( - transaction.id, - sLogger - ); - const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, transaction.id, currentHeight); - if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { - throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); + const transactionId = await Promise.race([timeoutPromise, doGenerateSequence(ctx, trx)]); + await trx.commit(); + ctx.body = { + id: transactionId, + }; + } catch (e: any) { + if (trx != null) { + await trx.rollback(); + } + throw new GatewayError(e?.message || e); + } finally { + if (timeoutId) { + clearTimeout(timeoutId); } + } +} - const tags = getUploaderTags( - originalAddress, - transaction.id, - currentHeight, - currentBlockId, - currentBlockTimestamp, - decodedTags - ); +async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { + const { sLogger, arweave, jwk, vrf, lastTxSync, signatureVerification } = ctx; - tags.push({ name: 'Sequencer-Mills', value: '' + millis }); - tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); - tags.push({ name: 'Sequencer-Prev-Sort-Key', value: contractPrevSortKey || 'null' }); + const initialBenchmark = Benchmark.measure(); - let vrfData = null; - if (requestVrfTag !== '') { - const vrfGen = generateVrfTags(sortKey, vrf, arweave); - tags.push(...vrfGen.vrfTags); - vrfData = vrfGen.vrfData; - } + const benchmark = Benchmark.measure(); - const interaction = createInteraction( - transaction, - originalAddress, - decodedTags, - currentHeight, - currentBlockId, - cachedBlockInfo, - sortKey, - vrfData, - isEvmSigner ? originalSignature : null, - testnetVersion, - contractPrevSortKey - ); + const transaction: Transaction = new Transaction({ ...ctx.request.body }); + sLogger.debug('New sequencer tx', transaction.id); - const verified = isEvmSigner - ? await signatureVerification.process(interaction) - : await arweave.transactions.verify(transaction); - if (!verified) { - throw new Error('Could not properly verify transaction.'); - } + const originalSignature = transaction.signature; + const originalOwner = transaction.owner; - const parsedInput = JSON.parse(inputTag); - const functionName = parseFunctionName(inputTag, sLogger); - let evolve: string | null; - evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; + let { + contractTag, + inputTag, + requestVrfTag, + internalWrites, + decodedTags, + originalAddress, + isEvmSigner, + testnetVersion, + } = await prepareTags(sLogger, transaction, originalOwner, arweave); + + const acquireMutexResult = await lastTxSync.acquireMutex(contractTag, trx); + sLogger.debug('Acquire mutex result', acquireMutexResult); + + const millis = Date.now(); + const sortKey = await createSortKey( + arweave, + jwk, + acquireMutexResult.blockHash, + millis, + transaction.id, + acquireMutexResult.blockHeight + ); + if (acquireMutexResult.lastSortKey !== null && sortKey.localeCompare(acquireMutexResult.lastSortKey) <= 0) { + throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${acquireMutexResult.lastSortKey})!`); + } - sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); - sLogger.debug('inserting into tables'); + const tags = [ + { name: 'Sequencer', value: 'RedStone' }, + { name: 'Sequencer-Owner', value: originalAddress }, + { name: 'Sequencer-Tx-Id', value: transaction.id }, + { name: 'Sequencer-Block-Height', value: '' + acquireMutexResult.blockHeight }, + { name: 'Sequencer-Block-Id', value: acquireMutexResult.blockHash }, + { name: 'Sequencer-Block-Timestamp', value: '' + acquireMutexResult.blockTimestamp }, + { name: 'Sequencer-Mills', value: '' + millis }, + { name: 'Sequencer-Sort-Key', value: sortKey }, + { name: 'Sequencer-Prev-Sort-Key', value: acquireMutexResult.lastSortKey || 'null' }, + ...decodedTags, + ]; - try { - serializeTags(tags); - } catch (e) { - throw new Error(`Tags could not be serialized properly. It may be due to the big input size.`); - } + let vrfData = null; + if (requestVrfTag !== '') { + const vrfGen = generateVrfTags(sortKey, vrf, arweave); + tags.push(...vrfGen.vrfTags); + vrfData = vrfGen.vrfData; + } + + const interaction = createInteraction( + transaction, + originalAddress, + decodedTags, + acquireMutexResult.blockHeight, + acquireMutexResult.blockHash, + acquireMutexResult.blockTimestamp, + sortKey, + vrfData, + isEvmSigner ? originalSignature : null, + testnetVersion, + acquireMutexResult.lastSortKey + ); + + const verified = isEvmSigner + ? await signatureVerification.process(interaction) + : await arweave.transactions.verify(transaction); + if (!verified) { + throw new Error('Could not properly verify transaction.'); + } + + const parsedInput = JSON.parse(inputTag); + const functionName = parseFunctionName(inputTag, sLogger); + let evolve: string | null; + evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; + + sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); + sLogger.debug('inserting into tables'); + + try { + serializeTags(tags); + } catch (e) { + throw new Error(`Tags could not be serialized properly. It may be due to the big input size.`); + } - await trx.raw( - ` + await trx.raw( + ` WITH ins_interaction AS ( - INSERT INTO interactions (interaction_id, - interaction, - block_height, - block_id, - contract_id, - function, - input, - confirmation_status, - confirming_peer, - source, - block_timestamp, - interact_write, - sort_key, - evolve, - testnet, - last_sort_key, - owner, - sync_timestamp) - VALUES (:interaction_id, - :interaction, - :block_height, - :block_id, - :contract_id, - :function, - :input, - :confirmation_status, - :confirming_peer, - :source, - :block_timestamp, - :interact_write, - :sort_key, - :evolve, - :testnet, - :prev_sort_key, - :owner, - :sync_timestamp) - RETURNING id) + INSERT + INTO interactions (interaction_id, + interaction, + block_height, + block_id, + contract_id, + function, + input, + confirmation_status, + confirming_peer, + source, + block_timestamp, + interact_write, + sort_key, + evolve, + testnet, + last_sort_key, + owner, + sync_timestamp) + VALUES (:interaction_id, :interaction, :block_height, :block_id, :contract_id, : function, : input, :confirmation_status, :confirming_peer, : source, :block_timestamp, :interact_write, :sort_key, :evolve, :testnet, :prev_sort_key, :owner, :sync_timestamp) + RETURNING id) INSERT INTO bundle_items (interaction_id, state, transaction, tags) SELECT i.id, 'PENDING', :original_transaction, :tags FROM ins_interaction i; `, - { - interaction_id: transaction.id, - interaction: interaction, - block_height: currentHeight, - block_id: currentBlockId, - contract_id: contractTag, - function: functionName, - input: inputTag, - confirmation_status: 'confirmed', - confirming_peer: BUNDLR_NODE1_URL, - source: 'redstone-sequencer', - block_timestamp: currentBlockTimestamp, - interact_write: internalWrites, - sort_key: sortKey, - evolve: evolve, - testnet: testnetVersion, - prev_sort_key: contractPrevSortKey, - owner: originalOwner, - original_transaction: ctx.request.body, - tags: JSON.stringify(tags), - sync_timestamp: millis, - } - ); + { + interaction_id: transaction.id, + interaction: interaction, + block_height: acquireMutexResult.blockHeight, + block_id: acquireMutexResult.blockHash, + contract_id: contractTag, + function: functionName, + input: inputTag, + confirmation_status: 'confirmed', + confirming_peer: BUNDLR_NODE1_URL, + source: 'redstone-sequencer', + block_timestamp: acquireMutexResult.blockTimestamp, + interact_write: internalWrites, + sort_key: sortKey, + evolve: evolve, + testnet: testnetVersion, + prev_sort_key: acquireMutexResult.lastSortKey, + owner: originalOwner, + original_transaction: ctx.request.body, + tags: JSON.stringify(tags), + sync_timestamp: millis, + } + ); - await trx.commit(); - sLogger.info('Total sequencer processing', benchmark.elapsed()); + sLogger.info('Total sequencer processing', benchmark.elapsed()); - ctx.body = { - id: transaction.id, - }; - - sendNotification(ctx, contractTag, undefined, interaction); - publishInteraction( - ctx, - contractTag, - interaction, - sortKey, - contractPrevSortKey, - functionName, - 'redstone-sequencer', - millis, - testnetVersion - ); - } catch (e: any) { - if (trx != null) { - await trx.rollback(); - } - throw new GatewayError(e?.message || e); - } + return transaction.id; } -export function createInteraction( +function createInteraction( transactionOrDataItem: Transaction | DataItem, originalAddress: string, decodedTags: GQLTagInterface[], currentHeight: number, currentBlockId: string, - blockInfo: BlockData, + currentBlockTimestamp: number, sortKey: string, vrfData: VrfData | null, signature: string | null, @@ -234,7 +227,7 @@ export function createInteraction( block: { height: currentHeight, id: currentBlockId, - timestamp: blockInfo.timestamp, + timestamp: currentBlockTimestamp, }, fee: { winston: isTransaction(transactionOrDataItem) ? transactionOrDataItem.reward : '0', @@ -344,6 +337,15 @@ async function prepareTags(logger: any, transaction: Transaction, originalOwner: originalAddress = await arweave.wallets.ownerToAddress(originalOwner); } + /*const tags = [ + { name: 'Sequencer', value: 'RedStone' }, + { name: 'Sequencer-Owner', value: originalAddress }, + { name: 'Sequencer-Tx-Id', value: transaction.id }, + { name: 'Sequencer-Block-Height', value: '' + currentHeight }, + { name: 'Sequencer-Block-Id', value: currentBlockId }, + ...decodedTags, + ];*/ + return { contractTag, inputTag, From 72d1c2790a4a1d4222ec11c2fdd4bdff7fa6b54b Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 6 Jun 2023 15:13:42 +0200 Subject: [PATCH 38/95] chore: logging --- src/gateway/init.ts | 2 +- tools/nakurwiaj.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 5b826728..04cabb08 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -79,7 +79,7 @@ export interface GatewayContext { LoggerFactory.INST.logLevel('info'); LoggerFactory.INST.logLevel('info', 'gateway'); - LoggerFactory.INST.logLevel('info', 'sequencer'); + LoggerFactory.INST.logLevel('debug', 'sequencer'); LoggerFactory.INST.logLevel('debug', 'LastTxSync'); LoggerFactory.INST.logLevel('debug', 'access'); const logger = LoggerFactory.INST.create('gateway'); diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 9e98cd66..9d19ce68 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -67,7 +67,7 @@ setInterval(async () => { }) ]); -}, 75); +}, 500); function readJSON(path) { const content = fs.readFileSync(path, 'utf-8'); From c559782ed2ed44685e7b3d1634071f18e4463d78 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 6 Jun 2023 19:22:20 +0200 Subject: [PATCH 39/95] fix: finishedBlockTimestamp --- src/gateway/LastTxSyncer.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gateway/LastTxSyncer.ts b/src/gateway/LastTxSyncer.ts index 90067139..6d383d81 100644 --- a/src/gateway/LastTxSyncer.ts +++ b/src/gateway/LastTxSyncer.ts @@ -38,13 +38,13 @@ export class LastTxSync { const result = await trx.raw( `SELECT 'sort_key' as type, max(sort_key) AS "lastSortKey", - null as finishedBlockHeight, - null as finishedBlockHash, - null as finishedTimestamp + null as "finishedBlockHeight", + null as "finishedBlockHash", + null as "finishedBlockTimestamp" FROM interactions WHERE contract_id = ? UNION ALL - SELECT 'finished_block' as type, null, finished_block_height, finished_block_hash, finished_timestamp + SELECT 'finished_block' as type, null, finished_block_height, finished_block_hash, finished_block_timestamp FROM sync_state WHERE name = 'Contracts'`, [contractTxId] ); @@ -58,7 +58,7 @@ export class LastTxSync { lastSortKey: result?.rows[sortKeyRow].lastSortKey, // note: this will return null if we're registering the very first tx for the contract blockHeight: result?.rows[finishedBlockRow].finishedBlockHeight, blockHash: result?.rows[finishedBlockRow].finishedBlockHash, - blockTimestamp: 0 // TODO + blockTimestamp: result?.rows[finishedBlockRow].finishedBlockTimestamp }; } From 3f9c03ca8e7ba548fd00984a9b28f211722d1516 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 6 Jun 2023 19:25:33 +0200 Subject: [PATCH 40/95] fix: code formatter... --- src/gateway/router/routes/sequencerRoute.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 5e391385..0d97ddb3 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -170,7 +170,25 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti last_sort_key, owner, sync_timestamp) - VALUES (:interaction_id, :interaction, :block_height, :block_id, :contract_id, : function, : input, :confirmation_status, :confirming_peer, : source, :block_timestamp, :interact_write, :sort_key, :evolve, :testnet, :prev_sort_key, :owner, :sync_timestamp) + VALUES ( + :interaction_id, + :interaction, + :block_height, + :block_id, + :contract_id, + :function, + :input, + :confirmation_status, + :confirming_peer, + :source, + :block_timestamp, + :interact_write, + :sort_key, + :evolve, + :testnet, + :prev_sort_key, + :owner, + :sync_timestamp) RETURNING id) INSERT INTO bundle_items (interaction_id, state, transaction, tags) From a366c9bbffd572520b4552f9a2d68bbd2bf6142b Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 6 Jun 2023 19:48:06 +0200 Subject: [PATCH 41/95] validation --- src/gateway/router/routes/sequencerRoute.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 0d97ddb3..e1d4d33e 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -79,6 +79,14 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const acquireMutexResult = await lastTxSync.acquireMutex(contractTag, trx); sLogger.debug('Acquire mutex result', acquireMutexResult); + if ( + acquireMutexResult.lastSortKey == null || + acquireMutexResult.blockHash == null || + acquireMutexResult.blockHeight == null || + acquireMutexResult.blockTimestamp == null + ) { + throw new Error(`Missing data in acquireMutexResult: ${JSON.stringify(acquireMutexResult)}`); + } const millis = Date.now(); const sortKey = await createSortKey( From b8ad42a19006267ab5ab21d03f5cb3d46627b9b8 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Wed, 7 Jun 2023 13:11:31 +0200 Subject: [PATCH 42/95] chore: naqrwiaj only 1 --- tools/nakurwiaj.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 9d19ce68..8c541eb8 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -45,7 +45,7 @@ setInterval(async () => { target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 }), - contractB.writeInteraction({ + /*contractB.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 @@ -64,7 +64,7 @@ setInterval(async () => { function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 - }) + })*/ ]); }, 500); From 4ef22b7dffac394b55acf43b46edf36fff8d6244 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 13 Jun 2023 12:30:14 +0200 Subject: [PATCH 43/95] feat: env - local,dev,main --- src/gateway/init.ts | 34 ++++++++++++--------- src/gateway/publisher.ts | 8 +++-- src/gateway/router/routes/sequencerRoute.ts | 1 - 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 04cabb08..ad694825 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -27,12 +27,13 @@ const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; const replica = (argv.replica as boolean) || false; const noSync = (argv.noSync as boolean) || false; -const localEnv = (argv.local as boolean) || false; const elliptic = require('elliptic'); const EC = new elliptic.ec('secp256k1'); const cors = require('@koa/cors'); +export type EnvType = 'local' | 'dev' | 'main'; + export type VRF = { pubKeyHex: string; privKey: any; ec: any }; export interface GatewayContext { @@ -50,7 +51,7 @@ export interface GatewayContext { publisher: Redis; publisher_v2: Redis; lastTxSync: LastTxSync; - localEnv: boolean; + env: EnvType; appSync?: string; signatureVerification: EvmSignatureVerificationServerPlugin; replica: boolean; @@ -86,7 +87,12 @@ export interface GatewayContext { const sLogger = LoggerFactory.INST.create('sequencer'); const accessLogger = LoggerFactory.INST.create('access'); - logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode. noSync = ${noSync}`); + const env = process.env.ENV as string; + if (!env) { + logger.error(`Set 'ENV' value in ${envPath} to either 'local', 'dev' or 'main'`); + process.exit(0); + } + logger.info(`🚀🚀🚀 Starting gateway in ${replica ? 'replica' : 'normal'} mode.\nnoSync = ${noSync}.\nENV: ${env}`); const arweave = initArweave(); const { bundlr, jwk } = initBundlr(logger); @@ -94,14 +100,15 @@ export interface GatewayContext { const gcpDataOptions = { client: 'pg' as 'pg', url: process.env.DB_URL_GCP as string, - ssl: localEnv - ? undefined - : { - rejectUnauthorized: false, - ca: fs.readFileSync('.secrets/ca.pem'), - cert: fs.readFileSync('.secrets/cert.pem'), - key: fs.readFileSync('.secrets/key.pem'), - }, + ssl: + env === 'local' + ? undefined + : { + rejectUnauthorized: false, + ca: fs.readFileSync('.secrets/ca.pem'), + cert: fs.readFileSync('.secrets/cert.pem'), + key: fs.readFileSync('.secrets/key.pem'), + }, primaryDb: true, }; @@ -145,7 +152,6 @@ export interface GatewayContext { ); app.context.sorter = new LexicographicalInteractionsSorter(arweave); app.context.lastTxSync = new LastTxSync(); - app.context.localEnv = localEnv; app.context.appSync = appSync; app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); app.context.replica = replica; @@ -188,7 +194,7 @@ export interface GatewayContext { logger.info('vrf', app.context.vrf); - if (!localEnv) { + if (env !== 'local') { const connectionOptions = readGwPubSubConfig('gw-pubsub.json'); logger.info('Redis connection options', connectionOptions); if (connectionOptions) { @@ -244,7 +250,7 @@ export interface GatewayContext { // note: only one worker in cluster runs the gateway tasks // all workers in cluster run the http server - if (!localEnv) { + if (env !== 'local') { logger.info(`Starting gateway tasks for ${cluster.worker?.id}`); await runGatewayTasks(app.context); } diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index 0742dfc1..ae6852f3 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -20,7 +20,7 @@ export function sendNotification( ) { const { logger } = ctx; - if (ctx.localEnv) { + if (ctx.env === 'local') { logger.info('Skipping publish contract notification for local env'); return; } @@ -63,7 +63,7 @@ export function publishInteraction( ) { const { logger, appSync } = ctx; - if (!appSync) { + if (!appSync || ctx.env === 'local') { logger.warn('App sync key not set'); return; } @@ -131,7 +131,9 @@ function publish( return; } - appSyncPublish(`${ctx.localEnv ? 'local/' : ''}${testnet ? 'testnet/' : ''}${channel}`, txToPublish, appSync) + const prefix = ctx.env === 'main' ? '' : `${ctx.env}/`; + + appSyncPublish(`${prefix}${testnet ? 'testnet/' : ''}${channel}`, txToPublish, appSync) .then((r) => { logger.debug(infoMessage); }) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index e1d4d33e..23e5d628 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -6,7 +6,6 @@ import { JWKInterface } from 'arweave/node/lib/wallet'; import { arrayToHex, Benchmark, - GQLNodeInterface, GQLTagInterface, SmartWeaveTags, timeout, From 8665fda748c5c497c0e7c859877df0dbb0bb38be Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 20 Jun 2023 10:55:22 +0200 Subject: [PATCH 44/95] chore: nakurwiaj, but not so much --- tools/nakurwiaj.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 8c541eb8..28597948 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -67,7 +67,7 @@ setInterval(async () => { })*/ ]); -}, 500); +}, 2000); function readJSON(path) { const content = fs.readFileSync(path, 'utf-8'); From 2482fc71de0eaf3f8419e8d1caad5c90e8841353 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 20 Jun 2023 11:24:35 +0200 Subject: [PATCH 45/95] chore: null is cool --- src/gateway/router/routes/sequencerRoute.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 23e5d628..8b5e9cc2 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -3,14 +3,7 @@ import Transaction from 'arweave/node/lib/transaction'; import { parseFunctionName } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; -import { - arrayToHex, - Benchmark, - GQLTagInterface, - SmartWeaveTags, - timeout, - WarpLogger, -} from 'warp-contracts'; +import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, timeout, WarpLogger } from 'warp-contracts'; import Bundlr from '@bundlr-network/client'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; @@ -78,8 +71,8 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const acquireMutexResult = await lastTxSync.acquireMutex(contractTag, trx); sLogger.debug('Acquire mutex result', acquireMutexResult); + // note: lastSortKey can be null if that's a very first interaction with a contract. if ( - acquireMutexResult.lastSortKey == null || acquireMutexResult.blockHash == null || acquireMutexResult.blockHeight == null || acquireMutexResult.blockTimestamp == null From dbf1a2e933a449bb17701f3b390472638f201cf6 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Wed, 21 Jun 2023 12:10:29 +0200 Subject: [PATCH 46/95] chore: nakurwiaj to L1 and L2 --- tools/nakurwiaj.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 28597948..ec2726ae 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -12,6 +12,7 @@ const contractA = warp.contract("IBrkOF0A8XqlZHVFtZXy7jfCJFcaLJ2XYp94xL1-yUc") }) .connect(wallet); +/* const contractB = warp.contract("1LsbT8HH8SbldveeZcZZwgmuLn0ueJ6pN7ZSrbTqeVU") .setEvaluationOptions({ sequencerUrl: 'http://34.141.17.15:5666/' @@ -35,6 +36,7 @@ const contractE = warp.contract("pxna6TxgVFaESLNu0uZvxeUMOSqoYL1n-RRLtk7mGjY") sequencerUrl: 'http://34.141.17.15:5666/' }) .connect(wallet); +*/ setInterval(async () => { @@ -66,9 +68,74 @@ setInterval(async () => { qty: 100 })*/ + ]); +}, 1000); + +setInterval(async () => { + console.log('sending to L2...'); + await Promise.all([ + contractA.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + /*contractB.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractC.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractD.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractE.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + })*/ + ]); }, 2000); + +setInterval(async () => { + console.log('sending to L1...'); + await Promise.all([ + contractA.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }, { disableBundling: true }), + /*contractB.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractC.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractD.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + }), + contractE.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 100 + })*/ + + ]); +}, 5000); + function readJSON(path) { const content = fs.readFileSync(path, 'utf-8'); try { From 20abfb8233992c55453c7318bf6ad860721d9712 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Fri, 23 Jun 2023 12:00:15 +0200 Subject: [PATCH 47/95] fix: interactions, not contracts --- src/gateway/LastTxSyncer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/LastTxSyncer.ts b/src/gateway/LastTxSyncer.ts index 6d383d81..a14d6528 100644 --- a/src/gateway/LastTxSyncer.ts +++ b/src/gateway/LastTxSyncer.ts @@ -46,7 +46,7 @@ export class LastTxSync { UNION ALL SELECT 'finished_block' as type, null, finished_block_height, finished_block_hash, finished_block_timestamp FROM sync_state - WHERE name = 'Contracts'`, [contractTxId] + WHERE name = 'Interactions'`, [contractTxId] ); if (result?.rows.length !== 2) { throw new Error("Acquire mutex result should have exactly 2 rows in result"); From 0b31d0d65f9fbfca749bac3df7cde326a09fcfe0 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Sat, 24 Jun 2023 10:02:09 +0200 Subject: [PATCH 48/95] chore: naq --- tools/nakurwiaj.js | 92 ++-------------------------------------------- 1 file changed, 4 insertions(+), 88 deletions(-) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index ec2726ae..97cb1a41 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -6,13 +6,6 @@ const wallet = readJSON('./.secrets/33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA. warpContracts.LoggerFactory.INST.logLevel('error'); -const contractA = warp.contract("IBrkOF0A8XqlZHVFtZXy7jfCJFcaLJ2XYp94xL1-yUc") - .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/' - }) - .connect(wallet); - -/* const contractB = warp.contract("1LsbT8HH8SbldveeZcZZwgmuLn0ueJ6pN7ZSrbTqeVU") .setEvaluationOptions({ sequencerUrl: 'http://34.141.17.15:5666/' @@ -25,61 +18,10 @@ const contractC = warp.contract("o-QYGKa6rkWj5i0Vx0VQy99myCkPNeCAJi6-UZnhIVU") }) .connect(wallet); -const contractD = warp.contract("Y8ngFNyfGo17FeSvB7NEzLxdjl-qpFlE1YIPM8Sa6fo") - .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/' - }) - .connect(wallet); - -const contractE = warp.contract("pxna6TxgVFaESLNu0uZvxeUMOSqoYL1n-RRLtk7mGjY") - .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/' - }) - .connect(wallet); -*/ - - -setInterval(async () => { - console.log('sending...'); - await Promise.all([ - contractA.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - /*contractB.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - contractC.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - contractD.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - contractE.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - })*/ - - ]); -}, 1000); - setInterval(async () => { console.log('sending to L2...'); await Promise.all([ - contractA.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - /*contractB.writeInteraction({ + contractB.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 @@ -89,49 +31,23 @@ setInterval(async () => { target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 }), - contractD.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - contractE.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - })*/ - ]); -}, 2000); +}, 3000); setInterval(async () => { console.log('sending to L1...'); await Promise.all([ - contractA.writeInteraction({ + contractB.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 }, { disableBundling: true }), - /*contractB.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), contractC.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 100 - }), - contractD.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - contractE.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - })*/ + }, { disableBundling: true }), ]); }, 5000); From 46071b89b9103321db5e2ec09405cbdbbdf77acb Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Sat, 24 Jun 2023 10:05:42 +0200 Subject: [PATCH 49/95] chore: warp wallet in naq --- tools/nakurwiaj.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 97cb1a41..03306922 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -2,7 +2,7 @@ const fs = require("fs"); const warpContracts = require("warp-contracts"); const warp = warpContracts.WarpFactory.forTestnet(); -const wallet = readJSON('./.secrets/33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA.json'); +const wallet = readJSON('./.secrets/warp-wallet-jwk.json'); warpContracts.LoggerFactory.INST.logLevel('error'); From e58f738e8ff0948d093ec2d119a97d7aa9369d2c Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 3 Aug 2023 12:26:13 +0200 Subject: [PATCH 50/95] adjust data item sequencer endpoint --- src/gateway/router/routes/sequencerRoute.ts | 33 +- .../router/routes/sequencerRoute_v2.ts | 354 +++++++++--------- 2 files changed, 183 insertions(+), 204 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 8b5e9cc2..e8910b06 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -224,7 +224,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti return transaction.id; } -function createInteraction( +export function createInteraction( transactionOrDataItem: Transaction | DataItem, originalAddress: string, decodedTags: GQLTagInterface[], @@ -355,15 +355,6 @@ async function prepareTags(logger: any, transaction: Transaction, originalOwner: originalAddress = await arweave.wallets.ownerToAddress(originalOwner); } - /*const tags = [ - { name: 'Sequencer', value: 'RedStone' }, - { name: 'Sequencer-Owner', value: originalAddress }, - { name: 'Sequencer-Tx-Id', value: transaction.id }, - { name: 'Sequencer-Block-Height', value: '' + currentHeight }, - { name: 'Sequencer-Block-Id', value: currentBlockId }, - ...decodedTags, - ];*/ - return { contractTag, inputTag, @@ -440,25 +431,3 @@ export async function createSortKey( return `${blockHeightString},${mills},${hashed}`; } - -export function getBlockInfo(id: string, sLogger: any) { - const cachedNetworkData = getCachedNetworkData(); - if (cachedNetworkData == null) { - throw new Error('Network or block info not yet cached.'); - } - const currentHeight = cachedNetworkData.cachedBlockInfo.height; - sLogger.debug(`Sequencer height: ${id}: ${currentHeight}`); - if (!currentHeight) { - throw new Error('Current height not set'); - } - const currentBlockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; - if (!currentBlockTimestamp) { - throw new Error('Current block timestamp not set'); - } - const currentBlockId = cachedNetworkData.cachedNetworkInfo.current; - if (!currentBlockId) { - throw new Error('Current block not set'); - } - - return { currentHeight, currentBlockTimestamp, currentBlockId, cachedBlockInfo: cachedNetworkData.cachedBlockInfo }; -} diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index f71453b8..94a71fbd 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -1,13 +1,12 @@ import Router from '@koa/router'; -import { parseFunctionName, safeParseInput } from '../../tasks/syncTransactions'; -import { Benchmark, SmartWeaveTags, VrfData } from 'warp-contracts'; +import { parseFunctionName } from '../../tasks/syncTransactions'; +import { Benchmark, SmartWeaveTags, VrfData, timeout } from 'warp-contracts'; import { isTxIdValid } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; -import { publishInteraction, sendNotification } from '../../publisher'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { DataItem } from 'arbundles'; -import { createInteraction, generateVrfTags, getBlockInfo, getUploaderTags } from './sequencerRoute'; +import { createInteraction, generateVrfTags } from './sequencerRoute'; import { createSortKey } from './sequencerRoute'; import { tagsExceedLimit } from 'warp-arbundles'; import rawBody from 'raw-body'; @@ -15,194 +14,205 @@ import { b64UrlToString } from 'arweave/node/lib/utils'; import { determineOwner } from './deploy/deployContractRoute_v2'; export async function sequencerRoute_v2(ctx: Router.RouterContext) { - const { sLogger, arweave, jwk, vrf, lastTxSync, dbSource } = ctx; + const { dbSource } = ctx; + const trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; - let trx: Knex.Transaction | null = null; + const { timeoutId, timeoutPromise } = timeout(0.5); try { - const initialBenchmark = Benchmark.measure(); - const benchmark = Benchmark.measure(); + const transactionId = await Promise.race([timeoutPromise, doGenerateSequence(ctx, trx)]); + await trx.commit(); + ctx.body = { + id: transactionId, + }; + } catch (e: any) { + if (trx != null) { + await trx.rollback(); + } + throw new GatewayError(e?.message || e); + } finally { + if (timeoutId) { + clearTimeout(timeoutId); + } + } +} - const rawDataItem: Buffer = await rawBody(ctx.req); - const interactionDataItem = new DataItem(rawDataItem); +async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { + const { sLogger, arweave, jwk, vrf, lastTxSync } = ctx; - if (tagsExceedLimit(interactionDataItem.tags)) { - throw new Error(`Interaction data item tags exceed limit.`); - } + const initialBenchmark = Benchmark.measure(); - if (b64UrlToString(interactionDataItem.data).length > 4) { - throw new Error("Interaction data item's data field exceeds 4 bytes limit."); - } + const benchmark = Benchmark.measure(); - sLogger.debug('New sequencer data item', interactionDataItem.id); + const rawDataItem: Buffer = await rawBody(ctx.req); + const interactionDataItem = new DataItem(rawDataItem); - const isInteractionDataItemValid = await interactionDataItem.isValid(); - if (!isInteractionDataItemValid) { - ctx.throw(400, 'Interaction data item binary is not valid.'); - } + if (tagsExceedLimit(interactionDataItem.tags)) { + throw new Error(`Interaction data item tags exceed limit.`); + } - const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; + if (b64UrlToString(interactionDataItem.data).length > 4) { + throw new Error("Interaction data item's data field exceeds 4 bytes limit."); + } - const trx = await dbSource.primaryDb.transaction(); - const contractPrevSortKey: string | null = await lastTxSync.acquireMutex(contractTag, trx); - const millis = Date.now(); + sLogger.debug('New sequencer data item', interactionDataItem.id); - const { currentHeight, currentBlockTimestamp, currentBlockId, cachedBlockInfo } = getBlockInfo( - interactionDataItem.id, - sLogger - ); + const isInteractionDataItemValid = await interactionDataItem.isValid(); + if (!isInteractionDataItemValid) { + ctx.throw(400, 'Interaction data item binary is not valid.'); + } - const sortKey = await createSortKey(arweave, jwk, currentBlockId, millis, interactionDataItem.id, currentHeight); - if (contractPrevSortKey !== null && sortKey.localeCompare(contractPrevSortKey) <= 0) { - throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${contractPrevSortKey})!`); - } + const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; + + const acquireMutexResult = await lastTxSync.acquireMutex(contractTag, trx); + sLogger.debug('Acquire mutex result', acquireMutexResult); + // note: lastSortKey can be null if that's a very first interaction with a contract. + if ( + acquireMutexResult.blockHash == null || + acquireMutexResult.blockHeight == null || + acquireMutexResult.blockTimestamp == null + ) { + throw new Error(`Missing data in acquireMutexResult: ${JSON.stringify(acquireMutexResult)}`); + } - const originalSignature = interactionDataItem.signature; - const originalAddress = await determineOwner(interactionDataItem, arweave); - const testnetVersion = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET)?.value || null; - const internalWrites: string[] = []; - interactionDataItem.tags - .filter((t) => t.name == SmartWeaveTags.INTERACT_WRITE) - .forEach((t) => internalWrites.push(t.value)); - - const tags = getUploaderTags( - originalAddress, - interactionDataItem.id, - currentHeight, - currentBlockId, - currentBlockTimestamp, - interactionDataItem.tags - ); - tags.push({ name: 'Sequencer-Mills', value: '' + millis }); - tags.push({ name: 'Sequencer-Sort-Key', value: sortKey }); - tags.push({ name: 'Sequencer-Prev-Sort-Key', value: contractPrevSortKey || 'null' }); - - let vrfData: VrfData | null = null; - const requestVrfTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.REQUEST_VRF)?.value || null; - if (requestVrfTag) { - const vrfGen = generateVrfTags(sortKey, vrf, arweave); - tags.push(...vrfGen.vrfTags); - vrfData = vrfGen.vrfData; - } + const millis = Date.now(); + const sortKey = await createSortKey( + arweave, + jwk, + acquireMutexResult.blockHash, + millis, + interactionDataItem.id, + acquireMutexResult.blockHeight + ); + if (acquireMutexResult.lastSortKey !== null && sortKey.localeCompare(acquireMutexResult.lastSortKey) <= 0) { + throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${acquireMutexResult.lastSortKey})!`); + } + + const originalSignature = interactionDataItem.signature; + const originalAddress = await determineOwner(interactionDataItem, arweave); + const testnetVersion = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET)?.value || null; + const inputTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.INPUT)?.value || ''; + const internalWrites: string[] = []; + interactionDataItem.tags + .filter((t) => t.name == SmartWeaveTags.INTERACT_WRITE) + .forEach((t) => internalWrites.push(t.value)); + + const tags = [ + { name: 'Sequencer', value: 'RedStone' }, + { name: 'Sequencer-Owner', value: originalAddress }, + { name: 'Sequencer-Tx-Id', value: interactionDataItem.id }, + { name: 'Sequencer-Block-Height', value: '' + acquireMutexResult.blockHeight }, + { name: 'Sequencer-Block-Id', value: acquireMutexResult.blockHash }, + { name: 'Sequencer-Block-Timestamp', value: '' + acquireMutexResult.blockTimestamp }, + { name: 'Sequencer-Mills', value: '' + millis }, + { name: 'Sequencer-Sort-Key', value: sortKey }, + { name: 'Sequencer-Prev-Sort-Key', value: acquireMutexResult.lastSortKey || 'null' }, + ...interactionDataItem.tags, + ]; + + let vrfData: VrfData | null = null; + const requestVrfTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.REQUEST_VRF)?.value || null; + if (requestVrfTag) { + const vrfGen = generateVrfTags(sortKey, vrf, arweave); + tags.push(...vrfGen.vrfTags); + vrfData = vrfGen.vrfData; + } - const inputTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.INPUT)?.value || ''; - - const parsedInput = safeParseInput(inputTag, sLogger); - const functionName = parseFunctionName(inputTag, sLogger); - let evolve: string | null; - evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; - - sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); - - const interaction = createInteraction( - interactionDataItem, - originalAddress, - interactionDataItem.tags, - currentHeight, - currentBlockId, - cachedBlockInfo, - sortKey, - vrfData, - originalSignature, - testnetVersion, - contractPrevSortKey - ); - - sLogger.debug('inserting into tables'); - - await trx.raw( - ` + const interaction = createInteraction( + interactionDataItem, + originalAddress, + interactionDataItem.tags, + acquireMutexResult.blockHeight, + acquireMutexResult.blockHash, + acquireMutexResult.blockTimestamp, + sortKey, + vrfData, + originalSignature, + testnetVersion, + acquireMutexResult.lastSortKey + ); + + const parsedInput = JSON.parse(inputTag); + const functionName = parseFunctionName(inputTag, sLogger); + let evolve: string | null; + evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; + + sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); + sLogger.debug('inserting into tables'); + + await trx.raw( + ` WITH ins_interaction AS ( - INSERT INTO interactions (interaction_id, - interaction, - block_height, - block_id, - contract_id, - function, - input, - confirmation_status, - confirming_peer, - source, - block_timestamp, - interact_write, - sort_key, - evolve, - testnet, - last_sort_key, - owner, - sync_timestamp) - VALUES (:interaction_id, - :interaction, - :block_height, - :block_id, - :contract_id, - :function, - :input, - :confirmation_status, - :confirming_peer, - :source, - :block_timestamp, - :interact_write, - :sort_key, - :evolve, - :testnet, - :prev_sort_key, - :owner, - :sync_timestamp) - RETURNING id) + INSERT + INTO interactions (interaction_id, + interaction, + block_height, + block_id, + contract_id, + function, + input, + confirmation_status, + confirming_peer, + source, + block_timestamp, + interact_write, + sort_key, + evolve, + testnet, + last_sort_key, + owner, + sync_timestamp) + VALUES ( + :interaction_id, + :interaction, + :block_height, + :block_id, + :contract_id, + :function, + :input, + :confirmation_status, + :confirming_peer, + :source, + :block_timestamp, + :interact_write, + :sort_key, + :evolve, + :testnet, + :prev_sort_key, + :owner, + :sync_timestamp) + RETURNING id) INSERT INTO bundle_items (interaction_id, state, transaction, tags, data_item) SELECT i.id, 'PENDING', :original_transaction, :tags, :data_item FROM ins_interaction i; `, - { - interaction_id: interactionDataItem.id, - interaction: interaction, - block_height: currentHeight, - block_id: currentBlockId, - contract_id: contractTag, - function: functionName, - input: inputTag, - confirmation_status: 'confirmed', - confirming_peer: BUNDLR_NODE1_URL, - source: 'redstone-sequencer', - block_timestamp: currentBlockTimestamp, - interact_write: internalWrites, - sort_key: sortKey, - evolve: evolve, - testnet: testnetVersion, - prev_sort_key: contractPrevSortKey, - owner: originalAddress, - original_transaction: ctx.request.body, - tags: JSON.stringify(tags), - sync_timestamp: millis, - data_item: interactionDataItem.getRaw(), - } - ); - - await trx.commit(); - sLogger.info('Total sequencer processing', benchmark.elapsed()); + { + interaction_id: interactionDataItem.id, + interaction: interaction, + block_height: acquireMutexResult.blockHeight, + block_id: acquireMutexResult.blockHash, + contract_id: contractTag, + function: functionName, + input: inputTag, + confirmation_status: 'confirmed', + confirming_peer: BUNDLR_NODE1_URL, + source: 'redstone-sequencer', + block_timestamp: acquireMutexResult.blockTimestamp, + interact_write: internalWrites, + sort_key: sortKey, + evolve: evolve, + testnet: testnetVersion, + prev_sort_key: acquireMutexResult.lastSortKey, + owner: originalAddress, + original_transaction: ctx.request.body, + tags: JSON.stringify(tags), + sync_timestamp: millis, + data_item: interactionDataItem.getRaw(), + } + ); - ctx.body = { - id: interactionDataItem.id, - }; + sLogger.info('Total sequencer processing', benchmark.elapsed()); - sendNotification(ctx, contractTag, undefined, interaction); - publishInteraction( - ctx, - contractTag, - interaction, - sortKey, - contractPrevSortKey, - functionName, - 'redstone-sequencer', - millis, - testnetVersion - ); - } catch (e: any) { - if (trx != null) { - await (trx as Knex.Transaction).rollback(); - } - throw new GatewayError(e?.message || e); - } + return interactionDataItem.id; } From 627186b19a39ac8058cd5fb62df6bbba503048ab Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 3 Aug 2023 13:52:01 +0200 Subject: [PATCH 51/95] new nakurwiaj --- package.json | 3 + tools/nakurwiaj.js | 155 +++++++++++++++++++++++++++++++++++---------- yarn.lock | 137 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 259 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 6dbab556..34dd850a 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,9 @@ "uuid": "^9.0.0", "warp-arbundles": "1.0.0", "warp-contracts": "1.2.48", + "warp-contracts-new": "npm:warp-contracts", + "warp-contracts-old": "npm:warp-contracts@1.4.12", + "warp-contracts-plugin-signature": "^1.0.16", "warp-contracts-pubsub": "^1.0.3", "warp-contracts-subscription-plugin": "1.0.4", "warp-signature": "1.0.4", diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 03306922..4fb3397b 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -1,57 +1,144 @@ -const fs = require("fs"); +const fs = require('fs'); +const warpContracts = require('warp-contracts-old'); +const warpContractsNew = require('warp-contracts-new'); +const { EthereumSigner } = require('warp-contracts-plugin-signature/server'); -const warpContracts = require("warp-contracts"); -const warp = warpContracts.WarpFactory.forTestnet(); +let errors_l1 = ``; +let errors_l2 = ``; + +const warp = warpContracts.WarpFactory.forMainnet({ + ...warpContracts.defaultCacheOptions, + dbLocation: 'warp/old', +}).useGwUrl('http://34.141.17.15:5666'); +const warpNew = warpContractsNew.WarpFactory.forMainnet({ + ...warpContractsNew.defaultCacheOptions, + dbLocation: 'warp/new', +}).useGwUrl('http://34.141.17.15:5666'); const wallet = readJSON('./.secrets/warp-wallet-jwk.json'); +const ethWallet = fs.readFileSync('./.secrets/ethereum-priv-key.txt', 'utf-8').replace(/\n/g, ''); warpContracts.LoggerFactory.INST.logLevel('error'); +warpContractsNew.LoggerFactory.INST.logLevel('error'); + +const contractB = warp + .contract('YhTW-jV7ffbYciz1bcJ-SM-79cmt9MkoZYutyaghg9Y') + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/', + }) + .connect(wallet); -const contractB = warp.contract("1LsbT8HH8SbldveeZcZZwgmuLn0ueJ6pN7ZSrbTqeVU") +const contractC = warp + .contract('-tU1YKqnwgzpZIxjqUPBzRFsCfXVNZ6t1lu5pi5cV3k') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/' + sequencerUrl: 'http://34.141.17.15:5666/', }) .connect(wallet); -const contractC = warp.contract("o-QYGKa6rkWj5i0Vx0VQy99myCkPNeCAJi6-UZnhIVU") +const contractD = warpNew + .contract('7AZv5bczZhJJpUfwhzjz3iGdzo2PaBi0elgoRwzwg4g') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/' + sequencerUrl: 'http://34.141.17.15:5666/', }) .connect(wallet); +const contractE = warpNew + .contract('OsGmh1UtH4QytV0Tdxgg_TJ-VjfHkQYPLX7yuK1OfiQ') + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/', + }) + .connect(wallet); + +const contractF = warpNew + .contract('7AZv5bczZhJJpUfwhzjz3iGdzo2PaBi0elgoRwzwg4g') + .setEvaluationOptions({ + sequencerUrl: 'http://34.141.17.15:5666/', + }) + .connect(new EthereumSigner(ethWallet)); + setInterval(async () => { console.log('sending to L2...'); - await Promise.all([ - contractB.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - contractC.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }), - ]); + try { + await Promise.all([ + contractB.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }), + contractC.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }), + contractD.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }), + contractE.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }), + contractF.writeInteraction({ + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }), + ]); + } catch (e) { + errors_l2 += `${e.stack}\n\n`; + } }, 3000); - setInterval(async () => { console.log('sending to L1...'); - await Promise.all([ - contractB.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }, { disableBundling: true }), - contractC.writeInteraction({ - function: 'transfer', - target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', - qty: 100 - }, { disableBundling: true }), - - ]); + try { + await Promise.all([ + contractB.writeInteraction( + { + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }, + { disableBundling: true } + ), + contractC.writeInteraction( + { + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }, + { disableBundling: true } + ), + contractD.writeInteraction( + { + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }, + { disableBundling: true } + ), + contractE.writeInteraction( + { + function: 'transfer', + target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', + qty: 1, + }, + { disableBundling: true } + ), + ]); + } catch (e) { + errors_l1 += `${e.stack}\n\n`; + } }, 5000); +setInterval(() => { + fs.appendFileSync(`errors_l1.txt`, errors_l1); + fs.appendFileSync(`errors_l2.txt`, errors_l2); + errors_l1 = ``; + errors_l2 = ``; +}, 3600000); + function readJSON(path) { const content = fs.readFileSync(path, 'utf-8'); try { @@ -67,4 +154,4 @@ process.on('uncaughtException', () => { process.on('unhandledRejection', (e) => { console.error('unhandledRejection'); -}); \ No newline at end of file +}); diff --git a/yarn.lock b/yarn.lock index ea360dd9..5927cb2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2388,6 +2388,30 @@ arbundles@^0.9.6: multistream "^4.1.0" tmp-promise "^3.0.2" +arbundles@^0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/arbundles/-/arbundles-0.9.8.tgz#d02e1151aa1cac75e33058a67f65a627e6a669c5" + integrity sha512-UevirqeqzCSLPlgyxvn7vvuRm22+wAK+HXCYGnE1HTytgfAu8so/g41wkUziNzoeeTNmodJpEy6RbRfYOaRsTA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/providers" "^5.7.2" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wallet" "^5.7.0" + "@noble/ed25519" "^1.6.1" + arweave "=1.11.8" + base64url "^3.0.1" + bs58 "^4.0.1" + keccak "^3.0.2" + secp256k1 "^4.0.2" + optionalDependencies: + "@randlabs/myalgo-connect" "^1.1.2" + algosdk "^1.13.1" + arweave-stream-tx "^1.1.0" + multistream "^4.1.0" + tmp-promise "^3.0.2" + archiver-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" @@ -2477,7 +2501,7 @@ arweave@1.11.8, arweave@=1.11.8: bignumber.js "^9.0.2" util "^0.12.4" -arweave@^1.13.7: +arweave@1.13.7, arweave@^1.13.7: version "1.13.7" resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.13.7.tgz#cda8534c833baec372a7052c61f53b4e39a886d7" integrity sha512-Hv+x2bSI6UyBHpuVbUDMMpMje1ETfpJWj52kKfz44O0IqDRi/LukOkkDUptup1p6OT6KP1/DdpnUnsNHoskFeA== @@ -2487,6 +2511,16 @@ arweave@^1.13.7: base64-js "^1.5.1" bignumber.js "^9.0.2" +arweave@^1.13.1: + version "1.14.4" + resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.14.4.tgz#5ba22136aa0e7fd9495258a3931fb770c9d6bf21" + integrity sha512-tmqU9fug8XAmFETYwgUhLaD3WKav5DaM4p1vgJpEj/Px2ORPPMikwnSySlFymmL2qgRh2ZBcZsg11+RXPPGLsA== + dependencies: + arconnect "^0.4.2" + asn1.js "^5.4.1" + base64-js "^1.5.1" + bignumber.js "^9.0.2" + asn1.js@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -2497,6 +2531,13 @@ asn1.js@^5.4.1: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" +async-mutex@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.4.0.tgz#ae8048cd4d04ace94347507504b3cf15e631c25f" + integrity sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA== + dependencies: + tslib "^2.4.0" + async-retry@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" @@ -2683,6 +2724,11 @@ bigint-buffer@^1.1.5: dependencies: bindings "^1.3.0" +bignumber.js@9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== + bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.0.2: version "9.1.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.0.tgz#8d340146107fe3a6cb8d40699643c302e8773b62" @@ -6871,6 +6917,11 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.4.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -7138,6 +7189,63 @@ warp-arbundles@1.0.0: buffer "^6.0.3" warp-isomorphic "^1.0.4" +warp-arbundles@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/warp-arbundles/-/warp-arbundles-1.0.1.tgz#c816ee44aacd90e0214b1b7db8028c6d5b468770" + integrity sha512-bWyF8PoS5D2M8yk7YAT/DFi4pzoPxfXaS1o9eEelcD5SU42PW/wVxwzrvn6pLaHFIK5Zys15V2eGd+8X1Ty62Q== + dependencies: + arweave "^1.13.7" + base64url "^3.0.1" + buffer "^6.0.3" + warp-isomorphic "^1.0.4" + +"warp-contracts-new@npm:warp-contracts": + version "1.4.14" + resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.14.tgz#0a14428229736f568cdd54723dfa903dfe86ccfc" + integrity sha512-5tJzD1biarpXLJRxneEB7thWCqRdZXYhPr77XJxY9oveLANryibYJSEtUbrycHcLurSAQ+Vyd2qd5JHq8TAC4A== + dependencies: + archiver "^5.3.0" + arweave "1.13.7" + async-mutex "^0.4.0" + bignumber.js "9.1.1" + events "3.3.0" + fast-copy "^3.0.0" + level "^8.0.0" + memory-level "^1.0.0" + safe-stable-stringify "2.4.1" + stream-buffers "^3.0.2" + unzipit "^1.4.0" + warp-arbundles "1.0.1" + warp-isomorphic "1.0.4" + warp-wasm-metering "1.0.1" + +"warp-contracts-old@npm:warp-contracts@1.4.12": + version "1.4.12" + resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.12.tgz#b1681fc0b81e9128c272d7ce8f417319ce5fb969" + integrity sha512-DjmxN4U26jzYhlumTj1QgxH1GPmjN2oAkTXDGBvXSpdLYvf0n3aGJLBVYddfH9P/IQlxcQJ6KaXS4Ihlq9FrAw== + dependencies: + archiver "^5.3.0" + arweave "1.13.7" + async-mutex "^0.4.0" + bignumber.js "9.1.1" + events "3.3.0" + fast-copy "^3.0.0" + level "^8.0.0" + memory-level "^1.0.0" + safe-stable-stringify "2.4.1" + stream-buffers "^3.0.2" + unzipit "^1.4.0" + warp-isomorphic "1.0.4" + warp-wasm-metering "1.0.1" + +warp-contracts-plugin-signature@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/warp-contracts-plugin-signature/-/warp-contracts-plugin-signature-1.0.16.tgz#7ba9ad9651ae20e679e76daaffe6836686ebf00d" + integrity sha512-sYrL/bCj7iqjUk7nPSnNpdkcvRPA0yQlNqBN0iyUQ9GQuyskwLDEeQUfe+T1oDwHaznqqABqBtItB+3TsUULLw== + dependencies: + arbundles "^0.9.8" + arweave "^1.13.1" + warp-contracts-pubsub@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/warp-contracts-pubsub/-/warp-contracts-pubsub-1.0.3.tgz#5d2636b3da95c7b2a31b51668b70b9c3fb3685a6" @@ -7196,7 +7304,15 @@ warp-contracts@1.2.48: vm2 "3.9.11" warp-wasm-metering "1.0.0" -warp-isomorphic@^1.0.4: +warp-isomorphic@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/warp-isomorphic/-/warp-isomorphic-1.0.0.tgz#dccccfc046bc6ac77919f8be1024ced1385c70ea" + integrity sha512-E+9+brlrnZoNpNvpz8foIZiCk9fIVukRBZYEy/yefM+oAG+zNgDPb/xNaZyUJWC8rSZxE1DqrhRl0JxjtLVltA== + dependencies: + buffer "^6.0.3" + undici "^5.8.0" + +warp-isomorphic@1.0.4, warp-isomorphic@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/warp-isomorphic/-/warp-isomorphic-1.0.4.tgz#1017eba260e0f0228b33b94b9e36a1afe54e09d8" integrity sha512-W77IoLjq/eu5bY1uRrlmVt5lLDoIHeZ0ozJ/j67FTnxvZRXu887biEnom1nx8q1UgOKyJh8eQYFQaE2FLlKhFg== @@ -7225,6 +7341,15 @@ warp-wasm-json-toolkit@1.0.0: leb128 "0.0.4" redstone-isomorphic "1.1.0" +warp-wasm-json-toolkit@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/warp-wasm-json-toolkit/-/warp-wasm-json-toolkit-1.0.2.tgz#16ca399e5b20da804c01ff0d00979341b689a0e7" + integrity sha512-T6pKJz9mO0ZFYiu4jB2v8j8t8Cw21n/+uFh0QKbc/7cJSssGd3I26sV/VXjoDbGuG7bGzK9BewlFd+ukvxABOA== + dependencies: + buffer-pipe "0.0.3" + leb128 "0.0.4" + warp-isomorphic "1.0.0" + warp-wasm-metering@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/warp-wasm-metering/-/warp-wasm-metering-1.0.0.tgz#ff2ded687885af22c8fc6560409a582e127c3af3" @@ -7233,6 +7358,14 @@ warp-wasm-metering@1.0.0: leb128 "^0.0.4" warp-wasm-json-toolkit "1.0.0" +warp-wasm-metering@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/warp-wasm-metering/-/warp-wasm-metering-1.0.1.tgz#1496b0b9a936985cf21a910e909b87630faa1c43" + integrity sha512-s2NtOPTGIDPWeDKyrY5UiUUf3oOjbjwGF9sgmRR3nqXzjxdgppvuf+6VYquzYM3xRMXIOq+AWMK2H/D/Yv+4tg== + dependencies: + leb128 "^0.0.4" + warp-wasm-json-toolkit "1.0.2" + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" From 5e49ac765253503c1f059401d6affb0fd544303e Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 3 Aug 2023 18:41:07 +0200 Subject: [PATCH 52/95] chore: save errors on exit --- tools/nakurwiaj.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 4fb3397b..f83c2a02 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -133,11 +133,19 @@ setInterval(async () => { }, 5000); setInterval(() => { + saveErrors(); +}, 3600000); + +function saveErrors() { fs.appendFileSync(`errors_l1.txt`, errors_l1); fs.appendFileSync(`errors_l2.txt`, errors_l2); errors_l1 = ``; errors_l2 = ``; -}, 3600000); +} + +process.on('SIGINT', () => { + saveErrors(); +}); function readJSON(path) { const content = fs.readFileSync(path, 'utf-8'); From f4e645be4c40b84a2e180603fb951730470fc9c8 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 3 Aug 2023 19:09:41 +0200 Subject: [PATCH 53/95] exit properly from nakurwiaj --- tools/nakurwiaj.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index f83c2a02..498982dd 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -145,6 +145,7 @@ function saveErrors() { process.on('SIGINT', () => { saveErrors(); + process.exit(-1); }); function readJSON(path) { From 3192e98ad4c1254effd2519100ec3d3c36f5f4ff Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 8 Aug 2023 12:38:39 +0200 Subject: [PATCH 54/95] chore: return sortKey from sequencer --- src/gateway/router/routes/sequencerRoute.ts | 43 ++++++++----------- .../router/routes/sequencerRoute_v2.ts | 18 +++++--- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index e8910b06..456fff7d 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -21,6 +21,14 @@ export type VrfData = { pubkey: string; }; +export type SequencerResult = { + sortKey: string; + prevSortKey: string | null; + id: string; + internalWrites: string[]; + timestamp: number +} + export async function sequencerRoute(ctx: Router.RouterContext) { const { dbSource } = ctx; const trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; @@ -28,11 +36,9 @@ export async function sequencerRoute(ctx: Router.RouterContext) { const { timeoutId, timeoutPromise } = timeout(0.5); try { - const transactionId = await Promise.race([timeoutPromise, doGenerateSequence(ctx, trx)]); + const result = await Promise.race([timeoutPromise, doGenerateSequence(ctx, trx)]); await trx.commit(); - ctx.body = { - id: transactionId, - }; + ctx.body = result; } catch (e: any) { if (trx != null) { await trx.rollback(); @@ -45,7 +51,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { } } -async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { +async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { const { sLogger, arweave, jwk, vrf, lastTxSync, signatureVerification } = ctx; const initialBenchmark = Benchmark.measure(); @@ -221,7 +227,13 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti sLogger.info('Total sequencer processing', benchmark.elapsed()); - return transaction.id; + return { + id: transaction.id, + sortKey, + timestamp: millis, + prevSortKey: acquireMutexResult.lastSortKey, + internalWrites + }; } export function createInteraction( @@ -367,25 +379,6 @@ async function prepareTags(logger: any, transaction: Transaction, originalOwner: }; } -export function getUploaderTags( - originalAddress: string, - id: string, - currentHeight: number, - currentBlockId: string, - currentBlockTimestamp: number, - decodedTags: GQLTagInterface[] -): GQLTagInterface[] { - return [ - { name: 'Sequencer', value: 'RedStone' }, - { name: 'Sequencer-Owner', value: originalAddress }, - { name: 'Sequencer-Tx-Id', value: id }, - { name: 'Sequencer-Block-Height', value: '' + currentHeight }, - { name: 'Sequencer-Block-Id', value: currentBlockId }, - { name: 'Sequencer-Block-Timestamp', value: '' + currentBlockTimestamp }, - ...decodedTags, - ]; -} - export async function uploadToBundlr( transaction: Transaction, bundlr: Bundlr, diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 94a71fbd..f388c5dd 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -6,7 +6,7 @@ import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { DataItem } from 'arbundles'; -import { createInteraction, generateVrfTags } from './sequencerRoute'; +import { createInteraction, generateVrfTags, SequencerResult } from "./sequencerRoute"; import { createSortKey } from './sequencerRoute'; import { tagsExceedLimit } from 'warp-arbundles'; import rawBody from 'raw-body'; @@ -20,11 +20,9 @@ export async function sequencerRoute_v2(ctx: Router.RouterContext) { const { timeoutId, timeoutPromise } = timeout(0.5); try { - const transactionId = await Promise.race([timeoutPromise, doGenerateSequence(ctx, trx)]); + const result = await Promise.race([timeoutPromise, doGenerateSequence(ctx, trx)]); await trx.commit(); - ctx.body = { - id: transactionId, - }; + ctx.body = result; } catch (e: any) { if (trx != null) { await trx.rollback(); @@ -37,7 +35,7 @@ export async function sequencerRoute_v2(ctx: Router.RouterContext) { } } -async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { +async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { const { sLogger, arweave, jwk, vrf, lastTxSync } = ctx; const initialBenchmark = Benchmark.measure(); @@ -214,5 +212,11 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti sLogger.info('Total sequencer processing', benchmark.elapsed()); - return interactionDataItem.id; + return { + id: interactionDataItem.id, + sortKey, + timestamp: millis, + prevSortKey: acquireMutexResult.lastSortKey, + internalWrites + }; } From 891cd40066f2ea6d4d0fe3e73ccf96e64ddcc767 Mon Sep 17 00:00:00 2001 From: Asia Date: Fri, 15 Sep 2023 14:18:28 +0200 Subject: [PATCH 55/95] fix: tags size limit should be checked when preparing tags for nested bundle --- src/gateway/router/routes/sequencerRoute_v2.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index f388c5dd..87422a1a 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -6,7 +6,7 @@ import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { DataItem } from 'arbundles'; -import { createInteraction, generateVrfTags, SequencerResult } from "./sequencerRoute"; +import { createInteraction, generateVrfTags, SequencerResult } from './sequencerRoute'; import { createSortKey } from './sequencerRoute'; import { tagsExceedLimit } from 'warp-arbundles'; import rawBody from 'raw-body'; @@ -108,6 +108,10 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti ...interactionDataItem.tags, ]; + if (tagsExceedLimit(tags)) { + throw new Error(`Nested bundle tags exceed limit.`); + } + let vrfData: VrfData | null = null; const requestVrfTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.REQUEST_VRF)?.value || null; if (requestVrfTag) { @@ -217,6 +221,6 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti sortKey, timestamp: millis, prevSortKey: acquireMutexResult.lastSortKey, - internalWrites + internalWrites, }; } From 284eac2f7c1e46da2261af0a983787cb6ae9ac81 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Mon, 18 Sep 2023 14:44:49 +0200 Subject: [PATCH 56/95] feat: return original src tx id from contract endpoint --- src/gateway/router/routes/contracts/contractWithSourceRoute.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/router/routes/contracts/contractWithSourceRoute.ts b/src/gateway/router/routes/contracts/contractWithSourceRoute.ts index 4a4eabe6..c51728db 100644 --- a/src/gateway/router/routes/contracts/contractWithSourceRoute.ts +++ b/src/gateway/router/routes/contracts/contractWithSourceRoute.ts @@ -25,6 +25,7 @@ export async function contractWithSourceRoute(ctx: Router.RouterContext) { ` SELECT c.contract_id as "txId", c.bundler_contract_tx_id as "bundlerTxId", + c.src_tx_id as "originalSrcTxId", s.src_tx_id as "srcTxId", (case when s.src_content_type = 'application/javascript' then s.src else null end) as src, (case when s.src_content_type = 'application/wasm' then s.src_binary else null end) as "srcBinary", From f7a741ba46d469f4d9f33e5d72bab4d0b809ec87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szynwelski?= Date: Fri, 27 Oct 2023 11:52:04 +0200 Subject: [PATCH 57/95] Endpoint with sequencer address --- src/gateway/router/gatewayRouter.ts | 2 ++ src/gateway/router/routes/sequencerAddress.ts | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 src/gateway/router/routes/sequencerAddress.ts diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index b50f8177..e57975bd 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -7,6 +7,7 @@ import { contractRoute } from './routes/contracts/contractRoute'; import { contractWithSourceRoute } from './routes/contracts/contractWithSourceRoute'; import { contractWithSourceRoute_v2 } from './routes/contracts/contractWithSourceRoute_v2'; import { interactionRoute } from './routes/interactions/interactionRoute'; +import { sequencerAddressRoute } from './routes/sequencerAddress' import { sequencerRoute } from './routes/sequencerRoute'; import { sequencerRoute_v2 } from './routes/sequencerRoute_v2'; import { interactionsStreamRoute } from './routes/interactions/interactionsStreamRoute'; @@ -57,6 +58,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/contracts-by-source', contractsBySourceRoute); router.get('/creator', creatorRoute); router.get('/gcp/alive', gcpAliveRoute); + router.get('/sequencer/address', sequencerAddressRoute) // post if (!replica) { diff --git a/src/gateway/router/routes/sequencerAddress.ts b/src/gateway/router/routes/sequencerAddress.ts new file mode 100644 index 00000000..214bcd9c --- /dev/null +++ b/src/gateway/router/routes/sequencerAddress.ts @@ -0,0 +1,8 @@ +import Router from '@koa/router'; + +export async function sequencerAddressRoute(ctx: Router.RouterContext) { + ctx.body = { + url: 'https://gw.warp.cc', + type: 'centralized' + }; +} From 24007bb70568d71b37e11ef3caa19504da197959 Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 9 Nov 2023 16:19:32 +0100 Subject: [PATCH 58/95] feat: contracts by tag route (#184) --- src/gateway/router/gatewayRouter.ts | 2 + .../router/routes/contracts/contractsByTag.ts | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/gateway/router/routes/contracts/contractsByTag.ts diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index e57975bd..842dafb1 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -29,6 +29,7 @@ import { deployContractRoute_v2 } from './routes/deploy/deployContractRoute_v2'; import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; import { gcpAliveRoute } from './routes/gcpAliveRoute'; +import { contractsByTag } from './routes/contracts/contractsByTag'; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -59,6 +60,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/creator', creatorRoute); router.get('/gcp/alive', gcpAliveRoute); router.get('/sequencer/address', sequencerAddressRoute) + router.get('/contracts-by-tag', contractsByTag); // post if (!replica) { diff --git a/src/gateway/router/routes/contracts/contractsByTag.ts b/src/gateway/router/routes/contracts/contractsByTag.ts new file mode 100644 index 00000000..24f6f840 --- /dev/null +++ b/src/gateway/router/routes/contracts/contractsByTag.ts @@ -0,0 +1,81 @@ +import Router from '@koa/router'; +import { Benchmark } from 'warp-contracts'; +import { GatewayError } from '../../../errorHandlerMiddleware'; + +const MAX_CONTRACTS_PER_PAGE = 100; + +export async function contractsByTag(ctx: Router.RouterContext) { + const { logger, dbSource, arweave } = ctx; + + const { tag, owner, page, limit, testnet } = ctx.query; + + if (!tag) { + throw new GatewayError('Tag parameter must be provided.', 422); + } + + logger.debug('Contracts by tag route', { tag, owner, page, limit }); + + const parsedPage = page ? parseInt(page as string) : 1; + const parsedLimit = limit ? Math.min(parseInt(limit as string), MAX_CONTRACTS_PER_PAGE) : MAX_CONTRACTS_PER_PAGE; + const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; + + const bindings: any[] = []; + const tagEncoded = JSON.stringify({ + name: arweave.utils.stringToB64Url(JSON.parse(tag as string).name), + value: arweave.utils.stringToB64Url(JSON.parse(tag as string).value), + }); + + owner && bindings.push(owner); + parsedPage && bindings.push(parsedLimit); + parsedPage && bindings.push(offset); + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + ` + SELECT c.contract_id AS contract, + c.owner AS owner, + c.testnet AS testnet, + c.contract_tx AS contractTx, + c.sync_timestamp AS syncTimestamp, + count(*) OVER () AS total + FROM contracts c + WHERE c.contract_id != '' + AND c.type != 'error' + ${testnet ? ' AND c.testnet IS NOT NULL' : ''} + ${owner ? ` AND c.owner = ?` : ''} + AND c.contract_tx->'tags' @> '[${tagEncoded}]' + GROUP BY c.contract_id, c.owner + ORDER BY c.sync_timestamp DESC + ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; + `, + bindings + ); + + const total = result?.rows?.length > 0 ? parseInt(result.rows[0].total) : 0; + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + page: parsedPage, + pages: Math.ceil(total / parsedLimit), + }, + contracts: result?.rows.map((r: any) => { + return { + ...r, + contracttx: { + tags: r.contracttx.tags.map((t: any) => { + try { + const name = arweave.utils.b64UrlToString(t.name); + const value = arweave.utils.b64UrlToString(t.value); + return { name, value }; + } catch (e) { + return; + } + }), + }, + }; + }), + }; + logger.debug('Contracts loaded in', benchmark.elapsed()); +} From 4c0f17bca11b491dd6cf66759e430c3d47f6cc52 Mon Sep 17 00:00:00 2001 From: Asia Date: Tue, 14 Nov 2023 10:54:01 +0100 Subject: [PATCH 59/95] feat: register contracts based on metadata from Arweave gql (#185) --- .../router/routes/contracts/contractsByTag.ts | 4 +- .../routes/deploy/registerContractRoute.ts | 155 +++++++++++------- 2 files changed, 96 insertions(+), 63 deletions(-) diff --git a/src/gateway/router/routes/contracts/contractsByTag.ts b/src/gateway/router/routes/contracts/contractsByTag.ts index 24f6f840..2b3befd7 100644 --- a/src/gateway/router/routes/contracts/contractsByTag.ts +++ b/src/gateway/router/routes/contracts/contractsByTag.ts @@ -7,7 +7,7 @@ const MAX_CONTRACTS_PER_PAGE = 100; export async function contractsByTag(ctx: Router.RouterContext) { const { logger, dbSource, arweave } = ctx; - const { tag, owner, page, limit, testnet } = ctx.query; + const { tag, owner, page, limit, testnet, srcId } = ctx.query; if (!tag) { throw new GatewayError('Tag parameter must be provided.', 422); @@ -26,6 +26,7 @@ export async function contractsByTag(ctx: Router.RouterContext) { }); owner && bindings.push(owner); + srcId && bindings.push(srcId); parsedPage && bindings.push(parsedLimit); parsedPage && bindings.push(offset); @@ -43,6 +44,7 @@ export async function contractsByTag(ctx: Router.RouterContext) { AND c.type != 'error' ${testnet ? ' AND c.testnet IS NOT NULL' : ''} ${owner ? ` AND c.owner = ?` : ''} + ${srcId ? ` AND c.src_tx_id = ?` : ''} AND c.contract_tx->'tags' @> '[${tagEncoded}]' GROUP BY c.contract_id, c.owner ORDER BY c.sync_timestamp DESC diff --git a/src/gateway/router/routes/deploy/registerContractRoute.ts b/src/gateway/router/routes/deploy/registerContractRoute.ts index b3a7a06b..46815fd1 100644 --- a/src/gateway/router/routes/deploy/registerContractRoute.ts +++ b/src/gateway/router/routes/deploy/registerContractRoute.ts @@ -1,56 +1,67 @@ import Router from '@koa/router'; -import {evalType} from '../../../tasks/contractsMetadata'; -import {getCachedNetworkData} from '../../../tasks/networkInfoCache'; -import {publishContract, sendNotification} from '../../../publisher'; -import {evalManifest, WarpDeployment} from './deployContractRoute'; -import {Tag} from 'arweave/node/lib/transaction'; -import {stringToB64Url} from 'arweave/node/lib/utils'; -import {fetch} from 'undici'; -import {backOff} from 'exponential-backoff'; -import {getTestnetTag} from './deployBundledRoute'; -import {ContractInsert} from '../../../../db/insertInterfaces'; -import {GatewayError} from "../../../errorHandlerMiddleware"; - -const BUNDLR_QUERY = `query Transactions($ids: [String!]) { +import { evalType } from '../../../tasks/contractsMetadata'; +import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; +import { publishContract, sendNotification } from '../../../publisher'; +import { evalManifest, WarpDeployment } from './deployContractRoute'; +import { Tag } from 'arweave/node/lib/transaction'; +import { stringToB64Url } from 'arweave/node/lib/utils'; +import { fetch } from 'undici'; +import { backOff } from 'exponential-backoff'; +import { getTestnetTag } from './deployBundledRoute'; +import { ContractInsert } from '../../../../db/insertInterfaces'; +import { GatewayError } from '../../../errorHandlerMiddleware'; + +const ARWEAVE_QUERY = `query Transaction($ids: [ID!]) { transactions(ids: $ids) { edges { node { - address + id + owner { address } + tags { + name + value + } + signature } } } }`; -const BUNDLR_NODES = ['node1', 'node2'] as const; -type BundlrNodeType = typeof BUNDLR_NODES[number]; +const REGISTER_PROVIDER = ['node1', 'node2', 'arweave'] as const; +type RegisterProviderType = typeof REGISTER_PROVIDER[number]; export async function registerContractRoute(ctx: Router.RouterContext) { - const {logger, dbSource} = ctx; + const { logger, dbSource } = ctx; let initStateRaw = ''; let contractTx = null; let txId = ''; + const registerProvider = ctx.request.body.registerProvider || ctx.request.body.bundlrNode; - const bundlrNode = ctx.request.body.bundlrNode; - if (!bundlrNode || !isBundlrNodeType(bundlrNode)) { + if (!registerProvider || !isRegisterProvider(registerProvider)) { throw new GatewayError( - `Invalid Bundlr Node. Should be equal to one of the following values: ${BUNDLR_NODES.map((n) => n).join( + `Invalid register type. Should be equal to one of the following values: ${REGISTER_PROVIDER.map((n) => n).join( ', ' - )}, found: ${bundlrNode}.`, 400 + )}, found: ${registerProvider}.`, + 400 ); } txId = ctx.request.body.id; - const txMetadata = ((await getBundlrGqlMetadata(txId, bundlrNode)) as any).transactions.edges[0].node; + const txMetadata: { tags: Tag[]; address: string; signature: string } = + registerProvider == 'arweave' + ? await getArweaveGqlMetadata(txId) + : await getBundlrNetworkMetadata(txId, registerProvider); - const {contractTagsIncluded, tags, signature} = await verifyContractTags(txId, bundlrNode); + const tags = txMetadata.tags; + const contractTagsIncluded = await verifyContractTags(tags); if (!contractTagsIncluded) { throw new GatewayError('Bundlr transaction is not valid contract transaction.', 400); } - logger.debug('Bundlr transaction marked as valid contract transaction.'); + logger.debug('Contract transaction marked as valid contract transaction.'); let encodedTags: Tag[] = []; @@ -79,7 +90,7 @@ export async function registerContractRoute(ctx: Router.RouterContext) { id: txId, owner: ownerAddress, data: null, - signature, + signature: txMetadata.signature, target: '', tags: encodedTags, }; @@ -95,9 +106,11 @@ export async function registerContractRoute(ctx: Router.RouterContext) { block_height: blockHeight, block_timestamp: blockTimestamp, content_type: contentType, - contract_tx: {tags: contractTx.tags}, + contract_tx: { tags: contractTx.tags }, bundler_contract_tx_id: txId, - bundler_contract_node: `https://${bundlrNode}.bundlr.network`, + bundler_contract_node: ['node1', 'node2'].includes(registerProvider) + ? `https://${registerProvider}.bundlr.network` + : `https://arweave.net`, testnet, deployment_type: WarpDeployment.External, manifest, @@ -135,7 +148,25 @@ export async function registerContractRoute(ctx: Router.RouterContext) { } } -export async function verifyContractTags(id: string, bundlrNode: string) { +export async function verifyContractTags(tags: Tag[]) { + const tagsIncluded = [ + { name: 'App-Name', value: 'SmartWeaveContract' }, + { name: 'App-Version', value: '0.3.0' }, + ]; + + const nameTagsIncluded = ['Contract-Src', 'Init-State', 'Content-Type']; + + const contractTagsIncluded = + tagsIncluded.every((ti) => tags.some((t: Tag) => t.name == ti.name && t.value == ti.value)) && + nameTagsIncluded.every((nti) => tags.some((t: Tag) => t.name == nti)); + + return contractTagsIncluded; +} + +export async function getBundlrNetworkMetadata( + id: string, + bundlrNode: string +): Promise<{ tags: Tag[]; address: string; signature: string }> { let response: any; const request = async () => { return fetch(`https://${bundlrNode}.bundlr.network/tx/${id}`).then((res) => { @@ -143,54 +174,54 @@ export async function verifyContractTags(id: string, bundlrNode: string) { }); }; try { - response = await backOff(request, { + response = (await backOff(request, { delayFirstAttempt: false, maxDelay: 2000, numOfAttempts: 5, - }); + })) as any; } catch (error: any) { throw new Error(`Unable to retrieve Bundlr network tags response. ${error.status}.`); } - const tags = response.tags; - const signature = response.signature; - const tagsIncluded = [ - {name: 'App-Name', value: 'SmartWeaveContract'}, - {name: 'App-Version', value: '0.3.0'}, - ]; - const nameTagsIncluded = ['Contract-Src', 'Init-State', 'Content-Type']; - - const contractTagsIncluded = - tagsIncluded.every((ti) => tags.some((t: Tag) => t.name == ti.name && t.value == ti.value)) && - nameTagsIncluded.every((nti) => tags.some((t: Tag) => t.name == nti)); - - return {contractTagsIncluded, tags, signature}; + return { tags: response.tags, address: response.address, signature: response.signature }; } -export async function getBundlrGqlMetadata(id: string, bundlrNode: string) { +export async function getArweaveGqlMetadata(id: string): Promise<{ tags: Tag[]; address: string; signature: string }> { const data = JSON.stringify({ - query: BUNDLR_QUERY, - variables: {ids: [id]}, + query: ARWEAVE_QUERY, + variables: { ids: [id] }, }); - const response = await fetch(`https://${bundlrNode}.bundlr.network/graphql`, { - method: 'POST', - body: data, - headers: { - 'Accept-Encoding': 'gzip, deflate, br', - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - }) - .then((res) => { + let response: any; + + const request = async () => { + return fetch(`https://arweave.net/graphql`, { + method: 'POST', + body: data, + headers: { + 'Accept-Encoding': 'gzip, deflate, br', + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }).then((res) => { return res.ok ? res.json() : Promise.reject(res); - }) - .catch((error) => { - throw new Error(`Unable to retrieve Bundlr gql response. ${error.status}.`); }); - return (response as any).data; + }; + try { + response = ( + (await backOff(request, { + delayFirstAttempt: false, + maxDelay: 2000, + numOfAttempts: 5, + })) as any + ).data.transactions.edges[0].node; + } catch (error: any) { + throw new Error(`Unable to retrieve Arweave gql response. ${error.status}.`); + } + + return { tags: response.tags, address: response.owner.address, signature: response.signature }; } -export function isBundlrNodeType(value: string): value is BundlrNodeType { - return BUNDLR_NODES.includes(value as BundlrNodeType); +export function isRegisterProvider(value: string): value is RegisterProviderType { + return REGISTER_PROVIDER.includes(value as RegisterProviderType); } From 17b43b29fb0099b600ccbe65e5aaa7b0b8a9900f Mon Sep 17 00:00:00 2001 From: Asia Date: Tue, 14 Nov 2023 14:03:00 +0100 Subject: [PATCH 60/95] feat: add srcTxId to contracts-by-tag route --- src/gateway/router/routes/contracts/contractsByTag.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/router/routes/contracts/contractsByTag.ts b/src/gateway/router/routes/contracts/contractsByTag.ts index 2b3befd7..e54c5938 100644 --- a/src/gateway/router/routes/contracts/contractsByTag.ts +++ b/src/gateway/router/routes/contracts/contractsByTag.ts @@ -34,6 +34,7 @@ export async function contractsByTag(ctx: Router.RouterContext) { const result: any = await dbSource.raw( ` SELECT c.contract_id AS contract, + c.src_tx_id AS srcTxId, c.owner AS owner, c.testnet AS testnet, c.contract_tx AS contractTx, From 71a445c52a8a169f3862debb9d23d5c4ac11fbc5 Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 16 Nov 2023 13:47:07 +0100 Subject: [PATCH 61/95] contracts-by-source route - remove interactions count (#186) --- .../contracts/contractsBySourceRoute.ts | 26 +++++++------------ .../2023_11_16_block_height_src_tx_id_idx.sql | 1 + 2 files changed, 11 insertions(+), 16 deletions(-) create mode 100644 updates/2023_11_16_block_height_src_tx_id_idx.sql diff --git a/src/gateway/router/routes/contracts/contractsBySourceRoute.ts b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts index 913be9c9..a9fa1395 100644 --- a/src/gateway/router/routes/contracts/contractsBySourceRoute.ts +++ b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts @@ -1,14 +1,14 @@ import Router from '@koa/router'; -import {Benchmark} from 'warp-contracts'; -import {isTxIdValid} from '../../../../utils'; -import {GatewayError} from "../../../errorHandlerMiddleware"; +import { Benchmark } from 'warp-contracts'; +import { isTxIdValid } from '../../../../utils'; +import { GatewayError } from '../../../errorHandlerMiddleware'; const MAX_INTERACTIONS_PER_PAGE = 5000; export async function contractsBySourceRoute(ctx: Router.RouterContext) { - const {logger, dbSource} = ctx; + const { logger, dbSource } = ctx; - const {id, page, limit, sort} = ctx.query; + const { id, page, limit, sort } = ctx.query; const parsedPage = page ? parseInt(page as string) : 1; @@ -29,8 +29,8 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - ` + const result: any = await dbSource.raw( + ` with c as (select contract_id, owner, bundler_contract_tx_id, block_height, block_timestamp from contracts where src_tx_id = ? @@ -41,26 +41,20 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { src as (select count(*) AS total from contracts where src_tx_id = ? - and type <> 'error'), + and type <> 'error') - interactions as (select c.contract_id, count(*) as interactions - from c - join interactions on interactions.contract_id = c.contract_id - group by c.contract_id) SELECT c.contract_id AS "contractId", c.owner AS "owner", c.bundler_contract_tx_id AS "bundlerTxId", c.block_height AS "blockHeight", c.block_timestamp AS "blockTimestamp", - coalesce(i.interactions, 0) AS "interactions", coalesce(src.total, 0) AS "total" from c - LEFT JOIN interactions i ON c.contract_id = i.contract_id LEFT JOIN src ON TRUE ${sort == 'desc' || sort == 'asc' ? `ORDER BY c.block_height ${sort.toUpperCase()}, c.contract_id` : ''}; `, - bindings - ); + bindings + ); const total = result?.rows?.length > 0 ? result?.rows[0].total : 0; diff --git a/updates/2023_11_16_block_height_src_tx_id_idx.sql b/updates/2023_11_16_block_height_src_tx_id_idx.sql new file mode 100644 index 00000000..22548a22 --- /dev/null +++ b/updates/2023_11_16_block_height_src_tx_id_idx.sql @@ -0,0 +1 @@ +CREATE INDEX contracts_block_height_src_tx_id_index ON contracts (block_height, src_tx_id); From f989f286aa5d3774a69bab091a26d036308eeb3b Mon Sep 17 00:00:00 2001 From: Asia Date: Thu, 16 Nov 2023 15:32:55 +0100 Subject: [PATCH 62/95] sql: contract_tx_tags_idx --- updates/2023_11_16_contract_tx_tags_idx.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 updates/2023_11_16_contract_tx_tags_idx.sql diff --git a/updates/2023_11_16_contract_tx_tags_idx.sql b/updates/2023_11_16_contract_tx_tags_idx.sql new file mode 100644 index 00000000..e3824280 --- /dev/null +++ b/updates/2023_11_16_contract_tx_tags_idx.sql @@ -0,0 +1,3 @@ +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_contract_tx_tags_gin + ON contracts USING gin ((contract_tx->'tags') jsonb_path_ops) +WHERE type != 'error'; From 5a6d978096fa56992379db2af0e80668677fb717 Mon Sep 17 00:00:00 2001 From: Asia Date: Fri, 17 Nov 2023 14:44:08 +0100 Subject: [PATCH 63/95] contracts-by-tags - accept tags list (#188) --- src/gateway/router/gatewayRouter.ts | 4 +- .../{contractsByTag.ts => contractsByTags.ts} | 57 ++++++++++++++++--- src/utils.ts | 8 +++ 3 files changed, 58 insertions(+), 11 deletions(-) rename src/gateway/router/routes/contracts/{contractsByTag.ts => contractsByTags.ts} (61%) diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 842dafb1..35fef8f4 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -29,7 +29,7 @@ import { deployContractRoute_v2 } from './routes/deploy/deployContractRoute_v2'; import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; import { gcpAliveRoute } from './routes/gcpAliveRoute'; -import { contractsByTag } from './routes/contracts/contractsByTag'; +import { contractsByTags } from './routes/contracts/contractsByTags'; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -60,7 +60,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/creator', creatorRoute); router.get('/gcp/alive', gcpAliveRoute); router.get('/sequencer/address', sequencerAddressRoute) - router.get('/contracts-by-tag', contractsByTag); + router.get('/contracts-by-tags', contractsByTags); // post if (!replica) { diff --git a/src/gateway/router/routes/contracts/contractsByTag.ts b/src/gateway/router/routes/contracts/contractsByTags.ts similarity index 61% rename from src/gateway/router/routes/contracts/contractsByTag.ts rename to src/gateway/router/routes/contracts/contractsByTags.ts index e54c5938..f8ff6780 100644 --- a/src/gateway/router/routes/contracts/contractsByTag.ts +++ b/src/gateway/router/routes/contracts/contractsByTags.ts @@ -1,29 +1,68 @@ import Router from '@koa/router'; import { Benchmark } from 'warp-contracts'; import { GatewayError } from '../../../errorHandlerMiddleware'; +import { encodeTag } from '../../../../utils'; const MAX_CONTRACTS_PER_PAGE = 100; +const MAX_TAGS_LIST_LENGTH = 5; +const MAX_TAGS_VALUES_LIST_LENGTH = 5; -export async function contractsByTag(ctx: Router.RouterContext) { +export async function contractsByTags(ctx: Router.RouterContext) { const { logger, dbSource, arweave } = ctx; - const { tag, owner, page, limit, testnet, srcId } = ctx.query; + const { tags, owner, page, limit, testnet, srcId } = ctx.query; - if (!tag) { + if (!tags) { throw new GatewayError('Tag parameter must be provided.', 422); } - logger.debug('Contracts by tag route', { tag, owner, page, limit }); + logger.debug('Contracts by tag route', { tags, owner, page, limit }); const parsedPage = page ? parseInt(page as string) : 1; const parsedLimit = limit ? Math.min(parseInt(limit as string), MAX_CONTRACTS_PER_PAGE) : MAX_CONTRACTS_PER_PAGE; const offset = parsedPage ? (parsedPage - 1) * parsedLimit : 0; const bindings: any[] = []; - const tagEncoded = JSON.stringify({ - name: arweave.utils.stringToB64Url(JSON.parse(tag as string).name), - value: arweave.utils.stringToB64Url(JSON.parse(tag as string).value), - }); + + const parsedTag = JSON.parse(tags as string); + + if (parsedTag.length > 5) { + throw new GatewayError( + `Maximum ${MAX_TAGS_LIST_LENGTH} tags are excepted in the query. Current tags list length: ${parsedTag.length}`, + 422 + ); + } + + if (parsedTag.length < 1) { + throw new GatewayError( + `At least one tag in the list is required. Current tags list length: ${parsedTag.length}`, + 422 + ); + } + + let tagsQuery = ``; + + for (let i = 0; i < parsedTag.length; i++) { + if (parsedTag[i].values.length > 1) { + if (parsedTag[i].values.length > 5) { + throw new GatewayError( + `Tag with name ${parsedTag[i].name} has too many values assigned. Maximum values list length: ${MAX_TAGS_VALUES_LIST_LENGTH}.`, + 422 + ); + } + let partialTagQuery = ` AND (`; + partialTagQuery += + parsedTag[i].values + .map( + (v: string) => `c.contract_tx->'tags' @> '[${JSON.stringify(encodeTag(parsedTag[i].name, v, arweave))}]'` + ) + .join(' OR ') + ')'; + tagsQuery += partialTagQuery; + } else { + const tagEncoded = JSON.stringify(encodeTag(parsedTag[i].name, parsedTag[i].values[0], arweave)); + tagsQuery += ` AND c.contract_tx->'tags' @> '[${tagEncoded}]'`; + } + } owner && bindings.push(owner); srcId && bindings.push(srcId); @@ -46,7 +85,7 @@ export async function contractsByTag(ctx: Router.RouterContext) { ${testnet ? ' AND c.testnet IS NOT NULL' : ''} ${owner ? ` AND c.owner = ?` : ''} ${srcId ? ` AND c.src_tx_id = ?` : ''} - AND c.contract_tx->'tags' @> '[${tagEncoded}]' + ${tagsQuery} GROUP BY c.contract_id, c.owner ORDER BY c.sync_timestamp DESC ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; diff --git a/src/utils.ts b/src/utils.ts index 44764d4a..fa0c3a85 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { Tag } from 'arweave/node/lib/transaction'; import { Tags } from 'warp-contracts'; +import Arweave from 'arweave'; export function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -39,3 +40,10 @@ export function getTagByName(tags: Tags, name: string) { const tagContentType = tags.find((tag: any) => tag.name == name)?.value; return tagContentType; } + +export function encodeTag(name: string, value: string, arweave: Arweave) { + return { + name: arweave.utils.stringToB64Url(name), + value: arweave.utils.stringToB64Url(value), + }; +} From f63cf3b13d8eadb42aea291654c2f7f490ac017d Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 16 Nov 2023 23:28:23 +0100 Subject: [PATCH 64/95] chore: refactor arweave network info cache --- .../{LastTxSyncer.ts => PgAdvisoryLocks.ts} | 62 ++- src/gateway/init.ts | 36 +- src/gateway/router/routes/arweaveInfoRoute.ts | 8 +- .../routes/deploy/deployBundledRoute.ts | 7 +- .../routes/deploy/deployContractRoute.ts | 7 +- .../routes/deploy/deployContractRoute_v2.ts | 9 +- .../routes/deploy/registerContractRoute.ts | 7 +- src/gateway/router/routes/gcpAliveRoute.ts | 2 +- src/gateway/router/routes/sequencerRoute.ts | 9 +- .../router/routes/sequencerRoute_v2.ts | 7 +- src/gateway/runGatewayTasks.ts | 58 --- src/gateway/tasks/contractsMetadata.ts | 281 -------------- src/gateway/tasks/evolvedContractSources.ts | 156 -------- src/gateway/tasks/loadPeers.ts | 66 ---- src/gateway/tasks/networkInfoCache.ts | 132 +++++-- src/gateway/tasks/syncTransactions.ts | 354 ------------------ .../tasks/verifyCorruptedTransactions.ts | 58 --- src/gateway/tasks/verifyInteractions.ts | 288 -------------- src/utils.ts | 21 +- tools/nakurwiaj.js | 24 +- tools/nakurwiaj_kontrakt.js | 47 +++ 21 files changed, 260 insertions(+), 1379 deletions(-) rename src/gateway/{LastTxSyncer.ts => PgAdvisoryLocks.ts} (53%) delete mode 100644 src/gateway/runGatewayTasks.ts delete mode 100644 src/gateway/tasks/contractsMetadata.ts delete mode 100644 src/gateway/tasks/evolvedContractSources.ts delete mode 100644 src/gateway/tasks/loadPeers.ts delete mode 100644 src/gateway/tasks/syncTransactions.ts delete mode 100644 src/gateway/tasks/verifyCorruptedTransactions.ts delete mode 100644 src/gateway/tasks/verifyInteractions.ts create mode 100644 tools/nakurwiaj_kontrakt.js diff --git a/src/gateway/LastTxSyncer.ts b/src/gateway/PgAdvisoryLocks.ts similarity index 53% rename from src/gateway/LastTxSyncer.ts rename to src/gateway/PgAdvisoryLocks.ts index a14d6528..65391e40 100644 --- a/src/gateway/LastTxSyncer.ts +++ b/src/gateway/PgAdvisoryLocks.ts @@ -2,24 +2,68 @@ import { Knex } from "knex"; import { Benchmark, LoggerFactory } from "warp-contracts"; import { createHash } from "crypto"; -export type AcquireMutexResult = { +export type SortKeyMutexResult = { lastSortKey: string | null, blockHeight: number, blockHash: string, blockTimestamp: number } -export class LastTxSync { +export class PgAdvisoryLocks { - private readonly logger = LoggerFactory.INST.create(LastTxSync.name); + private readonly logger = LoggerFactory.INST.create(PgAdvisoryLocks.name); - async acquireMutex(contractTxId: string, trx: Knex.Transaction): Promise { - const lockId = this.strToKey(contractTxId); + async acquireSortKeyMutex(contractTxId: string, trx: Knex.Transaction): Promise { + const lockFor = contractTxId; + const lockId = this.strToKey(lockFor); this.logger.debug("Locking for", { - contractTxId, + lockFor, lockId }); + await this.doAcquireLock(lockId, trx); + return await this.loadLastSortKey(contractTxId, trx); + } + + async acquireArweaveHeightMutex(trx: Knex.Transaction): Promise<{ blockHeight: number, blockHash: string, blockTimestamp: string } | null | undefined> { + const lockFor = "ArweaveHeight"; + const lockId = this.strToKey(lockFor); + this.logger.debug("Locking for", { + lockFor, + lockId + }); + const hasLock = await this.tryLock(lockId, trx); + if (hasLock) { + const result = await trx.raw( + ` + SELECT finished_block_height AS "blockHeight", + finished_block_hash AS "blockHash", + finished_block_timestamp as "blockTimestamp", + additional_data as "additionalData" + FROM sync_state + WHERE name = 'Arweave';` + ); + if (result?.rows?.length !== 1) { + return null; + } + + return result.rows[0]; + } else { + return undefined; + } + } + private async tryLock(lockId: number[], trx: Knex.Transaction): Promise { + const benchmark = Benchmark.measure(); + const result = await trx.raw( + `SELECT pg_try_advisory_xact_lock(?, ?);`, [lockId[0], lockId[1]] + ); + const hasLock = result.rows[0]["pg_try_advisory_xact_lock"]; + this.logger.debug("Acquiring pg_try_advisory_xact_lock", benchmark.elapsed(), hasLock); + + return hasLock; + } + + private async doAcquireLock(lockId: number[], trx: Knex.Transaction): Promise { // https://stackoverflow.com/a/20963803 await trx.raw(`SET LOCAL lock_timeout = '5s';`); const benchmark = Benchmark.measure(); @@ -27,11 +71,9 @@ export class LastTxSync { SELECT pg_advisory_xact_lock(?, ?); `, [lockId[0], lockId[1]]); this.logger.debug("Acquiring pg_advisory_xact_lock", benchmark.elapsed()); - - return this.loadLastSortKey(contractTxId, trx); } - private async loadLastSortKey(contractTxId: string, trx: Knex.Transaction): Promise { + private async loadLastSortKey(contractTxId: string, trx: Knex.Transaction): Promise { const benchmark = Benchmark.measure(); this.logger.debug("Loading lastSortKey", benchmark.elapsed()); @@ -46,7 +88,7 @@ export class LastTxSync { UNION ALL SELECT 'finished_block' as type, null, finished_block_height, finished_block_hash, finished_block_timestamp FROM sync_state - WHERE name = 'Interactions'`, [contractTxId] + WHERE name = 'Interactions';`, [contractTxId] ); if (result?.rows.length !== 2) { throw new Error("Acquire mutex result should have exactly 2 rows in result"); diff --git a/src/gateway/init.ts b/src/gateway/init.ts index ad694825..bc6bb313 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -5,17 +5,15 @@ import Application from 'koa'; import bodyParser from 'koa-bodyparser'; import { ArweaveWrapper, LexicographicalInteractionsSorter, LoggerFactory, WarpLogger } from 'warp-contracts'; import Arweave from 'arweave'; -import { runGatewayTasks } from './runGatewayTasks'; import gatewayRouter from './router/gatewayRouter'; import * as fs from 'fs'; -import cluster from 'cluster'; import welcomeRouter from './router/welcomeRouter'; import Bundlr from '@bundlr-network/client'; import { initBundlr } from '../bundlr/connect'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { runNetworkInfoCacheTask } from './tasks/networkInfoCache'; import Redis from 'ioredis'; -import { LastTxSync } from './LastTxSyncer'; +import { PgAdvisoryLocks } from './PgAdvisoryLocks'; import { initPubSub } from 'warp-contracts-pubsub'; // @ts-ignore import { EvmSignatureVerificationServerPlugin } from 'warp-signature/server'; @@ -50,7 +48,7 @@ export interface GatewayContext { sorter: LexicographicalInteractionsSorter; publisher: Redis; publisher_v2: Redis; - lastTxSync: LastTxSync; + pgAdvisoryLocks: PgAdvisoryLocks; env: EnvType; appSync?: string; signatureVerification: EvmSignatureVerificationServerPlugin; @@ -79,9 +77,9 @@ export interface GatewayContext { const appSync = process.env.APP_SYNC; LoggerFactory.INST.logLevel('info'); - LoggerFactory.INST.logLevel('info', 'gateway'); + LoggerFactory.INST.logLevel('debug', 'gateway'); LoggerFactory.INST.logLevel('debug', 'sequencer'); - LoggerFactory.INST.logLevel('debug', 'LastTxSync'); + LoggerFactory.INST.logLevel('debug', 'PgAdvisoryLocks'); LoggerFactory.INST.logLevel('debug', 'access'); const logger = LoggerFactory.INST.create('gateway'); const sLogger = LoggerFactory.INST.create('sequencer'); @@ -151,7 +149,7 @@ export interface GatewayContext { }) ); app.context.sorter = new LexicographicalInteractionsSorter(arweave); - app.context.lastTxSync = new LastTxSync(); + app.context.pgAdvisoryLocks = new PgAdvisoryLocks(); app.context.appSync = appSync; app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); app.context.replica = replica; @@ -236,29 +234,7 @@ export interface GatewayContext { app.context.publisher_v2 = publisher2; } } - - if (!fs.existsSync('gateway.lock')) { - await runNetworkInfoCacheTask(app.context); - - if (!noSync) { - try { - logger.info(`Creating lock file for ${cluster.worker?.id}`); - // note: if another process in cluster have already created the file - writing here - // will fail thanks to wx flags. https://stackoverflow.com/a/31777314 - fs.writeFileSync('gateway.lock', '' + cluster.worker?.id, { flag: 'wx' }); - removeLock = true; - - // note: only one worker in cluster runs the gateway tasks - // all workers in cluster run the http server - if (env !== 'local') { - logger.info(`Starting gateway tasks for ${cluster.worker?.id}`); - await runGatewayTasks(app.context); - } - } catch (e: any) { - logger.error('Error from gateway', e); - } - } - } + await runNetworkInfoCacheTask(app.context); } })(); diff --git a/src/gateway/router/routes/arweaveInfoRoute.ts b/src/gateway/router/routes/arweaveInfoRoute.ts index 6171995d..aae38118 100644 --- a/src/gateway/router/routes/arweaveInfoRoute.ts +++ b/src/gateway/router/routes/arweaveInfoRoute.ts @@ -3,9 +3,9 @@ import { getCachedNetworkData } from '../../tasks/networkInfoCache'; import {GatewayError} from "../../errorHandlerMiddleware"; export async function arweaveInfoRoute(ctx: Router.RouterContext) { - const { logger } = ctx; + const { logger, dbSource } = ctx; - const result = getCachedNetworkData().cachedNetworkInfo; + const result = (await getCachedNetworkData(dbSource)).cachedNetworkInfo; if (result == null) { throw new GatewayError('Network info not yet available.') } else { @@ -17,9 +17,9 @@ export async function arweaveInfoRoute(ctx: Router.RouterContext) { } export async function arweaveBlockRoute(ctx: Router.RouterContext) { - const { logger } = ctx; + const { logger, dbSource } = ctx; - const result = getCachedNetworkData().cachedBlockInfo; + const result = (await getCachedNetworkData(dbSource)).cachedBlockInfo; if (result == null) { throw new GatewayError('Block info not yet available.'); } else { diff --git a/src/gateway/router/routes/deploy/deployBundledRoute.ts b/src/gateway/router/routes/deploy/deployBundledRoute.ts index ad12f4bf..6f551ffb 100644 --- a/src/gateway/router/routes/deploy/deployBundledRoute.ts +++ b/src/gateway/router/routes/deploy/deployBundledRoute.ts @@ -1,5 +1,4 @@ import Router from '@koa/router'; -import { evalType } from '../../../tasks/contractsMetadata'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { DataItem } from 'arbundles'; import rawBody from 'raw-body'; @@ -9,6 +8,7 @@ import { evalManifest, WarpDeployment } from './deployContractRoute'; import { ContractInsert } from '../../../../db/insertInterfaces'; import { GatewayError } from '../../../errorHandlerMiddleware'; import { getDataItemWithoutData } from './deployContractRoute_v2'; +import { evalType } from "../../../../utils"; export async function deployBundledRoute(ctx: Router.RouterContext) { const { logger, dbSource, arweave, bundlr } = ctx; @@ -46,8 +46,9 @@ export async function deployBundledRoute(ctx: Router.RouterContext) { const contentType = dataItem.tags.find((t) => t.name == 'Content-Type')!.value; const testnet = getTestnetTag(dataItem.tags); const manifest = evalManifest(dataItem.tags); - const blockHeight = getCachedNetworkData().cachedNetworkInfo.height; - const blockTimestamp = getCachedNetworkData().cachedBlockInfo.timestamp; + const cachedNetworkData = await getCachedNetworkData(dbSource); + const blockHeight = cachedNetworkData.cachedNetworkInfo.height; + const blockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; const syncTimestamp = Date.now(); const insert: ContractInsert = { diff --git a/src/gateway/router/routes/deploy/deployContractRoute.ts b/src/gateway/router/routes/deploy/deployContractRoute.ts index 66bf994b..2bbb0787 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute.ts @@ -2,13 +2,13 @@ import Router, { RouterContext } from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; import Arweave from 'arweave'; import { GQLTagInterface, SmartWeaveTags } from 'warp-contracts'; -import { evalType } from '../../../tasks/contractsMetadata'; import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { uploadToBundlr } from '../sequencerRoute'; import { publishContract, sendNotification } from '../../../publisher'; import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; import {GatewayError} from "../../../errorHandlerMiddleware"; +import { evalType } from "../../../../utils"; /* - warp-wrapped - contract or source is wrapped in another transaction - it is posted by Warp Gateway to the Bundlr network and sent @@ -103,8 +103,9 @@ export async function deployContractRoute(ctx: Router.RouterContext) { const initState = JSON.parse(initStateRaw); const type = evalType(initState); const manifest = evalManifest(contractTags); - const blockHeight = getCachedNetworkData().cachedNetworkInfo.height; - const blockTimestamp = getCachedNetworkData().cachedBlockInfo.timestamp; + const cachedNetworkData = await getCachedNetworkData(dbSource); + const blockHeight = cachedNetworkData.cachedNetworkInfo.height; + const blockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; const syncTimestamp = Date.now(); const insert: ContractInsert = { diff --git a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts index 15c1e5cf..68e2f921 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -1,8 +1,7 @@ import Router from '@koa/router'; -import { evalType } from '../../../tasks/contractsMetadata'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { Bundle, DataItem } from 'arbundles'; -import { ContractSource, sleep, SmartWeaveTags } from 'warp-contracts'; +import { SmartWeaveTags } from 'warp-contracts'; import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { publishContract, sendNotification } from '../../../publisher'; import { evalManifest, WarpDeployment } from './deployContractRoute'; @@ -12,6 +11,7 @@ import { utils } from 'ethers'; import { longTo32ByteArray } from 'arbundles'; import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; import { GatewayError } from '../../../errorHandlerMiddleware'; +import { evalType } from "../../../../utils"; export async function deployContractRoute_v2(ctx: Router.RouterContext) { const { logger, arweave, dbSource } = ctx; @@ -99,8 +99,9 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { const contentType = contractDataItem.tags.find((t) => t.name == 'Content-Type')!.value; const testnet = getTestnetTag(contractDataItem.tags); const manifest = evalManifest(contractDataItem.tags); - const blockHeight = getCachedNetworkData().cachedNetworkInfo.height; - const blockTimestamp = getCachedNetworkData().cachedBlockInfo.timestamp; + const cachedNetworkData = await getCachedNetworkData(dbSource); + const blockHeight = cachedNetworkData.cachedNetworkInfo.height; + const blockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; const syncTimestamp = Date.now(); const insert: ContractInsert = { diff --git a/src/gateway/router/routes/deploy/registerContractRoute.ts b/src/gateway/router/routes/deploy/registerContractRoute.ts index 46815fd1..211825aa 100644 --- a/src/gateway/router/routes/deploy/registerContractRoute.ts +++ b/src/gateway/router/routes/deploy/registerContractRoute.ts @@ -1,5 +1,4 @@ import Router from '@koa/router'; -import { evalType } from '../../../tasks/contractsMetadata'; import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { publishContract, sendNotification } from '../../../publisher'; import { evalManifest, WarpDeployment } from './deployContractRoute'; @@ -10,6 +9,7 @@ import { backOff } from 'exponential-backoff'; import { getTestnetTag } from './deployBundledRoute'; import { ContractInsert } from '../../../../db/insertInterfaces'; import { GatewayError } from '../../../errorHandlerMiddleware'; +import { evalType } from "../../../../utils"; const ARWEAVE_QUERY = `query Transaction($ids: [ID!]) { transactions(ids: $ids) { @@ -82,8 +82,9 @@ export async function registerContractRoute(ctx: Router.RouterContext) { const contentType = tags.find((t: Tag) => t.name == 'Content-Type')!.value; const testnet = getTestnetTag(tags); const manifest = evalManifest(tags); - const blockHeight = getCachedNetworkData().cachedNetworkInfo.height; - const blockTimestamp = getCachedNetworkData().cachedBlockInfo.timestamp; + const cachedNetworkData = await getCachedNetworkData(dbSource); + const blockHeight = cachedNetworkData.cachedNetworkInfo.height; + const blockTimestamp = cachedNetworkData.cachedBlockInfo.timestamp; const syncTimestamp = Date.now(); contractTx = { diff --git a/src/gateway/router/routes/gcpAliveRoute.ts b/src/gateway/router/routes/gcpAliveRoute.ts index 9dcfee11..3c76b626 100644 --- a/src/gateway/router/routes/gcpAliveRoute.ts +++ b/src/gateway/router/routes/gcpAliveRoute.ts @@ -2,7 +2,7 @@ import Router from '@koa/router'; import { getCachedNetworkData } from '../../tasks/networkInfoCache'; export async function gcpAliveRoute(ctx: Router.RouterContext) { - const arBlockHeight = ctx.replica ? null : getCachedNetworkData().cachedBlockInfo.height; + const arBlockHeight = (await getCachedNetworkData(ctx.dbSource)).cachedBlockInfo.height; ctx.body = { gateway: 'ok', diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 456fff7d..79c0670e 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -1,11 +1,10 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; -import { parseFunctionName } from '../../tasks/syncTransactions'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, timeout, WarpLogger } from 'warp-contracts'; import Bundlr from '@bundlr-network/client'; -import { isTxIdValid } from '../../../utils'; +import { isTxIdValid, parseFunctionName } from "../../../utils"; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; @@ -52,7 +51,7 @@ export async function sequencerRoute(ctx: Router.RouterContext) { } async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { - const { sLogger, arweave, jwk, vrf, lastTxSync, signatureVerification } = ctx; + const { sLogger, arweave, jwk, vrf, pgAdvisoryLocks, signatureVerification } = ctx; const initialBenchmark = Benchmark.measure(); @@ -75,7 +74,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti testnetVersion, } = await prepareTags(sLogger, transaction, originalOwner, arweave); - const acquireMutexResult = await lastTxSync.acquireMutex(contractTag, trx); + const acquireMutexResult = await pgAdvisoryLocks.acquireSortKeyMutex(contractTag, trx); sLogger.debug('Acquire mutex result', acquireMutexResult); // note: lastSortKey can be null if that's a very first interaction with a contract. if ( @@ -83,7 +82,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti acquireMutexResult.blockHeight == null || acquireMutexResult.blockTimestamp == null ) { - throw new Error(`Missing data in acquireMutexResult: ${JSON.stringify(acquireMutexResult)}`); + throw new Error(`Missing data in acquireSortKeyMutex: ${JSON.stringify(acquireMutexResult)}`); } const millis = Date.now(); diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 87422a1a..103a37cb 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -1,7 +1,6 @@ import Router from '@koa/router'; -import { parseFunctionName } from '../../tasks/syncTransactions'; import { Benchmark, SmartWeaveTags, VrfData, timeout } from 'warp-contracts'; -import { isTxIdValid } from '../../../utils'; +import { isTxIdValid, parseFunctionName } from "../../../utils"; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; @@ -36,7 +35,7 @@ export async function sequencerRoute_v2(ctx: Router.RouterContext) { } async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transaction): Promise { - const { sLogger, arweave, jwk, vrf, lastTxSync } = ctx; + const { sLogger, arweave, jwk, vrf, pgAdvisoryLocks } = ctx; const initialBenchmark = Benchmark.measure(); @@ -62,7 +61,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; - const acquireMutexResult = await lastTxSync.acquireMutex(contractTag, trx); + const acquireMutexResult = await pgAdvisoryLocks.acquireSortKeyMutex(contractTag, trx); sLogger.debug('Acquire mutex result', acquireMutexResult); // note: lastSortKey can be null if that's a very first interaction with a contract. if ( diff --git a/src/gateway/runGatewayTasks.ts b/src/gateway/runGatewayTasks.ts deleted file mode 100644 index cc8f9cfd..00000000 --- a/src/gateway/runGatewayTasks.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { runLoadPeersTask } from './tasks/loadPeers'; -import { runVerifyInteractionsTask } from './tasks/verifyInteractions'; -import { runVerifyCorruptedTransactionsTask } from './tasks/verifyCorruptedTransactions'; -import { - runSyncLastHourTransactionsTask, - runSyncRecentTransactionsTask, -} from './tasks/syncTransactions'; -import { GatewayContext } from './init'; -import { runContractsMetadataTask, runLoadContractsFromGqlTask } from './tasks/contractsMetadata'; -import { runEvolvedContractSourcesTask } from './tasks/evolvedContractSources'; - -/** - * Gateway consists of four separate tasks, each runs with its own interval: - * - * 1. peers tasks - checks the status (ie. "/info" endpoint) of all the peers returned by the arweave.net/peers. - * If the given peer does not respond within MAX_ARWEAVE_PEER_INFO_TIMEOUT_MS - it is blacklisted 'till next round. - * "Blocks", "height" from the response to "/info" and response times are being stored in the db - so that it would - * be possible to rank peers be their "completeness" (ie. how many blocks do they store) and response times. - * - * 2. blocks sync task - listens for new blocks and loads the SmartWeave interaction transactions. - * - * 3. interactions verifier task - tries its best to confirm that transactions are not corrupted. - * It takes the first PARALLEL_REQUESTS non confirmed transactions with block height lower then - * current - MIN_CONFIRMATIONS. - * For each set of the selected 'interactionsToCheck' transactions it makes - * TX_CONFIRMATION_SUCCESSFUL_ROUNDS query rounds (to randomly selected at each round peers). - * Only if we get TX_CONFIRMATION_SUCCESSFUL_ROUNDS within TX_CONFIRMATION_MAX_ROUNDS - * AND response for the given transaction is the same for all the successful rounds - * - the "confirmation" info for given transaction is updated in the the database. - * - * 4. corrupted transactions verifier task - additional task that double-verifies interactions marked as corrupted. If during the - * re-check the interaction won't be recognized as corrupted - it is returned to the "not processed" pool. - * - * 5. contracts metadata task - loads the contracts metadata (src, init state, owner, etc.) - * - * note: as there are very little fully synced nodes and they often timeout/504 - this process is a real pain... - */ -export async function runGatewayTasks(context: GatewayContext) { - //await runBundlrCheck(context); - - await runLoadPeersTask(context); - - await runContractsMetadataTask(context); - - await runSyncRecentTransactionsTask(context); - - await runSyncLastHourTransactionsTask(context); - - await runVerifyInteractionsTask(context); - - await runVerifyCorruptedTransactionsTask(context); - - await runLoadContractsFromGqlTask(context); - - await runEvolvedContractSourcesTask(context); - - // await runSyncLastSixHoursTransactionsTask(context); -} diff --git a/src/gateway/tasks/contractsMetadata.ts b/src/gateway/tasks/contractsMetadata.ts deleted file mode 100644 index a0c87e6b..00000000 --- a/src/gateway/tasks/contractsMetadata.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { TaskRunner } from './TaskRunner'; -import { GatewayContext } from '../init'; -import { ContractDefinition, ContractDefinitionLoader, GQLEdgeInterface, SmartWeaveTags } from 'warp-contracts'; -import { loadPages, MAX_GQL_REQUEST, ReqVariables } from '../../gql'; -import { FIRST_SW_TX_BLOCK_HEIGHT, MAX_BATCH_INSERT, testnetVersion } from './syncTransactions'; -import { getCachedNetworkData } from './networkInfoCache'; -import { publishContract, sendNotification } from '../publisher'; -import { DatabaseSource } from '../../db/databaseSource'; -import { ContractInsert } from '../../db/insertInterfaces'; -import fs from 'fs'; - -const CONTRACTS_METADATA_INTERVAL_MS = 10000; - -const CONTRACTS_QUERY = `query Transactions($tags: [TagFilter!]!, $blockFilter: BlockFilter!, $first: Int!, $after: String) { - transactions(tags: $tags, block: $blockFilter, first: $first, sort: HEIGHT_ASC, after: $after) { - pageInfo { - hasNextPage - } - edges { - node { - id - tags { - name - value - } - block { - height - timestamp - } - parent { id } - bundledIn { id } - } - cursor - } - } - }`; - -export async function runContractsMetadataTask(context: GatewayContext) { - await TaskRunner.from('[contracts metadata]', loadContractsMetadata, context).runSyncEvery( - CONTRACTS_METADATA_INTERVAL_MS - ); -} - -export async function runLoadContractsFromGqlTask(context: GatewayContext) { - await TaskRunner.from('[contracts from gql]', loadContractsFromGql, context).runSyncEvery( - CONTRACTS_METADATA_INTERVAL_MS - ); -} - -async function loadContractsFromGql(context: GatewayContext) { - const { logger, dbSource } = context; - - let lastProcessedBlockHeight; - if (fs.existsSync('contracts-sync-l1.json')) { - const data = JSON.parse(fs.readFileSync('contracts-sync-l1.json', 'utf-8')); - lastProcessedBlockHeight = data?.lastProcessedBlockHeight; - } else { - let result: any; - try { - result = await dbSource.selectLastContract(); - lastProcessedBlockHeight = result?.block_height; - } catch (e: any) { - logger.error('Error while checking new blocks', e.message); - return; - } - } - - const currentNetworkHeight = getCachedNetworkData().cachedNetworkInfo.height; - lastProcessedBlockHeight = lastProcessedBlockHeight || FIRST_SW_TX_BLOCK_HEIGHT; - const from = lastProcessedBlockHeight - 1; - const to = currentNetworkHeight - from <= 100 ? currentNetworkHeight : from + 100; - logger.info('Loading L1 contracts', { - from, - to, - }); - - let transactions: GQLEdgeInterface[]; - try { - transactions = await load(context, from, to); - } catch (e: any) { - logger.error('Error while loading contracts', e.message); - return; - } - - if (transactions.length === 0) { - logger.info('No new contracts'); - fs.writeFileSync('contracts-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: to }), 'utf-8'); - return; - } - - logger.info(`Found ${transactions.length} contracts`); - - let contractsInserts: Partial[] = []; - - const contractsInsertsIds = new Set(); - for (let transaction of transactions) { - const contractId = transaction.node.id; - if (!contractsInsertsIds.has(contractId)) { - const contentType = getContentTypeTag(transaction); - const testnet = testnetVersion(transaction); - if (!contentType) { - logger.warn(`Cannot determine contract content type for contract ${contractId}`); - } - contractsInserts.push({ - contract_id: transaction.node.id, - block_height: transaction.node.block.height, - block_timestamp: transaction.node.block.timestamp, - content_type: contentType || 'unknown', - deployment_type: 'arweave', - testnet, - sync_timestamp: Date.now(), - }); - contractsInsertsIds.add(contractId); - - if (contractsInserts.length === MAX_BATCH_INSERT) { - try { - logger.info(`Batch insert ${MAX_BATCH_INSERT} interactions.`); - await insertContracts(dbSource, contractsInserts); - contractsInserts = []; - } catch (e) { - logger.error(e); - return; - } - } - } - } - - logger.info(`Saving last`, contractsInserts.length); - - if (contractsInserts.length > 0) { - try { - await insertContracts(dbSource, contractsInserts); - } catch (e) { - logger.error(e); - return; - } finally { - fs.writeFileSync('contracts-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: to }), 'utf-8'); - } - } else { - fs.writeFileSync('contracts-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: to }), 'utf-8'); - } - - logger.info(`Inserted ${contractsInserts.length} contracts`); -} - -async function insertContracts(dbSource: DatabaseSource, contractsInserts: any[]) { - await dbSource.insertContractsMetadata(contractsInserts); -} - -function getContentTypeTag(interactionTransaction: GQLEdgeInterface): string | undefined { - return interactionTransaction.node.tags.find((tag) => tag.name === SmartWeaveTags.CONTENT_TYPE)?.value; -} - -async function load(context: GatewayContext, from: number, to: number): Promise { - const variables: ReqVariables = { - bundledIn: null, - tags: [ - { - name: SmartWeaveTags.APP_NAME, - values: ['SmartWeaveContract'], - }, - ], - blockFilter: { - min: from, - max: to, - }, - first: MAX_GQL_REQUEST, - }; - - const { logger, arweaveWrapperGqlGoldsky } = context; - return await loadPages({ logger, arweaveWrapper: arweaveWrapperGqlGoldsky }, CONTRACTS_QUERY, variables); -} - -async function loadContractsMetadata(context: GatewayContext) { - const { arweave, logger, dbSource, arweaveWrapper } = context; - const definitionLoader = new ContractDefinitionLoader(arweave, 'mainnet'); - - const result: { - contract: string; - blockHeight: number; - blockTimestamp: number; - syncTimestamp: number; - testnet: string; - }[] = ( - await dbSource.raw( - ` - SELECT contract_id AS contract, - block_height AS blockHeight, - block_timestamp AS blockTimestamp, - sync_timestamp AS syncTimestamp, - testnet AS testnet - FROM contracts - WHERE contract_id != '' - AND contract_id NOT ILIKE '()%' - AND src_tx_id IS NULL - AND type IS NULL; - ` - ) - ).rows; - - const missing = result?.length || 0; - logger.info(`Loading ${missing} contract definitions.`); - - if (missing == 0) { - return; - } - - for (const row of result) { - logger.debug(`Loading ${row.contract} definition.`); - try { - const contractId = row.contract.trim(); - const definition: ContractDefinition = await definitionLoader.load(contractId); - const type = evalType(definition.initState); - const srcTxOwner = await arweave.wallets.ownerToAddress(definition.srcTx.owner); - - let update: any = { - src_tx_id: definition.srcTxId, - init_state: definition.initState, - owner: definition.owner, - type, - pst_ticker: type == 'pst' ? definition.initState?.ticker : null, - pst_name: type == 'pst' ? definition.initState?.name : null, - contract_tx: { tags: definition.contractTx.tags }, - }; - - let contracts_src_insert: any = { - src_tx_id: definition.srcTxId, - owner: srcTxOwner, - src_content_type: definition.contractType == 'js' ? 'application/javascript' : 'application/wasm', - src_tx: definition.srcTx, - deployment_type: 'arweave', - }; - - if (definition.contractType == 'js') { - contracts_src_insert = { - ...contracts_src_insert, - src: definition.src, - }; - } else { - const rawTxData = await arweaveWrapper.txData(definition.srcTxId); - contracts_src_insert = { - ...contracts_src_insert, - src_binary: rawTxData, - src_wasm_lang: definition.srcWasmLang, - }; - } - - logger.debug(`Inserting ${row.contract} metadata into db`); - await dbSource.updateContractMetadata(definition.txId, update); - - await dbSource.updateContractSrc(contracts_src_insert); - - // TODO: add tags to ContractDefinition type in the SDK - sendNotification(context, definition.txId, { initState: definition.initState, tags: [], srcTxId: definition.srcTxId }); - publishContract( - context, - contractId, - definition.owner, - type, - row.blockHeight, - row.blockTimestamp, - 'arweave', - row.syncTimestamp, - row.testnet - ); - - logger.debug(`${row.contract} metadata inserted into db`); - } catch (e) { - logger.error(`Error while loading contract ${row.contract} definition`, e); - await dbSource.updateContractError(row); - } - } -} - -export function evalType(initState: any): string { - if (initState.ticker && initState.balances) { - return 'pst'; - } - - return 'other'; -} diff --git a/src/gateway/tasks/evolvedContractSources.ts b/src/gateway/tasks/evolvedContractSources.ts deleted file mode 100644 index e4bc984a..00000000 --- a/src/gateway/tasks/evolvedContractSources.ts +++ /dev/null @@ -1,156 +0,0 @@ -import Arweave from 'arweave'; -import Transaction from 'arweave/node/lib/transaction'; -import { ContractDefinitionLoader, ContractSource, SmartWeaveTags, TagsParser, WasmSrc } from 'warp-contracts'; -import { ContractSourceInsert } from '../../db/insertInterfaces'; -import { GatewayContext } from '../init'; -import { TaskRunner } from './TaskRunner'; - -const CONTRACTS_SOURCE_INTERVAL_MS = 10000; - -export async function runEvolvedContractSourcesTask(context: GatewayContext) { - await TaskRunner.from('[evolved contract sources]', loadEvolvedContractSources, context).runSyncEvery( - CONTRACTS_SOURCE_INTERVAL_MS - ); -} - -async function loadEvolvedContractSources(context: GatewayContext) { - const { logger, dbSource, arweave } = context; - const definitionLoader = new ContractDefinitionLoader(arweave, 'mainnet'); - const tagsParser = new TagsParser(); - - const result: { evolve: string }[] = ( - await dbSource.raw( - ` - SELECT evolve - FROM interactions - WHERE evolve NOT IN (SELECT src_tx_id from contracts_src) - AND evolve IS NOT NULL; - ` - ) - ).rows; - - const missing = result?.length || 0; - logger.info(`Loading ${missing} evolved contract sources.`); - - if (missing == 0) { - return; - } - - for (const row of result) { - logger.debug(`Loading evolved contract source: ${row.evolve}.`); - const srcTxId = row.evolve; - - let src, srcWasmLang, contractType, srcTx, srcBinary; - - let loaded = false; - - try { - ({ src, srcWasmLang, contractType, srcTx } = await definitionLoader.loadContractSource(srcTxId)); - await insertSourceToDb(srcTxId, contractType, srcTx, src, srcBinary, srcWasmLang, context, tagsParser); - loaded = true; - } catch (e) { - logger.debug(`Cannot load evolved contract source transaction. ${srcTxId}.`, e); - } - - if (!loaded) { - try { - ({ src, srcBinary, srcTx, srcWasmLang, contractType, srcBinary } = await loadSourceDataItem( - srcTxId, - tagsParser - )); - await insertSourceToDb(srcTxId, contractType, srcTx, src, srcBinary, srcWasmLang, context, tagsParser); - loaded = true; - } catch (e) { - logger.debug(`Cannot load evolved contract source data item ${srcTxId}.`, e); - } - } - - if (!loaded) { - try { - let contracts_src_insert: any = { - src_tx_id: srcTxId, - src: 'error', - }; - - await dbSource.insertContractSource(contracts_src_insert); - logger.debug(`${row.evolve} evolved contract source inserted into db as errored.`); - } catch (e) { - logger.error(`Error while loading evolved contract source ${srcTxId}`, e); - } - } - } - logger.info(`Loaded ${missing} evolved contract sources.`); -} - -export async function loadSourceDataItem(srcTxId: string, tagsParser: TagsParser) { - const jsonSrc = await fetch(`https://arweave.net/${srcTxId}`).then((res) => { - return res.json(); - }); - const srcTx = new Transaction(jsonSrc); - let src, srcBinary, srcWasmLang, srcContentType; - - srcContentType = tagsParser.getTag(srcTx, SmartWeaveTags.CONTENT_TYPE).value; - if (srcContentType == 'application/javascript') { - src = Arweave.utils.bufferToString(srcTx.data); - } else { - const bufData = Buffer.from(srcTx.data); - const wasmSrc = new WasmSrc(bufData); - srcBinary = await wasmSrc.sourceCode(); - srcWasmLang = tagsParser.getTag(srcTx, SmartWeaveTags.WASM_LANG).value; - } - - return { - src, - srcBinary, - srcTx, - srcWasmLang, - contractType: srcContentType == 'application/javascript' ? 'js' : 'wasm', - }; -} - -export async function insertSourceToDb( - srcTxId: string, - contractType: string, - srcTx: Transaction, - src: any, - srcBinary: any, - srcWasmLang: string | null, - ctx: GatewayContext, - tagsParser: TagsParser -): Promise { - const tx = new Transaction(srcTx); - - const decodedTags = tagsParser.decodeTags(tx); - const signatureType = decodedTags.find((t) => t.name == SmartWeaveTags.SIGNATURE_TYPE); - const testnet = decodedTags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET); - - let contracts_src_insert: any = { - src_tx_id: srcTxId, - src_content_type: contractType == 'js' ? 'application/javascript' : 'application/wasm', - src_tx: srcTx, - owner: - signatureType && signatureType.name == 'ethereum' - ? srcTx.owner - : await ctx.arweave.wallets.ownerToAddress(srcTx.owner), - testnet: testnet ? testnet : null, - }; - - if (contractType == 'js') { - contracts_src_insert = { - ...contracts_src_insert, - src: src, - }; - } else { - contracts_src_insert = { - ...contracts_src_insert, - src_binary: srcBinary ? srcBinary : await ctx.arweaveWrapper.txData(srcTxId), - src_wasm_lang: srcWasmLang, - }; - } - - ctx.logger.debug(`Inserting ${srcTxId} evolved contract source into db`); - - await ctx.dbSource.insertContractSource(contracts_src_insert); - - ctx.logger.debug(`${srcTxId} evolved contract source inserted into db`); -} diff --git a/src/gateway/tasks/loadPeers.ts b/src/gateway/tasks/loadPeers.ts deleted file mode 100644 index 657ee295..00000000 --- a/src/gateway/tasks/loadPeers.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { PeerList } from 'arweave/node/network'; -import { Benchmark } from 'warp-contracts'; -import axios from 'axios'; -import { TaskRunner } from './TaskRunner'; -import { GatewayContext } from '../init'; -import { PeerInsert } from '../../db/insertInterfaces'; - -const MAX_ARWEAVE_PEER_INFO_TIMEOUT_MS = 3000; -const PEERS_CHECK_INTERVAL_MS = 1000 * 60 * 60; - -export async function runLoadPeersTask(context: GatewayContext) { - const { logger, dbSource } = context; - const currentPeers: { peer: string }[] = await dbSource.raw(`SELECT peer from peers;`); - if (currentPeers.length < 200) { - logger.info('Pre-loading peers...'); - await loadPeers(context); - } - - await TaskRunner.from('[load peers]', loadPeers, context).runAsyncEvery(PEERS_CHECK_INTERVAL_MS, false); -} - -async function loadPeers(context: GatewayContext) { - const { logger, arweave, dbSource } = context; - - logger.info('Updating peers...'); - - const newPeers: PeerList = await arweave.network.getPeers(); - const currentPeers: { peer: string }[] = await dbSource.raw(`SELECT peer FROM peers;`); - - const peersToRemove: string[] = []; - currentPeers.forEach((currentPeer) => { - if (!newPeers.find((peer) => currentPeer.peer === peer)) { - peersToRemove.push(currentPeer.peer); - } - }); - - logger.debug('Removing no longer available peers', peersToRemove); - - const removedCount = await dbSource.deletePeers(peersToRemove); - - logger.debug(`Removed ${removedCount} elements.`); - - for (const peer of newPeers) { - logger.debug(`Checking Arweave peer ${peer} [${newPeers.indexOf(peer) + 1} / ${newPeers.length}]`); - try { - const benchmark = Benchmark.measure(); - const result = await axios.get(`http://${peer}/info`, { - timeout: MAX_ARWEAVE_PEER_INFO_TIMEOUT_MS, - }); - const elapsed = benchmark.elapsed(true); - - const peerInsert: PeerInsert = { - peer: peer, - blocks: result.data.blocks, - height: result.data.height, - response_time: elapsed, - blacklisted: false, - }; - - await dbSource.insertPeer(peerInsert); - } catch (e: any) { - logger.error(`Error from ${peer}`, e.message); - await dbSource.insertPeerEror(peer); - } - } -} diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index 8674e4a7..96ef3899 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -1,65 +1,119 @@ -import { NetworkInfoInterface } from 'arweave/node/network'; -import { BlockData } from 'arweave/node/blocks'; -import { GatewayContext } from '../init'; -import { TaskRunner } from './TaskRunner'; -import { BLOCKS_INTERVAL_MS } from './syncTransactions'; -import fs from 'fs'; +import { NetworkInfoInterface } from "arweave/node/network"; +import { BlockData } from "arweave/node/blocks"; +import { GatewayContext } from "../init"; +import { TaskRunner } from "./TaskRunner"; +import { Knex } from "knex"; +import Arweave from "arweave"; +import { DatabaseSource } from "../../db/databaseSource"; +import { sleep } from "../../utils"; export type NetworkCacheType = { cachedNetworkInfo: NetworkInfoInterface; cachedBlockInfo: BlockData; }; -let cache: NetworkCacheType; export async function runNetworkInfoCacheTask(context: GatewayContext) { - const { arweave, logger, arweaveWrapper } = context; + const { arweave, logger, arweaveWrapper, pgAdvisoryLocks, dbSource } = context; async function updateNetworkInfo() { + // @ts-ignore + const trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; + try { - const newNetworkInfo = await arweaveWrapper.info(); - if (cache?.cachedNetworkInfo && newNetworkInfo && newNetworkInfo.height <= cache.cachedNetworkInfo.height) { - logger.debug('New network height lower or equal than current, skipping.', { - currentHeight: cache?.cachedNetworkInfo.height, - newHeight: newNetworkInfo.height, - }); + const currentArweaveBlock = await pgAdvisoryLocks.acquireArweaveHeightMutex(trx); + if (currentArweaveBlock === undefined) { + logger.debug("Network info already locked, skipping"); return; } - const cachedNetworkInfo = newNetworkInfo; - const cachedBlockInfo = await arweave.blocks.get(cachedNetworkInfo.current as string); - - (cachedBlockInfo as any).poa = {}; - (cachedBlockInfo as any).txs = []; - - cache = { - cachedNetworkInfo, - cachedBlockInfo, - }; + const newNetworkInfo = await arweaveWrapper.info(); + if (currentArweaveBlock === null) { + logger.debug("Current arweave block null, inserting"); + const additionalData = await prepareCacheData(arweave, newNetworkInfo); + await trx.raw(` + INSERT INTO sync_state(name, finished_block_height, finished_block_hash, additional_data) + VALUES ('Arweave', + :block_height, + :block_hash, + :additional_data); + `, { + block_height: newNetworkInfo.height, + block_hash: newNetworkInfo.current, + additional_data: additionalData + }); + } else { + if (newNetworkInfo && newNetworkInfo.height <= currentArweaveBlock.blockHeight) { + logger.debug("New network height lower or equal than current, skipping.", { + currentHeight: currentArweaveBlock.blockHeight, + newHeight: newNetworkInfo.height + }); + await sleep(1000); + await trx.commit(); + return; + } - fs.writeFileSync('network-cache.json', JSON.stringify(cache), 'utf-8'); - logger.debug('New network height', cache.cachedNetworkInfo.height); + const additionalData = await prepareCacheData(arweave, newNetworkInfo); + await trx.raw(` + UPDATE sync_state + SET finished_block_height=:block_height, + finished_block_hash=:block_hash, + additional_data=:additional_data + WHERE name = 'Arweave'; + `, { + block_height: newNetworkInfo.height, + block_hash: newNetworkInfo.current, + additional_data: additionalData + }); + } + // hold lock for a while, so that other process that are trying to check the height + // at about the same time - will get blocked + await sleep(1000); + await trx.commit(); + logger.debug("New network height", newNetworkInfo.height); } catch (e) { - logger.error('Error while loading network info', e); + if (trx != null) { + await trx.rollback(); + } + logger.error("Error while loading network info", e); } } await TaskRunner.from( - '[Arweave network info]', + "[Arweave network info]", async () => { - logger.debug('Loading network info'); - if (cache?.cachedNetworkInfo == null || cache?.cachedBlockInfo == null) { - while (cache?.cachedNetworkInfo == null || cache?.cachedBlockInfo == null) { - await updateNetworkInfo(); - } - } else { - await updateNetworkInfo(); - } + logger.debug("Loading network info"); + await updateNetworkInfo(); }, context - ).runSyncEvery(BLOCKS_INTERVAL_MS, true); + ).runSyncEvery(30 * 1000, true); } -export function getCachedNetworkData(): NetworkCacheType { - return JSON.parse(fs.readFileSync('network-cache.json', 'utf-8')); +export async function getCachedNetworkData(dbSource: DatabaseSource): Promise { + // @ts-ignore + const result = await dbSource.primaryDb.raw(` + SELECT additional_data + FROM sync_state + WHERE name = 'Arweave'; + `); + + if (result?.rows?.length !== 1) { + throw new Error("Cached Arweave network data not available."); + } + + return result.rows[0].additional_data; +} + +async function prepareCacheData(arweave: Arweave, newNetworkInfo: NetworkInfoInterface): Promise { + const cachedNetworkInfo = newNetworkInfo; + const cachedBlockInfo = await arweave.blocks.get(cachedNetworkInfo.current as string); + + (cachedBlockInfo as any).poa = {}; + (cachedBlockInfo as any).txs = []; + (cachedBlockInfo as any).poa2 = {}; + + return { + cachedNetworkInfo, + cachedBlockInfo + }; } diff --git a/src/gateway/tasks/syncTransactions.ts b/src/gateway/tasks/syncTransactions.ts deleted file mode 100644 index 993efa6a..00000000 --- a/src/gateway/tasks/syncTransactions.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { GQLEdgeInterface, WarpLogger, SmartWeaveTags, TagsParser } from 'warp-contracts'; -import { TaskRunner } from './TaskRunner'; -import { GatewayContext } from '../init'; -import { loadPages, MAX_GQL_REQUEST, ReqVariables } from '../../gql'; -import { isTxIdValid } from '../../utils'; -import { publishInteraction, sendNotification } from '../publisher'; -import { DatabaseSource } from '../../db/databaseSource'; -import { InteractionInsert } from '../../db/insertInterfaces'; -import fs from 'fs'; -import { getCachedNetworkData } from './networkInfoCache'; - -const INTERACTIONS_QUERY = `query Transactions($tags: [TagFilter!]!, $blockFilter: BlockFilter!, $first: Int!, $after: String) { - transactions(tags: $tags, block: $blockFilter, first: $first, sort: HEIGHT_ASC, after: $after) { - pageInfo { - hasNextPage - } - edges { - node { - id - owner { address } - recipient - tags { - name - value - } - block { - height - id - timestamp - } - fee { winston } - quantity { winston } - parent { id } - bundledIn { id } - } - cursor - } - } - }`; - -const tagsParser = new TagsParser(); - -// in theory avg. block time on Arweave is 120s (?) -// in fact, it varies from ~20s to minutes... -export const BLOCKS_INTERVAL_MS = 30 * 1000; -export const FIRST_SW_TX_BLOCK_HEIGHT = 472810; -const LOAD_PAST_BLOCKS = 50; // smartweave interaction are currently somewhat rare... -// that was a limit for sqlite, but let's leave it for now... -export const MAX_BATCH_INSERT = 500; - -const AVG_BLOCK_TIME_SECONDS = 60; -export const AVG_BLOCKS_PER_HOUR = (60 * 60) / AVG_BLOCK_TIME_SECONDS + 10; -const AVG_BLOCKS_PER_DAY = (60 * 60 * 24) / AVG_BLOCK_TIME_SECONDS + 60; - -const HOUR_INTERVAL_MS = 60 * 60 * 1000; -const DAY_INTERVAL_MS = HOUR_INTERVAL_MS * 24; - -export async function runSyncRecentTransactionsTask(context: GatewayContext) { - await TaskRunner.from('[sync latest transactions]', syncLastTransactions, context).runSyncEvery(BLOCKS_INTERVAL_MS); -} - -export async function runSyncLastHourTransactionsTask(context: GatewayContext) { - await TaskRunner.from('[sync last hour transactions]', syncLastHourTransactions, context).runSyncEvery( - HOUR_INTERVAL_MS - ); -} - -export async function runSyncLastSixHoursTransactionsTask(context: GatewayContext) { - await TaskRunner.from('[sync last 6 hours transactions]', syncLastSixHoursTransactionsTask, context).runSyncEvery( - DAY_INTERVAL_MS - ); -} - -function syncLastTransactions(context: GatewayContext) { - return syncTransactions(context, 5, true); -} - -function syncLastHourTransactions(context: GatewayContext) { - return syncTransactions(context, AVG_BLOCKS_PER_HOUR); -} - -function syncLastSixHoursTransactionsTask(context: GatewayContext) { - return syncTransactions(context, AVG_BLOCKS_PER_HOUR * 6); -} - -async function syncTransactions(context: GatewayContext, pastBlocksAmount: number, publish = false) { - const { dbSource, logger, sorter } = context; - - logger.info('Syncing L1 interactions'); - - let lastProcessedBlockHeight; - if (fs.existsSync('interactions-sync-l1.json')) { - const data = JSON.parse(fs.readFileSync('interactions-sync-l1.json', 'utf-8')); - lastProcessedBlockHeight = data?.lastProcessedBlockHeight; - } else { - let result: any; - try { - result = await dbSource.selectLastProcessedArweaveInteraction(); - lastProcessedBlockHeight = result?.block_height; - } catch (e: any) { - logger.error('Error while loading last loaded arweave interaction', e.message); - return; - } - } - - const currentNetworkHeight = getCachedNetworkData().cachedNetworkInfo.height; - // note: the first SW interaction was registered at 472810 block height - lastProcessedBlockHeight = lastProcessedBlockHeight || FIRST_SW_TX_BLOCK_HEIGHT; - - logger.debug('Network info', { - currentNetworkHeight, - lastProcessedBlockHeight, - }); - - const heightFrom = lastProcessedBlockHeight - pastBlocksAmount; - let heightTo = currentNetworkHeight; - - // note: only main task should have this protection. The 'last hour' and 'last 6 hours' tasks - // will obviously try to resync more blocks. - if (publish) { - if (heightTo > heightFrom + 20) { - heightTo = heightFrom + 20; - } - } - - logger.info('Loading interactions for blocks', { - heightFrom, - heightTo, - }); - - // 2. load interactions - let gqlInteractions: GQLEdgeInterface[]; - try { - gqlInteractions = await load( - context, - // Checking LOAD_PAST_BLOCKS blocks back in the past, as - // arweave.net GQL endpoint (very) rarely returns no transactions for the latest block - // - even if there are some transactions in this block... - // We want to be sure that we won't miss any transaction because of a random Arweave gateway quirk... - // There's no risk of duplicates, as transaction's id is the primary key of the table - // - and "ON CONFLICT" clause protects from unique constraint errors. - heightFrom, - heightTo - ); - } catch (e: any) { - logger.error('Error while loading interactions', e.message); - return; - } - - if (gqlInteractions.length === 0) { - logger.info('Now new interactions'); - // note: publish is set to true only for the main syncing task - and also only this task should - // store info about last processed height - if (publish) { - fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: heightTo }), 'utf-8'); - } - return; - } - - logger.info(`Found ${gqlInteractions.length} interactions`); - - // 3. map interactions into inserts to "interactions" table - let interactionsInserts: InteractionInsert[] = []; - const interactionsInsertsIds = new Set(); - - const contracts = new Map(); - - for (let i = 0; i < gqlInteractions.length; i++) { - const interaction = gqlInteractions[i]; - const blockId = interaction.node.block.id; - - const contractId = tagsParser.getContractTag(interaction.node); - const input = tagsParser.getInputTag(interaction.node, contractId)?.value; - const parsedInput = safeParseInput(input, logger); - - const functionName = parsedInput ? parsedInput.function : '[Error during parsing function name]'; - - let evolve: string | null; - - evolve = - functionName == 'evolve' && parsedInput?.value && isTxIdValid(parsedInput?.value) ? parsedInput?.value : null; - - const internalWrites = tagsParser.getInteractWritesContracts(interaction.node); - - if (contractId === undefined || input === undefined) { - logger.error('Contract or input tag not found for interaction', interaction); - continue; - } - - const sortKey = await sorter.createSortKey(blockId, interaction.node.id, interaction.node.block.height); - const testnet = testnetVersion(interaction); - const syncTimestamp = Date.now(); - // now this one is really fucked-up - if the interaction contains the same tag X-times, - // the default GQL endpoint will return this interaction X-times... - // this is causing "SQLITE_CONSTRAINT: UNIQUE constraint failed: interactions.id" - // - and using "ON CONFLICT" does not work here - as it works only for - // the rows currently stored in db - not the ones that we're trying to batch insert. - if (interactionsInsertsIds.has(interaction.node.id)) { - logger.warn('Interaction already added', interaction.node.id); - } else { - interactionsInsertsIds.add(interaction.node.id); - interactionsInserts.push({ - interaction_id: interaction.node.id, - interaction: JSON.stringify(interaction.node), - block_height: interaction.node.block.height, - block_timestamp: interaction.node.block.timestamp, - block_id: blockId, - contract_id: contractId, - function: functionName, - input: input, - confirmation_status: 'not_processed', - interact_write: internalWrites, - sort_key: sortKey, - evolve: evolve, - testnet, - owner: interaction.node.owner.address, - sync_timestamp: syncTimestamp, - }); - } - if (interactionsInserts.length === MAX_BATCH_INSERT) { - try { - logger.info(`Batch insert ${MAX_BATCH_INSERT} interactions.`); - const interactionsInsertResult: any = await insertInteractions(dbSource, interactionsInserts); - - logger.debug(`Inserted ${interactionsInsertResult.rowCount}`); - interactionsInserts = []; - } catch (e) { - // note: not sure how to behave in this case... - // if we continue the processing, there's a risk that some blocks/interactions will be skipped. - logger.error(e); - return; - } - } - contracts.set(interaction.node.id, { - contractId, - interaction: interaction.node, - blockHeight: interaction.node.block.height, - sortKey, - source: 'arweave', - syncTimestamp, - functionName, - testnet, - }); - } - - // 4. inserting the rest interactions into DB - logger.info(`Saving last`, interactionsInserts.length); - - if (interactionsInserts.length > 0) { - try { - const interactionsInsertResult: any = await insertInteractions(dbSource, interactionsInserts); - logger.debug(`Inserted ${interactionsInsertResult.rowCount}`); - } catch (e) { - logger.error(e); - return; - } finally { - if (publish) { - fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: heightTo }), 'utf-8'); - } - } - } else { - if (publish) { - fs.writeFileSync('interactions-sync-l1.json', JSON.stringify({ lastProcessedBlockHeight: heightTo }), 'utf-8'); - } - } - - if (publish) { - for (let [key, value] of contracts) { - sendNotification(context, value.contractId, undefined, value.interaction); - publishInteraction( - context, - value.contractId, - value.interaction, - value.sortKey, - null, - value.functionName, - value.source, - value.syncTimestamp, - value.testnet - ); - } - } -} - -async function insertInteractions(dbSource: DatabaseSource, interactionsInserts: InteractionInsert[]) { - // why using onConflict.merge()? - // because it happened once that GQL endpoint returned the exact same transactions - // twice - for different block heights (827991 and then 827993) - // For the record, these transactions were: - // INmaBb6pk0MATLrs3mCw5bjeRCbR2e-j-v4swpWHPTg - // QIbp0CwxNUwA8xQSS36Au2Lj1QEgnO8n-shQ2d3AWps - // UJhsjQLhSr1mL4C-t3XvotAhYGIN-P7EkkxNyRRIQ-w - // UZ1XnYr4waM7Zm77TZduZ4Tx8uS8y9PeyX6kKEPQh10 - // cZHBNtzkSF_MtkZCz1RD8_D9lVjOOYAuEUk2xbdm7LA - // lwGTY3yEBfxTgPFO4DZMouHWVaXLJu7SxP-hpDb_S2M - // ouv9X3-ceGPhb2ALVaLq2qzj_ZDgbSmjGj9wz5k5qRo - // qT-ihh8K3J7Lek4774-GmFoAhU4pemWZPXv66B09xCI - // qUk-UuPAOaOkoqMP_btCJLYP-c-8kHRKjg_nefQVLgQ - - // note: the same issue occurred recently for tx IoGSPjQ--LY2KRgCBioaX0GTlohCq64IYSFolayuEPg - // it was first returned for block 868561, and then moved to 868562 - probably due to fork - return await dbSource.insertInteractionsSync(interactionsInserts); -} - -// TODO: verify internalWrites -async function load(context: GatewayContext, from: number, to: number): Promise { - const mainTransactionsVariables: ReqVariables = { - bundledIn: null, - tags: [ - { - name: SmartWeaveTags.APP_NAME, - values: ['SmartWeaveAction'], - }, - ], - blockFilter: { - min: from, - max: to, - }, - first: MAX_GQL_REQUEST, - }; - - const { logger, arweaveWrapperGqlGoldsky } = context; - return await loadPages( - { logger, arweaveWrapper: arweaveWrapperGqlGoldsky }, - INTERACTIONS_QUERY, - mainTransactionsVariables - ); -} - -export function testnetVersion(tx: GQLEdgeInterface): string | null { - return tx.node.tags.find((tag) => tag.name === 'Warp-Testnet')?.value || null; -} - -export function parseFunctionName(input: string, logger: WarpLogger) { - try { - return JSON.parse(input).function; - } catch (e) { - logger.error('Could not parse function name', { - input: input, - }); - return '[Error during parsing function name]'; - } -} - -export function safeParseInput(input: string, logger: WarpLogger) { - try { - return JSON.parse(input); - } catch (e) { - logger.error('Could not parse input', { - input, - }); - return null; - } -} diff --git a/src/gateway/tasks/verifyCorruptedTransactions.ts b/src/gateway/tasks/verifyCorruptedTransactions.ts deleted file mode 100644 index d3760831..00000000 --- a/src/gateway/tasks/verifyCorruptedTransactions.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { TaskRunner } from './TaskRunner'; -import { MIN_CONFIRMATIONS } from './verifyInteractions'; -import { GatewayContext } from '../init'; - -const CORRUPTED_CHECK_INTERVAL_MS = 1000 * 60 * 60; - -export async function runVerifyCorruptedTransactionsTask(context: GatewayContext) { - await TaskRunner.from('[corrupted transactions check]', verifyCorruptedTransactions, context).runAsyncEvery( - CORRUPTED_CHECK_INTERVAL_MS, - false - ); -} - -async function verifyCorruptedTransactions(context: GatewayContext) { - const { arweave, logger, dbSource } = context; - - let corruptedTransactions: { id: string }[]; - - try { - corruptedTransactions = ( - await dbSource.raw(` - SELECT interaction_id as id - FROM interactions - WHERE confirmation_status = 'corrupted'; - `) - ).rows; - } catch (e: any) { - logger.error('Error while checking corrupted transactions', e.message); - return; - } - - logger.debug(`Rechecking ${corruptedTransactions.length} corrupted transactions`); - - for (const corrupted of corruptedTransactions) { - try { - const result = await arweave.transactions.getStatus(corrupted.id); - if ( - result.status !== 404 && - result && - result.confirmed && - result.confirmed.number_of_confirmations >= MIN_CONFIRMATIONS - ) { - logger.warn( - `Transaction ${corrupted.id} is probably not corrupted, confirmations ${result.confirmed.number_of_confirmations}` - ); - - // returning transaction to "not_processed" pool. - await dbSource.updateNotProcessedInteraction(corrupted.id); - } else { - logger.info(`Transaction ${corrupted.id} confirmed as corrupted`); - } - } catch (e) { - logger.error(`Error while verifying ${corrupted.id}`); - } - } - - logger.info('Corrupted transactions confirmation done.'); -} diff --git a/src/gateway/tasks/verifyInteractions.ts b/src/gateway/tasks/verifyInteractions.ts deleted file mode 100644 index c35ffee1..00000000 --- a/src/gateway/tasks/verifyInteractions.ts +++ /dev/null @@ -1,288 +0,0 @@ -import axios from 'axios'; -import { TaskRunner } from './TaskRunner'; -import { GatewayContext } from '../init'; - -export const MIN_CONFIRMATIONS = 10; -const PARALLEL_REQUESTS = 10; -const TX_CONFIRMATION_SUCCESSFUL_ROUNDS = 3; -const TX_CONFIRMATION_MAX_ROUNDS = 4; -const TX_CONFIRMATION_MAX_ROUND_TIMEOUT_MS = 3000; -const CONFIRMATIONS_INTERVAL_MS = 30000; - -let lastVerificationHeight = 0; - -type ConfirmationRoundResult = { - txId: string; - peer: string; - result: string; - confirmations: number; -}[]; - -export async function runVerifyInteractionsTask(context: GatewayContext) { - await TaskRunner.from('[verify interactions]', verifyInteractions, context).runSyncEvery(CONFIRMATIONS_INTERVAL_MS); -} - -async function verifyInteractions(context: GatewayContext) { - const { logger, dbSource, arweaveWrapper } = context; - - let currentNetworkHeight; - try { - currentNetworkHeight = (await arweaveWrapper.info()).height as number; - } catch (e: any) { - logger.error('Error from Arweave', e.message); - return; - } - - const safeNetworkHeight = currentNetworkHeight - MIN_CONFIRMATIONS; - logger.debug('Verify confirmations params:', { - currentNetworkHeight, - safeNetworkHeight, - lastVerificationHeight, - }); - - // note: as the "status" endpoint for arweave.net sometime returns 504 - Bad Gateway for corrupted transactions, - // we need to ask peers directly... - // https://discord.com/channels/357957786904166400/812013044892172319/917819482787958806 - // only 7 nodes are currently fully synced, duh... - let peers: { peer: string }[]; - try { - peers = ( - await dbSource.raw(` - SELECT peer - FROM peers - WHERE height > 0 - AND blacklisted = false - ORDER BY height - blocks ASC, response_time ASC - LIMIT ${PARALLEL_REQUESTS}; - `) - ).rows; - } catch (e: any) { - logger.error('Error while fetching peers', e.message); - return; - } - - if (peers.length < PARALLEL_REQUESTS) { - logger.warn('Arweave peers not loaded yet.'); - return; - } - - // note: - // 1. excluding Kyve contracts, as they moved to Moonbeam (and their contracts have the most interactions) - // 2. excluding Koi contracts (well, those with the most interactions, as there are dozens of Koi contracts) - // - as they're using their own infrastructure and probably won't be interested in using this solution. - // TODO: make this list configurable. - let interactionsToCheck: { block_height: number; interaction_id: string }[]; - try { - interactionsToCheck = ( - await dbSource.raw( - ` - SELECT block_height, interaction_id - FROM interactions - WHERE block_height < (SELECT max(block_height) FROM interactions) - ? - AND block_height > ? - AND confirmation_status = 'not_processed' - AND source = 'arweave' - AND contract_id NOT IN ( - 'LkfzZvdl_vfjRXZOPjnov18cGnnK3aDKj0qSQCgkCX8', /* kyve */ - 'l6S4oMyzw_rggjt4yt4LrnRmggHQ2CdM1hna2MK4o_c', /* kyve */ - 'B1SRLyFzWJjeA0ywW41Qu1j7ZpBLHsXSSrWLrT3ebd8', /* kyve */ - 'cETTyJQYxJLVQ6nC3VxzsZf1x2-6TW2LFkGZa91gUWc', /* koi */ - '8cq1wbjWHNiPg7GwYpoDT2m9HX99LY7tklRQWfh1L6c', /* kyve */ - 'qzVAzvhwr1JFTPE8lIU9ZG_fuihOmBr7ewZFcT3lIUc', /* koi */ - 'OFD4GqQcqp-Y_Iqh8DN_0s3a_68oMvvnekeOEu_a45I', /* kyve */ - 'CdPAQNONoR83Shj3CbI_9seC-LqgI1oLaRJhSwP90-o', /* koi */ - 'dNXaqE_eATp2SRvyFjydcIPHbsXAe9UT-Fktcqs7MDk' /* kyve */ - ) - ORDER BY block_height ASC - LIMIT ?;`, - [MIN_CONFIRMATIONS, lastVerificationHeight, PARALLEL_REQUESTS] - ) - ).rows; - } catch (e: any) { - logger.error('Error while fetching interactions', e.message); - return; - } - - if (interactionsToCheck === undefined || interactionsToCheck.length === 0) { - logger.info('No new interactions to confirm.'); - // just in case - search for the non-confirmed interactions from the beginning in the next round - lastVerificationHeight = 0; - return; - } - - const prevVerificationHeight = lastVerificationHeight; - - lastVerificationHeight = [...interactionsToCheck].pop()?.block_height || lastVerificationHeight; - - logger.debug( - `Checking ${interactionsToCheck.length} interactions from height ${interactionsToCheck[0].block_height}.` - ); - - let statusesRounds: ConfirmationRoundResult[] = Array(TX_CONFIRMATION_SUCCESSFUL_ROUNDS); - let successfulRounds = 0; - let rounds = 0; - - // we need to make sure that each interaction in each round will be checked by a different peer. - // - that's why we keep the peers registry per interaction - const interactionsPeers = new Map(); - interactionsToCheck.forEach((i) => { - interactionsPeers.set(i.interaction_id, [...peers]); - }); - - // at some point we could probably generify the snowball and use it here to ask multiple peers. - while (successfulRounds < TX_CONFIRMATION_SUCCESSFUL_ROUNDS && rounds < TX_CONFIRMATION_MAX_ROUNDS) { - // too many rounds have already failed and there's no chance to get the minimal successful rounds... - if (successfulRounds + TX_CONFIRMATION_MAX_ROUNDS - rounds < TX_CONFIRMATION_SUCCESSFUL_ROUNDS) { - logger.warn("There's no point in trying, exiting.."); - lastVerificationHeight = prevVerificationHeight; - return; - } - - try { - const roundResult: ConfirmationRoundResult = []; - - // checking status of each of the interaction by a randomly selected peer. - // in each round each interaction will be checked by a different peer. - const statuses = await Promise.race([ - new Promise(function (resolve, reject) { - setTimeout( - () => reject('Status query timeout, better luck next time...'), - TX_CONFIRMATION_MAX_ROUND_TIMEOUT_MS - ); - }), - - Promise.allSettled( - interactionsToCheck.map((tx) => { - const interactionPeers = interactionsPeers.get(tx.interaction_id)!; - const randomPeer = interactionPeers[Math.floor(Math.random() * interactionPeers.length)]; - - // removing the selected peer for this interaction - // - so it won't be selected again in any of the next rounds. - interactionPeers.splice(peers.indexOf(randomPeer), 1); - const randomPeerUrl = `http://${randomPeer.peer}`; - - return axios.get(`${randomPeerUrl}/tx/${tx.interaction_id}/status`); - }) - ), - ]); - - // verifying responses from peers - for (let i = 0; i < statuses.length; i++) { - const statusResponse = statuses[i]; - const txId = interactionsToCheck[i].interaction_id; - if (statusResponse.status === 'rejected') { - // interaction is (probably) corrupted - if (statusResponse.reason.response?.status === 404) { - logger.warn(`Interaction ${txId} on ${statusResponse.reason.request.host} not found.`); - roundResult.push({ - txId: txId, - peer: statusResponse.reason.request.host, - result: 'corrupted', - confirmations: 0, - }); - } else { - // no proper response from peer (eg. 500) - // TODO: consider blacklisting such peer (after returning error X times?) 'till next peersCheckLoop - logger.error( - `Query for ${txId} to ${statusResponse.reason?.request?.host} rejected. ${statusResponse.reason}.` - ); - roundResult.push({ - txId: txId, - peer: statusResponse.reason?.request?.host, - result: 'error', - confirmations: 0, - }); - } - } else { - // transaction confirmed by given peer - const confirmations = parseInt(statusResponse.value.data['number_of_confirmations']); - logger.trace(`Confirmed ${txId} with ${confirmations}`); - - roundResult.push({ - txId: txId, - peer: statusResponse.value.request.host, - result: confirmations >= MIN_CONFIRMATIONS ? 'confirmed' : 'forked', - confirmations: statusResponse.value.data['number_of_confirmations'], - }); - } - } - statusesRounds[successfulRounds] = roundResult; - successfulRounds++; - } catch (e) { - logger.error(e); - } finally { - rounds++; - } - } - - if (successfulRounds != TX_CONFIRMATION_SUCCESSFUL_ROUNDS) { - logger.warn( - `Transactions verification was not successful, successful rounds ${successfulRounds}, required successful rounds ${TX_CONFIRMATION_SUCCESSFUL_ROUNDS}` - ); - lastVerificationHeight = prevVerificationHeight; - } else { - logger.info('Verifying rounds'); - - // sanity check...whether all rounds have the same amount of interactions checked. - for (let i = 0; i < statusesRounds.length; i++) { - const r = statusesRounds[i]; - if (r.length !== interactionsToCheck.length) { - logger.error(`Each round should have ${interactionsToCheck.length} results. Round ${i} has ${r.length}.`); - lastVerificationHeight = prevVerificationHeight; - return; - } - } - - // programming is just loops and if-s... - // For each interaction we're verifying whether the result returned in each round is the same. - // If it is the same for all rounds - we store the confirmation status in the db. - // It it is not the same - we're logging the difference and move to the next interaction. - for (let i = 0; i < interactionsToCheck.length; i++) { - let status = null; - let sameStatusOccurrence = 0; - const confirmingPeers = []; - const confirmations = []; - - for (let j = 0; j < TX_CONFIRMATION_SUCCESSFUL_ROUNDS; j++) { - const newStatus = statusesRounds[j][i].result; - if (status === null || newStatus === status) { - status = newStatus; - sameStatusOccurrence++; - confirmingPeers.push(statusesRounds[j][i].peer); - confirmations.push(statusesRounds[j][i].confirmations); - } else { - logger.warn('Different response from peers for', { - current_peer: statusesRounds[j][i], - // note: j - 1 is safe here, because in this branch j >= 1 - // - if the status is different, than it means we're checking at least - // second round for the given transaction - prev_peer: statusesRounds[j - 1][i], - }); - break; - } - } - - if (sameStatusOccurrence === TX_CONFIRMATION_SUCCESSFUL_ROUNDS) { - // sanity check... - if (status === null) { - logger.error('WTF? Status should not be null!'); - continue; - } - try { - logger.trace('Updating confirmation status in db'); - await dbSource.updateInteractionConfirmationStatus( - interactionsToCheck[i].interaction_id, - status, - confirmingPeers, - confirmations - ); - } catch (e) { - logger.error(e); - lastVerificationHeight = prevVerificationHeight; - } - } - } - } - - logger.info('Transactions confirmation done.'); -} diff --git a/src/utils.ts b/src/utils.ts index fa0c3a85..c3d03c93 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { Tag } from 'arweave/node/lib/transaction'; -import { Tags } from 'warp-contracts'; +import { Tags, WarpLogger } from "warp-contracts"; import Arweave from 'arweave'; export function sleep(ms: number): Promise { @@ -47,3 +47,22 @@ export function encodeTag(name: string, value: string, arweave: Arweave) { value: arweave.utils.stringToB64Url(value), }; } + +export function evalType(initState: any): string { + if (initState.ticker && initState.balances) { + return 'pst'; + } + + return 'other'; +} + +export function parseFunctionName(input: string, logger: WarpLogger) { + try { + return JSON.parse(input).function; + } catch (e) { + logger.error('Could not parse function name', { + input: input, + }); + return '[Error during parsing function name]'; + } +} diff --git a/tools/nakurwiaj.js b/tools/nakurwiaj.js index 498982dd..7bd3bd77 100644 --- a/tools/nakurwiaj.js +++ b/tools/nakurwiaj.js @@ -9,11 +9,11 @@ let errors_l2 = ``; const warp = warpContracts.WarpFactory.forMainnet({ ...warpContracts.defaultCacheOptions, dbLocation: 'warp/old', -}).useGwUrl('http://34.141.17.15:5666'); +}).useGwUrl('http://35.242.203.146:5666'); const warpNew = warpContractsNew.WarpFactory.forMainnet({ ...warpContractsNew.defaultCacheOptions, dbLocation: 'warp/new', -}).useGwUrl('http://34.141.17.15:5666'); +}).useGwUrl('http://35.242.203.146:5666'); const wallet = readJSON('./.secrets/warp-wallet-jwk.json'); const ethWallet = fs.readFileSync('./.secrets/ethereum-priv-key.txt', 'utf-8').replace(/\n/g, ''); @@ -23,35 +23,35 @@ warpContractsNew.LoggerFactory.INST.logLevel('error'); const contractB = warp .contract('YhTW-jV7ffbYciz1bcJ-SM-79cmt9MkoZYutyaghg9Y') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/', + sequencerUrl: 'http://35.242.203.146:5666/', }) .connect(wallet); const contractC = warp .contract('-tU1YKqnwgzpZIxjqUPBzRFsCfXVNZ6t1lu5pi5cV3k') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/', + sequencerUrl: 'http://35.242.203.146:5666/', }) .connect(wallet); const contractD = warpNew .contract('7AZv5bczZhJJpUfwhzjz3iGdzo2PaBi0elgoRwzwg4g') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/', + sequencerUrl: 'http://35.242.203.146:5666/', }) .connect(wallet); const contractE = warpNew .contract('OsGmh1UtH4QytV0Tdxgg_TJ-VjfHkQYPLX7yuK1OfiQ') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/', + sequencerUrl: 'http://35.242.203.146:5666/', }) .connect(wallet); const contractF = warpNew .contract('7AZv5bczZhJJpUfwhzjz3iGdzo2PaBi0elgoRwzwg4g') .setEvaluationOptions({ - sequencerUrl: 'http://34.141.17.15:5666/', + sequencerUrl: 'http://35.242.203.146:5666/', }) .connect(new EthereumSigner(ethWallet)); @@ -59,7 +59,7 @@ setInterval(async () => { console.log('sending to L2...'); try { await Promise.all([ - contractB.writeInteraction({ + /*contractB.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 1, @@ -68,7 +68,7 @@ setInterval(async () => { function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 1, - }), + }),*/ contractD.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', @@ -79,17 +79,18 @@ setInterval(async () => { target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 1, }), - contractF.writeInteraction({ + /*contractF.writeInteraction({ function: 'transfer', target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI', qty: 1, - }), + }),*/ ]); } catch (e) { errors_l2 += `${e.stack}\n\n`; } }, 3000); +/* setInterval(async () => { console.log('sending to L1...'); try { @@ -131,6 +132,7 @@ setInterval(async () => { errors_l1 += `${e.stack}\n\n`; } }, 5000); +*/ setInterval(() => { saveErrors(); diff --git a/tools/nakurwiaj_kontrakt.js b/tools/nakurwiaj_kontrakt.js new file mode 100644 index 00000000..92c38f48 --- /dev/null +++ b/tools/nakurwiaj_kontrakt.js @@ -0,0 +1,47 @@ +const fs = require('fs'); +const warpContractsNew = require('warp-contracts-new'); +const { DeployPlugin } = require("warp-contracts-plugin-deploy"); +const { ArweaveSigner } = require("warp-arbundles"); + +const warpNew = warpContractsNew.WarpFactory.forMainnet({ + ...warpContractsNew.defaultCacheOptions, + dbLocation: 'warp/new', +}) + .use(new DeployPlugin()) + .useGwUrl('http://35.242.203.146:5666'); +const wallet = readJSON('./.secrets/33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA.json'); + +warpContractsNew.LoggerFactory.INST.logLevel('error'); + +async function doDeploy() { + try { + const { contractTxId } = await warpNew.deploy({ + wallet: new ArweaveSigner(wallet), + initState: JSON.stringify({}), + src: 'export async function handle(state, action){}' + }); + console.log("new contract", contractTxId); + } catch(e) { + console.error(e); + } +} + +doDeploy().finally(() => console.log("done")); + + +function readJSON(path) { + const content = fs.readFileSync(path, 'utf-8'); + try { + return JSON.parse(content); + } catch (e) { + throw new Error(`File "${path}" does not contain a valid JSON`); + } +} + +process.on('uncaughtException', () => { + console.error('uncaughtException'); +}); + +process.on('unhandledRejection', (e) => { + console.error('unhandledRejection'); +}); From b04b3a4b1944cb3f7830240299e53a2acedfe83d Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 21 Nov 2023 15:04:42 +0100 Subject: [PATCH 65/95] chore: reduce max connections --- src/db/databaseSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/databaseSource.ts b/src/db/databaseSource.ts index c1fbcf83..3e191596 100644 --- a/src/db/databaseSource.ts +++ b/src/db/databaseSource.ts @@ -290,7 +290,7 @@ export class DatabaseSource { useNullAsDefault: true, pool: { min: 5, - max: 30, + max: 20, createTimeoutMillis: 3000, acquireTimeoutMillis: 30000, idleTimeoutMillis: 30000, From 6c26934635c341dfe3dafee26e1b5463b81f095e Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 21 Nov 2023 15:12:49 +0100 Subject: [PATCH 66/95] chore: reduce max connections --- src/db/databaseSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/databaseSource.ts b/src/db/databaseSource.ts index 3e191596..d467e3ec 100644 --- a/src/db/databaseSource.ts +++ b/src/db/databaseSource.ts @@ -290,7 +290,7 @@ export class DatabaseSource { useNullAsDefault: true, pool: { min: 5, - max: 20, + max: 10, createTimeoutMillis: 3000, acquireTimeoutMillis: 30000, idleTimeoutMillis: 30000, From 000857088cbee527855a772e7ba0a691816f9160 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 21 Nov 2023 15:55:37 +0100 Subject: [PATCH 67/95] chore: increase max connections --- src/db/databaseSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/databaseSource.ts b/src/db/databaseSource.ts index d467e3ec..3e191596 100644 --- a/src/db/databaseSource.ts +++ b/src/db/databaseSource.ts @@ -290,7 +290,7 @@ export class DatabaseSource { useNullAsDefault: true, pool: { min: 5, - max: 10, + max: 20, createTimeoutMillis: 3000, acquireTimeoutMillis: 30000, idleTimeoutMillis: 30000, From 47fa4f5d107598f4b1e4b5438296c83eba9550ff Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 21 Nov 2023 16:12:48 +0100 Subject: [PATCH 68/95] chore: increase arweave network sync interval --- src/gateway/tasks/networkInfoCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index 96ef3899..23958061 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -86,7 +86,7 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { await updateNetworkInfo(); }, context - ).runSyncEvery(30 * 1000, true); + ).runSyncEvery(40 * 1000, true); } export async function getCachedNetworkData(dbSource: DatabaseSource): Promise { From edc8dc3f6542873332bc657f5beeab46724a049d Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 21 Nov 2023 16:23:05 +0100 Subject: [PATCH 69/95] chore: commit... --- src/gateway/tasks/networkInfoCache.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/tasks/networkInfoCache.ts b/src/gateway/tasks/networkInfoCache.ts index 23958061..c005876a 100644 --- a/src/gateway/tasks/networkInfoCache.ts +++ b/src/gateway/tasks/networkInfoCache.ts @@ -24,6 +24,7 @@ export async function runNetworkInfoCacheTask(context: GatewayContext) { const currentArweaveBlock = await pgAdvisoryLocks.acquireArweaveHeightMutex(trx); if (currentArweaveBlock === undefined) { logger.debug("Network info already locked, skipping"); + await trx.commit(); return; } From 910e4a9c662767f190e611808677cb7c35a3c84c Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 21 Nov 2023 17:18:02 +0100 Subject: [PATCH 70/95] chore: logging --- src/gateway/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index bc6bb313..a95dea6a 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -77,7 +77,7 @@ export interface GatewayContext { const appSync = process.env.APP_SYNC; LoggerFactory.INST.logLevel('info'); - LoggerFactory.INST.logLevel('debug', 'gateway'); + LoggerFactory.INST.logLevel('info', 'gateway'); LoggerFactory.INST.logLevel('debug', 'sequencer'); LoggerFactory.INST.logLevel('debug', 'PgAdvisoryLocks'); LoggerFactory.INST.logLevel('debug', 'access'); From b202c132e3832cdafe0a9224bcc5fdf95a4a726c Mon Sep 17 00:00:00 2001 From: Asia Date: Fri, 24 Nov 2023 11:48:22 +0100 Subject: [PATCH 71/95] feat: input in interaction data field (#189) --- .../interactionsSortKeyRoute_v2.ts | 67 ++++++++++++------- .../router/routes/sequencerRoute_v2.ts | 45 ++++++++++--- src/gateway/router/welcomeRouter.ts | 2 + src/utils.ts | 13 +++- updates/2023_11_22_manifest_column.sql | 1 + 5 files changed, 92 insertions(+), 36 deletions(-) create mode 100644 updates/2023_11_22_manifest_column.sql diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts index d02aefbd..ba08a463 100644 --- a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts @@ -1,12 +1,12 @@ import Router from '@koa/router'; -import {Benchmark} from 'warp-contracts'; +import { SmartWeaveTags } from 'warp-contracts'; const MAX_INTERACTIONS_PER_PAGE = 5000; export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { - const {dbSource, logger} = ctx; + const { dbSource, logger } = ctx; - const {contractId, confirmationStatus, page, limit, from, to, totalCount, source, fromSdk} = ctx.query; + const { contractId, confirmationStatus, page, limit, from, to, totalCount, source, fromSdk } = ctx.query; const parsedPage = page ? parseInt(page as string) : 1; @@ -17,7 +17,7 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { const parsedConfirmationStatus = confirmationStatus ? confirmationStatus == 'not_corrupted' - ? undefined// ['confirmed', 'not_processed'] + ? undefined // ['confirmed', 'not_processed'] : [confirmationStatus] : undefined; @@ -40,6 +40,7 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { const query = ` SELECT interaction, + input, confirmation_status, sort_key ${isFromSdk ? '' : ',confirming_peer, confirmations, bundler_tx_id '} @@ -47,10 +48,10 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { FROM interactions WHERE (contract_id = ? OR interact_write @> ARRAY [?]) ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' - } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' + } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} ORDER BY sort_key ${isFromSdk ? 'ASC' : 'DESC'} LIMIT ? OFFSET ?; `; @@ -73,24 +74,29 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; - const benchmark = Benchmark.measure(); - const mappedInteractions = isFromSdk - ? result?.rows?.map((r: any) => ({ - ...r.interaction, - sortKey: r.sort_key, - confirmationStatus: r.confirmation_status, - })) - : result?.rows?.map((r: any) => ({ - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - sortKey: r.sort_key, - }, - })); + ? result?.rows?.map((r: any) => { + const interactionTagsWithInput = addInputToInteractionTags(r.interaction.tags, r.input); + return { + ...{ ...r.interaction, tags: interactionTagsWithInput }, + sortKey: r.sort_key, + confirmationStatus: r.confirmation_status, + }; + }) + : result?.rows?.map((r: any) => { + const interactionTagsWithInput = addInputToInteractionTags(r.interaction.tags, r.input); + return { + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + tags: interactionTagsWithInput, + bundlerTxId: r.bundler_tx_id, + sortKey: r.sort_key, + }, + }; + }); ctx.body = { paging: { @@ -112,3 +118,14 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { interactions: mappedInteractions, }; } + +export function addInputToInteractionTags(interactionTags: { name: string; value: string }[], input: string) { + interactionTags.splice( + interactionTags.findIndex((i: { name: string; value: string }) => i.name == SmartWeaveTags.INPUT), + 1 + ); + + interactionTags.push({ name: SmartWeaveTags.INPUT, value: input }); + + return interactionTags; +} diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 103a37cb..11cd19ae 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -1,6 +1,6 @@ import Router from '@koa/router'; import { Benchmark, SmartWeaveTags, VrfData, timeout } from 'warp-contracts'; -import { isTxIdValid, parseFunctionName } from "../../../utils"; +import { isTxIdValid, parseFunctionName, safeParse } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; @@ -12,6 +12,8 @@ import rawBody from 'raw-body'; import { b64UrlToString } from 'arweave/node/lib/utils'; import { determineOwner } from './deploy/deployContractRoute_v2'; +export const MAX_INTERACTION_DATA_ITEM_SIZE_BYTES = 20000; + export async function sequencerRoute_v2(ctx: Router.RouterContext) { const { dbSource } = ctx; const trx = (await dbSource.primaryDb.transaction()) as Knex.Transaction; @@ -48,8 +50,12 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti throw new Error(`Interaction data item tags exceed limit.`); } - if (b64UrlToString(interactionDataItem.data).length > 4) { - throw new Error("Interaction data item's data field exceeds 4 bytes limit."); + if (interactionDataItem.getRaw().length > MAX_INTERACTION_DATA_ITEM_SIZE_BYTES) { + throw new Error( + `Interaction data item size: ${ + interactionDataItem.getRaw().length + } exceeds maximum interaction data item size limit: ${MAX_INTERACTION_DATA_ITEM_SIZE_BYTES}.` + ); } sLogger.debug('New sequencer data item', interactionDataItem.id); @@ -85,15 +91,30 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti throw new Error(`New sortKey (${sortKey}) <= lastSortKey (${acquireMutexResult.lastSortKey})!`); } + const data = b64UrlToString(interactionDataItem.data); const originalSignature = interactionDataItem.signature; const originalAddress = await determineOwner(interactionDataItem, arweave); const testnetVersion = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET)?.value || null; - const inputTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.INPUT)?.value || ''; const internalWrites: string[] = []; interactionDataItem.tags .filter((t) => t.name == SmartWeaveTags.INTERACT_WRITE) .forEach((t) => internalWrites.push(t.value)); + const interactionTags = interactionDataItem.tags; + let input: string; + + const inputFromTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.INPUT); + if (inputFromTag) { + input = inputFromTag.value; + } else { + const inputFromData = JSON.parse(data).input; + if (inputFromData) { + input = JSON.stringify(inputFromData); + } else { + throw new Error('No input specified.'); + } + } + const tags = [ { name: 'Sequencer', value: 'RedStone' }, { name: 'Sequencer-Owner', value: originalAddress }, @@ -122,7 +143,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const interaction = createInteraction( interactionDataItem, originalAddress, - interactionDataItem.tags, + interactionTags, acquireMutexResult.blockHeight, acquireMutexResult.blockHash, acquireMutexResult.blockTimestamp, @@ -133,10 +154,11 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti acquireMutexResult.lastSortKey ); - const parsedInput = JSON.parse(inputTag); - const functionName = parseFunctionName(inputTag, sLogger); + const parsedInput = safeParse(input, sLogger); + const functionName = parseFunctionName(input, sLogger); let evolve: string | null; evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; + const manifest = safeParse(data, sLogger).manifest || null; sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); sLogger.debug('inserting into tables'); @@ -162,7 +184,8 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti testnet, last_sort_key, owner, - sync_timestamp) + sync_timestamp, + manifest) VALUES ( :interaction_id, :interaction, @@ -181,7 +204,8 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti :testnet, :prev_sort_key, :owner, - :sync_timestamp) + :sync_timestamp, + :manifest) RETURNING id) INSERT INTO bundle_items (interaction_id, state, transaction, tags, data_item) @@ -195,7 +219,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti block_id: acquireMutexResult.blockHash, contract_id: contractTag, function: functionName, - input: inputTag, + input: input, confirmation_status: 'confirmed', confirming_peer: BUNDLR_NODE1_URL, source: 'redstone-sequencer', @@ -210,6 +234,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti tags: JSON.stringify(tags), sync_timestamp: millis, data_item: interactionDataItem.getRaw(), + manifest: manifest, } ); diff --git a/src/gateway/router/welcomeRouter.ts b/src/gateway/router/welcomeRouter.ts index 3b65cb73..ed6133c2 100644 --- a/src/gateway/router/welcomeRouter.ts +++ b/src/gateway/router/welcomeRouter.ts @@ -1,4 +1,5 @@ import Router from '@koa/router'; +import { MAX_INTERACTION_DATA_ITEM_SIZE_BYTES } from './routes/sequencerRoute_v2'; const welcomeRouter = new Router(); @@ -6,6 +7,7 @@ welcomeRouter.get('/', (ctx: Router.RouterContext) => { ctx.body = { name: 'Warp Gateway', id: process.env.pm_id, + maxInteractionDataItemSizeBytes: MAX_INTERACTION_DATA_ITEM_SIZE_BYTES, }; }); diff --git a/src/utils.ts b/src/utils.ts index c3d03c93..b2ed6130 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { Tag } from 'arweave/node/lib/transaction'; -import { Tags, WarpLogger } from "warp-contracts"; +import { Tags, WarpLogger } from 'warp-contracts'; import Arweave from 'arweave'; export function sleep(ms: number): Promise { @@ -66,3 +66,14 @@ export function parseFunctionName(input: string, logger: WarpLogger) { return '[Error during parsing function name]'; } } + +export function safeParse(jsonString: string, logger: WarpLogger) { + try { + return JSON.parse(jsonString); + } catch (e) { + logger.error('Could not parse JSON string', { + jsonString, + }); + return null; + } +} diff --git a/updates/2023_11_22_manifest_column.sql b/updates/2023_11_22_manifest_column.sql new file mode 100644 index 00000000..fc59f6a0 --- /dev/null +++ b/updates/2023_11_22_manifest_column.sql @@ -0,0 +1 @@ +ALTER TABLE interactions ADD COLUMN manifest jsonb; \ No newline at end of file From 52161ea2e95c9c2fcb2290ffc01ad895d8638e11 Mon Sep 17 00:00:00 2001 From: Asia Date: Fri, 24 Nov 2023 12:24:38 +0100 Subject: [PATCH 72/95] fix: null data when cannot be parsed --- src/gateway/router/routes/sequencerRoute_v2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 11cd19ae..27155844 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -158,7 +158,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const functionName = parseFunctionName(input, sLogger); let evolve: string | null; evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; - const manifest = safeParse(data, sLogger).manifest || null; + const manifest = safeParse(data, sLogger)?.manifest || null; sLogger.debug('Initial benchmark', initialBenchmark.elapsed()); sLogger.debug('inserting into tables'); From 5188a8d4f10157e66aee21d84c93c989ee9e4f88 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 27 Nov 2023 12:17:45 +0100 Subject: [PATCH 73/95] interactions sonar - input in data update --- .../routes/interactions/interactionsSonar.ts | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/gateway/router/routes/interactions/interactionsSonar.ts b/src/gateway/router/routes/interactions/interactionsSonar.ts index bc4bc847..0e602420 100644 --- a/src/gateway/router/routes/interactions/interactionsSonar.ts +++ b/src/gateway/router/routes/interactions/interactionsSonar.ts @@ -1,12 +1,13 @@ import Router from '@koa/router'; -import {Benchmark} from 'warp-contracts'; +import { Benchmark } from 'warp-contracts'; +import { addInputToInteractionTags } from './interactionsSortKeyRoute_v2'; const MAX_INTERACTIONS_PER_PAGE = 5000; export async function interactionsSonar(ctx: Router.RouterContext) { - const {dbSource, logger} = ctx; + const { dbSource, logger } = ctx; - const {contractId, confirmationStatus, page, limit, from, to, source} = ctx.query; + const { contractId, confirmationStatus, page, limit, from, to, source } = ctx.query; const parsedPage = page ? parseInt(page as string) : 1; @@ -32,6 +33,7 @@ export async function interactionsSonar(ctx: Router.RouterContext) { const query = ` SELECT interaction, + input, confirmation_status, sort_key, confirming_peer, @@ -40,9 +42,9 @@ export async function interactionsSonar(ctx: Router.RouterContext) { FROM interactions WHERE (contract_id = ? OR interact_write @> ARRAY [?]) ${ - parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` - : '' + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} ORDER BY sort_key DESC ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; `; @@ -85,18 +87,20 @@ export async function interactionsSonar(ctx: Router.RouterContext) { }, }), - interactions: result?.rows?.map((r: any) => ({ - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - bundlerTxId: r.bundler_tx_id, - sortKey: r.sort_key, - }, - })), + interactions: result?.rows?.map((r: any) => { + const interactionTagsWithInput = addInputToInteractionTags(r.interaction.tags, r.input); + return { + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...{ ...r.interaction, tags: interactionTagsWithInput }, + bundlerTxId: r.bundler_tx_id, + sortKey: r.sort_key, + }, + }; + }), }; logger.info('Mapping interactions: ', benchmark.elapsed()); - } From 03aa89ae8f93c8d52ab26e4b0e0e88ac006d03c7 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Mon, 27 Nov 2023 21:32:02 +0100 Subject: [PATCH 74/95] fix: input tag fix --- .../routes/interactions/interactionsSortKeyRoute_v2.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts index ba08a463..d01bff05 100644 --- a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts @@ -120,12 +120,9 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { } export function addInputToInteractionTags(interactionTags: { name: string; value: string }[], input: string) { - interactionTags.splice( - interactionTags.findIndex((i: { name: string; value: string }) => i.name == SmartWeaveTags.INPUT), - 1 - ); - - interactionTags.push({ name: SmartWeaveTags.INPUT, value: input }); + if (interactionTags.findIndex((i: { name: string; value: string }) => i.name == SmartWeaveTags.INPUT) === -1) { + interactionTags.push({ name: SmartWeaveTags.INPUT, value: input }); + } return interactionTags; } From 846d798c3f43c01a2299ace422aef2bb005b1021 Mon Sep 17 00:00:00 2001 From: Asia Date: Wed, 29 Nov 2023 10:10:09 +0100 Subject: [PATCH 75/95] fix: add input tag to interaction tags list when input format is equal to data (#191) --- package.json | 4 +- src/db/insertInterfaces.ts | 2 +- src/gateway/init.ts | 33 ++++--- .../routes/contracts/contractDataRoute.ts | 2 +- .../routes/deploy/deployContractRoute.ts | 16 ++-- .../routes/deploy/deployContractRoute_v2.ts | 12 +-- .../router/routes/deploy/deploySourceRoute.ts | 8 +- .../routes/deploy/deploySourceRoute_v2.ts | 4 +- .../routes/interactions/interactionsSonar.ts | 5 +- .../interactionsSortKeyRoute_v2.ts | 45 +++------- src/gateway/router/routes/sequencerRoute.ts | 26 ++++-- .../router/routes/sequencerRoute_v2.ts | 32 ++++--- src/utils.ts | 4 +- yarn.lock | 88 +++++++++++-------- 14 files changed, 148 insertions(+), 133 deletions(-) diff --git a/package.json b/package.json index 34dd850a..218f626d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@koa/router": "10.1.1", "JSONStream": "^1.3.5", "arbundles": "^0.9.6", - "arweave": "1.11.8", + "arweave": "1.13.7", "axios": "^0.26.1", "dotenv": "16.0.3", "elliptic": "^6.5.4", @@ -46,7 +46,7 @@ "undici": "5.21.0", "uuid": "^9.0.0", "warp-arbundles": "1.0.0", - "warp-contracts": "1.2.48", + "warp-contracts": "1.4.26-beta.0", "warp-contracts-new": "npm:warp-contracts", "warp-contracts-old": "npm:warp-contracts@1.4.12", "warp-contracts-plugin-signature": "^1.0.16", diff --git a/src/db/insertInterfaces.ts b/src/db/insertInterfaces.ts index 021e1f72..c6c15e62 100644 --- a/src/db/insertInterfaces.ts +++ b/src/db/insertInterfaces.ts @@ -49,7 +49,7 @@ export interface ContractInsert { block_timestamp: number; content_type: string | undefined; contract_tx: { - tags: Tags; + tags: { name: string; value: string }[]; }; bundler_contract_tx_id: string; bundler_contract_node: string; diff --git a/src/gateway/init.ts b/src/gateway/init.ts index a95dea6a..e6954c08 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -3,7 +3,14 @@ import { hideBin } from 'yargs/helpers'; import Koa from 'koa'; import Application from 'koa'; import bodyParser from 'koa-bodyparser'; -import { ArweaveWrapper, LexicographicalInteractionsSorter, LoggerFactory, WarpLogger } from 'warp-contracts'; +import { + ArweaveWrapper, + LexicographicalInteractionsSorter, + LoggerFactory, + WarpFactory, + WarpLogger, + defaultCacheOptions, +} from 'warp-contracts'; import Arweave from 'arweave'; import gatewayRouter from './router/gatewayRouter'; import * as fs from 'fs'; @@ -84,6 +91,18 @@ export interface GatewayContext { const logger = LoggerFactory.INST.create('gateway'); const sLogger = LoggerFactory.INST.create('sequencer'); const accessLogger = LoggerFactory.INST.create('access'); + const warp = WarpFactory.forMainnet(); + const warpGqlGoldsky = WarpFactory.forMainnet( + defaultCacheOptions, + false, + Arweave.init({ + host: 'arweave-search.goldsky.com', + port: 443, + protocol: 'https', + timeout: 20000, + logging: false, + }) + ); const env = process.env.ENV as string; if (!env) { @@ -138,16 +157,8 @@ export interface GatewayContext { app.context.arweave = arweave; app.context.bundlr = bundlr; app.context.jwk = jwk; - app.context.arweaveWrapper = new ArweaveWrapper(arweave); - app.context.arweaveWrapperGqlGoldsky = new ArweaveWrapper( - Arweave.init({ - host: 'arweave-search.goldsky.com', - port: 443, - protocol: 'https', - timeout: 20000, - logging: false, - }) - ); + app.context.arweaveWrapper = new ArweaveWrapper(warp); + app.context.arweaveWrapperGqlGoldsky = new ArweaveWrapper(warpGqlGoldsky); app.context.sorter = new LexicographicalInteractionsSorter(arweave); app.context.pgAdvisoryLocks = new PgAdvisoryLocks(); app.context.appSync = appSync; diff --git a/src/gateway/router/routes/contracts/contractDataRoute.ts b/src/gateway/router/routes/contracts/contractDataRoute.ts index 190a0557..c34ce1c3 100644 --- a/src/gateway/router/routes/contracts/contractDataRoute.ts +++ b/src/gateway/router/routes/contracts/contractDataRoute.ts @@ -59,7 +59,7 @@ async function getContractData( logger: WarpLogger, id: string, bundlrId: string, - tags: { name: string; value: string }[], + tags: Tags, arweaveWrapper: ArweaveWrapper, deploymentType: string, bundlrContractNode: string diff --git a/src/gateway/router/routes/deploy/deployContractRoute.ts b/src/gateway/router/routes/deploy/deployContractRoute.ts index 2bbb0787..87b3a21a 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute.ts @@ -1,14 +1,14 @@ import Router, { RouterContext } from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; import Arweave from 'arweave'; -import { GQLTagInterface, SmartWeaveTags } from 'warp-contracts'; +import { GQLTagInterface, SMART_WEAVE_TAGS, WARP_TAGS } from 'warp-contracts'; import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { uploadToBundlr } from '../sequencerRoute'; import { publishContract, sendNotification } from '../../../publisher'; import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; -import {GatewayError} from "../../../errorHandlerMiddleware"; -import { evalType } from "../../../../utils"; +import { GatewayError } from '../../../errorHandlerMiddleware'; +import { evalType } from '../../../../utils'; /* - warp-wrapped - contract or source is wrapped in another transaction - it is posted by Warp Gateway to the Bundlr network and sent @@ -63,8 +63,8 @@ export async function deployContractRoute(ctx: Router.RouterContext) { srcTxOwner = srcTagsData.originalAddress; srcTestnet = srcTagsData.testnet; - srcContentType = tagValue(SmartWeaveTags.CONTENT_TYPE, srcTagsData.tags); - srcWasmLang = tagValue(SmartWeaveTags.WASM_LANG, srcTagsData.tags); + srcContentType = tagValue(SMART_WEAVE_TAGS.CONTENT_TYPE, srcTagsData.tags); + srcWasmLang = tagValue(WARP_TAGS.WASM_LANG, srcTagsData.tags); if (srcContentType == 'application/javascript') { src = Arweave.utils.bufferToString(srcTx.data); } else { @@ -78,7 +78,7 @@ export async function deployContractRoute(ctx: Router.RouterContext) { bundled_tx_id: bundlerSrcTxId, }); } else { - srcTxId = tagValue(SmartWeaveTags.CONTRACT_SRC_TX_ID, contractTags); + srcTxId = tagValue(SMART_WEAVE_TAGS.CONTRACT_SRC_TX_ID, contractTags); if (!srcTxId) { throw new Error('SrcTxId not defined'); } @@ -96,7 +96,7 @@ export async function deployContractRoute(ctx: Router.RouterContext) { bundled_tx_id: bundlerContractTx.id, }); - let initStateRaw = tagValue(SmartWeaveTags.INIT_STATE, contractTags); + let initStateRaw = tagValue(WARP_TAGS.INIT_STATE, contractTags); if (!initStateRaw) { initStateRaw = Arweave.utils.bufferToString(contractTx.data); } @@ -118,7 +118,7 @@ export async function deployContractRoute(ctx: Router.RouterContext) { pst_name: type == 'pst' ? initState?.name : null, block_height: blockHeight, block_timestamp: blockTimestamp, - content_type: tagValue(SmartWeaveTags.CONTENT_TYPE, contractTags), + content_type: tagValue(SMART_WEAVE_TAGS.CONTENT_TYPE, contractTags), contract_tx: { tags: contractTx.toJSON().tags }, bundler_contract_tx_id: bundlerContractTx.id, bundler_contract_node: BUNDLR_NODE1_URL, diff --git a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts index 68e2f921..28c82a9e 100644 --- a/src/gateway/router/routes/deploy/deployContractRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deployContractRoute_v2.ts @@ -1,7 +1,7 @@ import Router from '@koa/router'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { Bundle, DataItem } from 'arbundles'; -import { SmartWeaveTags } from 'warp-contracts'; +import { SMART_WEAVE_TAGS, Tags, WARP_TAGS } from 'warp-contracts'; import { getCachedNetworkData } from '../../../tasks/networkInfoCache'; import { publishContract, sendNotification } from '../../../publisher'; import { evalManifest, WarpDeployment } from './deployContractRoute'; @@ -11,7 +11,7 @@ import { utils } from 'ethers'; import { longTo32ByteArray } from 'arbundles'; import { ContractInsert, ContractSourceInsert } from '../../../../db/insertInterfaces'; import { GatewayError } from '../../../errorHandlerMiddleware'; -import { evalType } from "../../../../utils"; +import { evalType } from '../../../../utils'; export async function deployContractRoute_v2(ctx: Router.RouterContext) { const { logger, arweave, dbSource } = ctx; @@ -52,7 +52,7 @@ export async function deployContractRoute_v2(ctx: Router.RouterContext) { srcOwner = await determineOwner(srcDataItem, arweave); srcTestnet = getTestnetTag(srcDataItem.tags); srcContentType = srcDataItem.tags.find((t) => t.name == 'Content-Type')!.value; - srcWasmLang = srcDataItem.tags.find((t) => t.name == SmartWeaveTags.WASM_LANG)?.value; + srcWasmLang = srcDataItem.tags.find((t) => t.name == WARP_TAGS.WASM_LANG)?.value; if (srcContentType == 'application/javascript') { src = Arweave.utils.bufferToString(srcDataItem.rawData); } else { @@ -163,9 +163,9 @@ export async function verifyDeployTags(dataItem: DataItem, opts?: { contract: bo const tags = dataItem.tags; const deployTags = [ - { name: SmartWeaveTags.APP_NAME, value: opts?.contract ? 'SmartWeaveContract' : 'SmartWeaveContractSource' }, - { name: SmartWeaveTags.APP_VERSION, value: '0.3.0' }, - { name: SmartWeaveTags.SDK, value: 'Warp' }, + { name: SMART_WEAVE_TAGS.APP_NAME, value: opts?.contract ? 'SmartWeaveContract' : 'SmartWeaveContractSource' }, + { name: SMART_WEAVE_TAGS.APP_VERSION, value: '0.3.0' }, + { name: SMART_WEAVE_TAGS.SDK, value: 'Warp' }, ]; const contractNameTags = ['Contract-Src', 'Nonce']; diff --git a/src/gateway/router/routes/deploy/deploySourceRoute.ts b/src/gateway/router/routes/deploy/deploySourceRoute.ts index cab814cd..5c97a61c 100644 --- a/src/gateway/router/routes/deploy/deploySourceRoute.ts +++ b/src/gateway/router/routes/deploy/deploySourceRoute.ts @@ -1,12 +1,12 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; import Arweave from 'arweave'; -import { SmartWeaveTags } from 'warp-contracts'; +import { SMART_WEAVE_TAGS, WARP_TAGS } from 'warp-contracts'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { uploadToBundlr } from '../sequencerRoute'; import { prepareTags, tagValue, verifyEvmSignature, WarpDeployment } from './deployContractRoute'; import { ContractSourceInsert } from '../../../../db/insertInterfaces'; -import {GatewayError} from "../../../errorHandlerMiddleware"; +import { GatewayError } from '../../../errorHandlerMiddleware'; export async function deploySourceRoute(ctx: Router.RouterContext) { const { logger, arweave, bundlr, dbSource } = ctx; @@ -25,8 +25,8 @@ export async function deploySourceRoute(ctx: Router.RouterContext) { srcTxOwner = srcTagsData.originalAddress; srcTestnet = srcTagsData.testnet; - srcContentType = tagValue(SmartWeaveTags.CONTENT_TYPE, srcTagsData.tags); - srcWasmLang = tagValue(SmartWeaveTags.WASM_LANG, srcTagsData.tags); + srcContentType = tagValue(SMART_WEAVE_TAGS.CONTENT_TYPE, srcTagsData.tags); + srcWasmLang = tagValue(WARP_TAGS.WASM_LANG, srcTagsData.tags); if (srcContentType == 'application/javascript') { src = Arweave.utils.bufferToString(srcTx.data); } else { diff --git a/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts b/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts index 15e83317..210f7db8 100644 --- a/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts +++ b/src/gateway/router/routes/deploy/deploySourceRoute_v2.ts @@ -1,6 +1,6 @@ import Router from '@koa/router'; import Arweave from 'arweave'; -import { SmartWeaveTags } from 'warp-contracts'; +import { SMART_WEAVE_TAGS, WARP_TAGS } from 'warp-contracts'; import { BUNDLR_NODE1_URL } from '../../../../constants'; import { WarpDeployment } from './deployContractRoute'; import rawBody from 'raw-body'; @@ -36,7 +36,7 @@ export async function deploySourceRoute_v2(ctx: Router.RouterContext) { srcTestnet = getTestnetTag(dataItem.tags); srcContentType = dataItem.tags.find((t) => t.name == 'Content-Type')!.value; - srcWasmLang = dataItem.tags.find((t) => t.name == SmartWeaveTags.WASM_LANG)?.value; + srcWasmLang = dataItem.tags.find((t) => t.name == WARP_TAGS.WASM_LANG)?.value; if (srcContentType == 'application/javascript') { src = Arweave.utils.bufferToString(dataItem.rawData); } else { diff --git a/src/gateway/router/routes/interactions/interactionsSonar.ts b/src/gateway/router/routes/interactions/interactionsSonar.ts index 0e602420..d7b22616 100644 --- a/src/gateway/router/routes/interactions/interactionsSonar.ts +++ b/src/gateway/router/routes/interactions/interactionsSonar.ts @@ -1,6 +1,5 @@ import Router from '@koa/router'; import { Benchmark } from 'warp-contracts'; -import { addInputToInteractionTags } from './interactionsSortKeyRoute_v2'; const MAX_INTERACTIONS_PER_PAGE = 5000; @@ -33,7 +32,6 @@ export async function interactionsSonar(ctx: Router.RouterContext) { const query = ` SELECT interaction, - input, confirmation_status, sort_key, confirming_peer, @@ -88,13 +86,12 @@ export async function interactionsSonar(ctx: Router.RouterContext) { }), interactions: result?.rows?.map((r: any) => { - const interactionTagsWithInput = addInputToInteractionTags(r.interaction.tags, r.input); return { status: r.confirmation_status, confirming_peers: r.confirming_peer, confirmations: r.confirmations, interaction: { - ...{ ...r.interaction, tags: interactionTagsWithInput }, + ...r.interaction, bundlerTxId: r.bundler_tx_id, sortKey: r.sort_key, }, diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts index d01bff05..e80f1e1b 100644 --- a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v2.ts @@ -1,5 +1,4 @@ import Router from '@koa/router'; -import { SmartWeaveTags } from 'warp-contracts'; const MAX_INTERACTIONS_PER_PAGE = 5000; @@ -40,7 +39,6 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { const query = ` SELECT interaction, - input, confirmation_status, sort_key ${isFromSdk ? '' : ',confirming_peer, confirmations, bundler_tx_id '} @@ -75,28 +73,21 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; const mappedInteractions = isFromSdk - ? result?.rows?.map((r: any) => { - const interactionTagsWithInput = addInputToInteractionTags(r.interaction.tags, r.input); - return { - ...{ ...r.interaction, tags: interactionTagsWithInput }, + ? result?.rows?.map((r: any) => ({ + ...r.interaction, + sortKey: r.sort_key, + confirmationStatus: r.confirmation_status, + })) + : result?.rows?.map((r: any) => ({ + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, sortKey: r.sort_key, - confirmationStatus: r.confirmation_status, - }; - }) - : result?.rows?.map((r: any) => { - const interactionTagsWithInput = addInputToInteractionTags(r.interaction.tags, r.input); - return { - status: r.confirmation_status, - confirming_peers: r.confirming_peer, - confirmations: r.confirmations, - interaction: { - ...r.interaction, - tags: interactionTagsWithInput, - bundlerTxId: r.bundler_tx_id, - sortKey: r.sort_key, - }, - }; - }); + }, + })); ctx.body = { paging: { @@ -118,11 +109,3 @@ export async function interactionsSortKeyRoute_v2(ctx: Router.RouterContext) { interactions: mappedInteractions, }; } - -export function addInputToInteractionTags(interactionTags: { name: string; value: string }[], input: string) { - if (interactionTags.findIndex((i: { name: string; value: string }) => i.name == SmartWeaveTags.INPUT) === -1) { - interactionTags.push({ name: SmartWeaveTags.INPUT, value: input }); - } - - return interactionTags; -} diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 79c0670e..417954e5 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -2,9 +2,17 @@ import Router from '@koa/router'; import Transaction from 'arweave/node/lib/transaction'; import Arweave from 'arweave'; import { JWKInterface } from 'arweave/node/lib/wallet'; -import { arrayToHex, Benchmark, GQLTagInterface, SmartWeaveTags, timeout, WarpLogger } from 'warp-contracts'; +import { + arrayToHex, + Benchmark, + GQLTagInterface, + SMART_WEAVE_TAGS, + timeout, + WARP_TAGS, + WarpLogger, +} from 'warp-contracts'; import Bundlr from '@bundlr-network/client'; -import { isTxIdValid, parseFunctionName } from "../../../utils"; +import { isTxIdValid, parseFunctionName } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; @@ -25,8 +33,8 @@ export type SequencerResult = { prevSortKey: string | null; id: string; internalWrites: string[]; - timestamp: number -} + timestamp: number; +}; export async function sequencerRoute(ctx: Router.RouterContext) { const { dbSource } = ctx; @@ -231,7 +239,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti sortKey, timestamp: millis, prevSortKey: acquireMutexResult.lastSortKey, - internalWrites + internalWrites, }; } @@ -335,16 +343,16 @@ async function prepareTags(logger: any, transaction: Transaction, originalOwner: for (const tag of transaction.tags) { const key = tag.get('name', { decode: true, string: true }); const value = tag.get('value', { decode: true, string: true }); - if (key == SmartWeaveTags.CONTRACT_TX_ID) { + if (key == SMART_WEAVE_TAGS.CONTRACT_TX_ID) { contractTag = value; } - if (key == SmartWeaveTags.INPUT) { + if (key == SMART_WEAVE_TAGS.INPUT) { inputTag = value; } - if (key == SmartWeaveTags.INTERACT_WRITE) { + if (key == WARP_TAGS.INTERACT_WRITE) { internalWrites.push(value); } - if (key == SmartWeaveTags.REQUEST_VRF) { + if (key == WARP_TAGS.REQUEST_VRF) { requestVrfTag = value; } if (key == 'Signature-Type' && value == 'ethereum') { diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 27155844..93ac08e7 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -1,5 +1,5 @@ import Router from '@koa/router'; -import { Benchmark, SmartWeaveTags, VrfData, timeout } from 'warp-contracts'; +import { Benchmark, SMART_WEAVE_TAGS, VrfData, WARP_TAGS, timeout } from 'warp-contracts'; import { isTxIdValid, parseFunctionName, safeParse } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; @@ -65,7 +65,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti ctx.throw(400, 'Interaction data item binary is not valid.'); } - const contractTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.CONTRACT_TX_ID)!.value; + const contractTag = interactionDataItem.tags.find((t) => t.name == SMART_WEAVE_TAGS.CONTRACT_TX_ID)!.value; const acquireMutexResult = await pgAdvisoryLocks.acquireSortKeyMutex(contractTag, trx); sLogger.debug('Acquire mutex result', acquireMutexResult); @@ -94,25 +94,32 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const data = b64UrlToString(interactionDataItem.data); const originalSignature = interactionDataItem.signature; const originalAddress = await determineOwner(interactionDataItem, arweave); - const testnetVersion = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.WARP_TESTNET)?.value || null; + const testnetVersion = interactionDataItem.tags.find((t) => t.name == WARP_TAGS.WARP_TESTNET)?.value || null; const internalWrites: string[] = []; interactionDataItem.tags - .filter((t) => t.name == SmartWeaveTags.INTERACT_WRITE) + .filter((t) => t.name == WARP_TAGS.INTERACT_WRITE) .forEach((t) => internalWrites.push(t.value)); const interactionTags = interactionDataItem.tags; let input: string; - - const inputFromTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.INPUT); - if (inputFromTag) { - input = inputFromTag.value; - } else { + const inputFormat = interactionDataItem.tags.find((t) => t.name == WARP_TAGS.INPUT_FORMAT)?.value; + if (inputFormat == 'tag') { + const inputFromTag = interactionDataItem.tags.find((t) => t.name == SMART_WEAVE_TAGS.INPUT); + if (inputFromTag) { + input = inputFromTag.value; + } else { + throw new Error('Input in tag not specified.'); + } + } else if (inputFormat == 'data') { const inputFromData = JSON.parse(data).input; if (inputFromData) { input = JSON.stringify(inputFromData); + interactionTags.push({ name: SMART_WEAVE_TAGS.INPUT, value: input }); } else { - throw new Error('No input specified.'); + throw new Error('Input in data not specified.'); } + } else { + throw new Error('Input format not specified.'); } const tags = [ @@ -133,7 +140,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti } let vrfData: VrfData | null = null; - const requestVrfTag = interactionDataItem.tags.find((t) => t.name == SmartWeaveTags.REQUEST_VRF)?.value || null; + const requestVrfTag = interactionDataItem.tags.find((t) => t.name == WARP_TAGS.REQUEST_VRF)?.value || null; if (requestVrfTag) { const vrfGen = generateVrfTags(sortKey, vrf, arweave); tags.push(...vrfGen.vrfTags); @@ -173,7 +180,6 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti block_id, contract_id, function, - input, confirmation_status, confirming_peer, source, @@ -193,7 +199,6 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti :block_id, :contract_id, :function, - :input, :confirmation_status, :confirming_peer, :source, @@ -219,7 +224,6 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti block_id: acquireMutexResult.blockHash, contract_id: contractTag, function: functionName, - input: input, confirmation_status: 'confirmed', confirming_peer: BUNDLR_NODE1_URL, source: 'redstone-sequencer', diff --git a/src/utils.ts b/src/utils.ts index b2ed6130..bb84acd7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -23,14 +23,14 @@ export function isTxIdValid(txId: string): boolean { } export function decodeTags(tags: Tags) { - const decodedTags: { name: string; value: string }[] = []; + const decodedTags: Tags = []; const mappedTags = tags.map((tag: { name: string; value: string }) => { return new Tag(tag.name, tag.value); }); mappedTags.forEach((tag: Tag) => { let name = tag.get('name', { decode: true, string: true }); let value = tag.get('value', { decode: true, string: true }); - decodedTags.push({ name, value }); + decodedTags.push(new Tag(name, value)); }); return decodedTags; diff --git a/yarn.lock b/yarn.lock index 5927cb2c..0f04a117 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1311,6 +1311,11 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" +"@fastify/busboy@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" + integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== + "@humanwhocodes/config-array@^0.6.0": version "0.6.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.6.0.tgz#b5621fdb3b32309d2d16575456cbc277fa8f021a" @@ -2489,27 +2494,27 @@ arweave@1.11.6, arweave@^1.10.13, arweave@^1.11.4, arweave@^1.11.6: bignumber.js "^9.0.2" util "^0.12.4" -arweave@1.11.8, arweave@=1.11.8: - version "1.11.8" - resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.11.8.tgz#09376e0c6cec40a661cbb27a306cb11c0a663cd8" - integrity sha512-58ODeNPIC4OjaOCl2bXjKbOFGsiVZFs+DkQg3BvQGvFWNqw1zTJ4Jp01xGUz+GbdOaDyJcCC0g3l0HwdJfFPyw== +arweave@1.13.7, arweave@^1.13.7: + version "1.13.7" + resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.13.7.tgz#cda8534c833baec372a7052c61f53b4e39a886d7" + integrity sha512-Hv+x2bSI6UyBHpuVbUDMMpMje1ETfpJWj52kKfz44O0IqDRi/LukOkkDUptup1p6OT6KP1/DdpnUnsNHoskFeA== dependencies: arconnect "^0.4.2" asn1.js "^5.4.1" - axios "^0.27.2" base64-js "^1.5.1" bignumber.js "^9.0.2" - util "^0.12.4" -arweave@1.13.7, arweave@^1.13.7: - version "1.13.7" - resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.13.7.tgz#cda8534c833baec372a7052c61f53b4e39a886d7" - integrity sha512-Hv+x2bSI6UyBHpuVbUDMMpMje1ETfpJWj52kKfz44O0IqDRi/LukOkkDUptup1p6OT6KP1/DdpnUnsNHoskFeA== +arweave@=1.11.8: + version "1.11.8" + resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.11.8.tgz#09376e0c6cec40a661cbb27a306cb11c0a663cd8" + integrity sha512-58ODeNPIC4OjaOCl2bXjKbOFGsiVZFs+DkQg3BvQGvFWNqw1zTJ4Jp01xGUz+GbdOaDyJcCC0g3l0HwdJfFPyw== dependencies: arconnect "^0.4.2" asn1.js "^5.4.1" + axios "^0.27.2" base64-js "^1.5.1" bignumber.js "^9.0.2" + util "^0.12.4" arweave@^1.13.1: version "1.14.4" @@ -7005,6 +7010,13 @@ undici@^4.12.2: resolved "https://registry.yarnpkg.com/undici/-/undici-4.16.0.tgz#469bb87b3b918818d3d7843d91a1d08da357d5ff" integrity sha512-tkZSECUYi+/T1i4u+4+lwZmQgLXd4BLGlrc7KZPcLIW7Jpq99+Xpc30ONv7nS6F5UNOxp/HBZSSL9MafUrvJbw== +undici@^5.19.1: + version "5.28.1" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.1.tgz#1052d37bd1a2e8cf3e188d7caebff833fdc06fa7" + integrity sha512-xcIIvj1LOQH9zAL54iWFkuDEaIVEjLrru7qRpa3GrEEHk6OBhb/LycuUY2m7VCcTuDeLziXCxobQVyKExyGeIA== + dependencies: + "@fastify/busboy" "^2.0.0" + undici@^5.8.0: version "5.12.0" resolved "https://registry.yarnpkg.com/undici/-/undici-5.12.0.tgz#c758ffa704fbcd40d506e4948860ccaf4099f531" @@ -7199,6 +7211,16 @@ warp-arbundles@1.0.1: buffer "^6.0.3" warp-isomorphic "^1.0.4" +warp-arbundles@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/warp-arbundles/-/warp-arbundles-1.0.4.tgz#10c0cd662ab41b0dabad9159c7110f43425cc5cc" + integrity sha512-KeRac/EJ7VOK+v5+PSMh2SrzpCKOAFnJICLlqZWt6qPkDCzVwcrNE5wFxOlEk5U170ewMDAB3e86UHUblevXpw== + dependencies: + arweave "^1.13.7" + base64url "^3.0.1" + buffer "^6.0.3" + warp-isomorphic "^1.0.7" + "warp-contracts-new@npm:warp-contracts": version "1.4.14" resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.14.tgz#0a14428229736f568cdd54723dfa903dfe86ccfc" @@ -7283,26 +7305,25 @@ warp-contracts@1.2.20: unzipit "^1.4.0" vm2 "3.9.11" -warp-contracts@1.2.48: - version "1.2.48" - resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.2.48.tgz#2a325e80093eb54ed59af495e21c3b2c98b796a9" - integrity sha512-TBZJ/VZdr+9mFjH2gjf55kTeHc9/tXQ3bsym41+ujq6m1kIreyhL1I0G7bn6qSHpAbOIZKIjP5GC5+pp9pm8Ew== +warp-contracts@1.4.26-beta.0: + version "1.4.26-beta.0" + resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.26-beta.0.tgz#2784c0bd45669f6a3c6281ea1daeeb6ece5dfc6f" + integrity sha512-B5us0r45aqfQoHiQQVg/q9xlVmceyKK7ZyZaJYef0eozdcrBZ576KkdZxKSGGaO+BnDZjkVxh1e/I/sV67/Yng== dependencies: - "@assemblyscript/loader" "^0.19.23" - "@idena/vrf-js" "^1.0.1" archiver "^5.3.0" - arweave "1.11.8" - elliptic "^6.5.4" + arweave "1.13.7" + async-mutex "^0.4.0" + bignumber.js "9.1.1" events "3.3.0" fast-copy "^3.0.0" level "^8.0.0" memory-level "^1.0.0" - redstone-isomorphic "1.1.8" safe-stable-stringify "2.4.1" stream-buffers "^3.0.2" unzipit "^1.4.0" - vm2 "3.9.11" - warp-wasm-metering "1.0.0" + warp-arbundles "^1.0.4" + warp-isomorphic "^1.0.7" + warp-wasm-metering "1.0.1" warp-isomorphic@1.0.0: version "1.0.0" @@ -7320,6 +7341,14 @@ warp-isomorphic@1.0.4, warp-isomorphic@^1.0.4: buffer "^6.0.3" undici "^5.8.0" +warp-isomorphic@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/warp-isomorphic/-/warp-isomorphic-1.0.7.tgz#abf1ee7bce44bec7c6b97547859e614876869aa7" + integrity sha512-fXHbUXwdYqPm9fRPz8mjv5ndPco09aMQuTe4kXfymzOq8V6F3DLsg9cIafxvjms9/mc6eijzkLBJ63yjEENEjA== + dependencies: + buffer "^6.0.3" + undici "^5.19.1" + warp-signature@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/warp-signature/-/warp-signature-1.0.4.tgz#34868050192e10b3d2577db13fe1c2ec5242086f" @@ -7332,15 +7361,6 @@ warp-signature@1.0.4: safe-stable-stringify "^2.4.1" warp-contracts "1.2.20" -warp-wasm-json-toolkit@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/warp-wasm-json-toolkit/-/warp-wasm-json-toolkit-1.0.0.tgz#f08b555b64fac2b102450e6a5e94f4bf71405508" - integrity sha512-pFJpP3djS6GvDu5ohgBjSjkYQrKs1Toi7hsvjW5FIJO1Q/msclbeoUY3Poiyx0Hz6oRVfuO2MZkmCreDnNaUTg== - dependencies: - buffer-pipe "0.0.3" - leb128 "0.0.4" - redstone-isomorphic "1.1.0" - warp-wasm-json-toolkit@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/warp-wasm-json-toolkit/-/warp-wasm-json-toolkit-1.0.2.tgz#16ca399e5b20da804c01ff0d00979341b689a0e7" @@ -7350,14 +7370,6 @@ warp-wasm-json-toolkit@1.0.2: leb128 "0.0.4" warp-isomorphic "1.0.0" -warp-wasm-metering@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/warp-wasm-metering/-/warp-wasm-metering-1.0.0.tgz#ff2ded687885af22c8fc6560409a582e127c3af3" - integrity sha512-lOlVz7BDTnTMuvhrtIbVtozGJANoVgVn6gD3dTEFyIMehC250CKHmsqenX1jy5OM2DNL/VuFNdCTLHCGaPg64w== - dependencies: - leb128 "^0.0.4" - warp-wasm-json-toolkit "1.0.0" - warp-wasm-metering@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/warp-wasm-metering/-/warp-wasm-metering-1.0.1.tgz#1496b0b9a936985cf21a910e909b87630faa1c43" From f796ff2c3d86d34178cddbe9e05646fa6134ccaf Mon Sep 17 00:00:00 2001 From: Asia Date: Wed, 29 Nov 2023 11:06:27 +0100 Subject: [PATCH 76/95] fix: input in data - backwards compatibility --- .../router/routes/sequencerRoute_v2.ts | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 93ac08e7..69ea9072 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -1,5 +1,5 @@ import Router from '@koa/router'; -import { Benchmark, SMART_WEAVE_TAGS, VrfData, WARP_TAGS, timeout } from 'warp-contracts'; +import { Benchmark, SMART_WEAVE_TAGS, Tags, VrfData, WARP_TAGS, timeout } from 'warp-contracts'; import { isTxIdValid, parseFunctionName, safeParse } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; @@ -101,25 +101,18 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti .forEach((t) => internalWrites.push(t.value)); const interactionTags = interactionDataItem.tags; - let input: string; + let input: string | null; const inputFormat = interactionDataItem.tags.find((t) => t.name == WARP_TAGS.INPUT_FORMAT)?.value; if (inputFormat == 'tag') { - const inputFromTag = interactionDataItem.tags.find((t) => t.name == SMART_WEAVE_TAGS.INPUT); - if (inputFromTag) { - input = inputFromTag.value; - } else { - throw new Error('Input in tag not specified.'); - } + input = getInputFromTag(interactionDataItem.tags); } else if (inputFormat == 'data') { - const inputFromData = JSON.parse(data).input; - if (inputFromData) { - input = JSON.stringify(inputFromData); - interactionTags.push({ name: SMART_WEAVE_TAGS.INPUT, value: input }); - } else { - throw new Error('Input in data not specified.'); - } + input = getInputFromData(data, interactionTags); } else { - throw new Error('Input format not specified.'); + input = getInputFromTag(interactionDataItem.tags) || getInputFromData(data, interactionTags); + } + + if (!input) { + throw new Error(`Input not specifided`); } const tags = [ @@ -252,3 +245,18 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti internalWrites, }; } + +function getInputFromTag(tags: { name: string; value: string }[]) { + const inputFromTag = tags.find((t) => t.name == SMART_WEAVE_TAGS.INPUT); + return inputFromTag ? inputFromTag.value : null; +} + +function getInputFromData(data: string, interactionTags: { name: string; value: string }[]) { + const inputFromData = JSON.parse(data).input; + if (inputFromData) { + interactionTags.push({ name: SMART_WEAVE_TAGS.INPUT, value: JSON.stringify(inputFromData) }); + return JSON.stringify(inputFromData); + } else { + return null; + } +} From 347bd5b56a752ecfc1619c6e537b48393f070d95 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 30 Nov 2023 19:07:46 +0100 Subject: [PATCH 77/95] chore: stop using javascript. --- package.json | 4 +- src/bundlr/connect.ts | 39 +- src/gateway/PgAdvisoryLocks.ts | 1 + src/gateway/init.ts | 5 +- src/gateway/router/routes/sequencerRoute.ts | 7 +- yarn.lock | 477 +++++++++++++------- 6 files changed, 334 insertions(+), 199 deletions(-) diff --git a/package.json b/package.json index 218f626d..08a05819 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "license": "MIT", "author": "Redstone Team ", "dependencies": { - "@bundlr-network/client": "0.9.6", + "@irys/sdk": "0.1.1", "@idena/vrf-js": "^1.0.1", "@koa/cors": "3.2.0", "@koa/router": "10.1.1", @@ -76,6 +76,6 @@ "ts-jest": "27.1.2", "ts-node": "^10.2.1", "tsconfig-paths": "^3.10.1", - "typescript": "4.5.2" + "typescript": "4.9.5" } } diff --git a/src/bundlr/connect.ts b/src/bundlr/connect.ts index e107fbe8..45e2f1a6 100644 --- a/src/bundlr/connect.ts +++ b/src/bundlr/connect.ts @@ -1,25 +1,30 @@ -import { WarpLogger } from 'warp-contracts'; -import Bundlr from '@bundlr-network/client'; -import fs from 'fs'; -import { TaskRunner } from '../gateway/tasks/TaskRunner'; -import { GatewayContext } from '../gateway/init'; -import { JWKInterface } from 'arweave/node/lib/wallet'; -import { BUNDLR_NODE1_URL } from '../constants'; +import { WarpLogger } from "warp-contracts"; +import fs from "fs"; +import { TaskRunner } from "../gateway/tasks/TaskRunner"; +import { GatewayContext } from "../gateway/init"; +import { JWKInterface } from "arweave/node/lib/wallet"; +import { BUNDLR_NODE1_URL } from "../constants"; +import Irys from "@irys/sdk"; const BUNDLR_CHECK_INTERVAL = 3600000; export async function runBundlrCheck(context: GatewayContext) { - await TaskRunner.from('[bundlr balance check]', checkBalance, context).runSyncEvery(BUNDLR_CHECK_INTERVAL, true); + await TaskRunner.from("[bundlr balance check]", checkBalance, context).runSyncEvery(BUNDLR_CHECK_INTERVAL, true); } -export function initBundlr(logger: WarpLogger): { bundlr: Bundlr; jwk: JWKInterface } { - const jwk = JSON.parse(fs.readFileSync('.secrets/warp-wallet-jwk.json').toString()); - const bundlr = new Bundlr(BUNDLR_NODE1_URL, 'arweave', jwk, { - timeout: 5000, +export function initBundlr(logger: WarpLogger): { bundlr: Irys; jwk: JWKInterface } { + const jwk = JSON.parse(fs.readFileSync(".secrets/warp-wallet-jwk.json").toString()); + const bundlr = new Irys({ + url: BUNDLR_NODE1_URL, + token: "arweave", + key: jwk, + config: { + timeout: 5000 + } }); - logger.info('Running bundlr on', { + logger.info("Running bundlr on", { address: bundlr.address, - currency: bundlr.currency, + currency: bundlr.token }); return { bundlr, jwk }; @@ -27,15 +32,15 @@ export function initBundlr(logger: WarpLogger): { bundlr: Bundlr; jwk: JWKInterf async function checkBalance(context: GatewayContext) { const { bundlr, logger } = context; - logger.debug('Checking Bundlr balance'); + logger.debug("Checking Bundlr balance"); // Check your balance const balance = await bundlr.getLoadedBalance(); - logger.debug('Current Bundlr balance', balance); + logger.debug("Current Bundlr balance", balance); // If balance is < 0.5 AR if (balance.isLessThan(5e11)) { - logger.debug('Funding Bundlr'); + logger.debug("Funding Bundlr"); // Fund your account with 0.5 AR //const fundResult = await bundlr.fund(5e11); //logger.debug("Fund result", fundResult); diff --git a/src/gateway/PgAdvisoryLocks.ts b/src/gateway/PgAdvisoryLocks.ts index 65391e40..4a632c1d 100644 --- a/src/gateway/PgAdvisoryLocks.ts +++ b/src/gateway/PgAdvisoryLocks.ts @@ -54,6 +54,7 @@ export class PgAdvisoryLocks { private async tryLock(lockId: number[], trx: Knex.Transaction): Promise { const benchmark = Benchmark.measure(); + await trx.raw(`SET LOCAL lock_timeout = '5s';`); const result = await trx.raw( `SELECT pg_try_advisory_xact_lock(?, ?);`, [lockId[0], lockId[1]] ); diff --git a/src/gateway/init.ts b/src/gateway/init.ts index e6954c08..75cccb54 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -15,7 +15,6 @@ import Arweave from 'arweave'; import gatewayRouter from './router/gatewayRouter'; import * as fs from 'fs'; import welcomeRouter from './router/welcomeRouter'; -import Bundlr from '@bundlr-network/client'; import { initBundlr } from '../bundlr/connect'; import { JWKInterface } from 'arweave/node/lib/wallet'; import { runNetworkInfoCacheTask } from './tasks/networkInfoCache'; @@ -27,7 +26,7 @@ import { EvmSignatureVerificationServerPlugin } from 'warp-signature/server'; import { DatabaseSource } from '../db/databaseSource'; import { accessLogMiddleware } from './accessLogMiddleware'; import { errorHandlerMiddleware } from './errorHandlerMiddleware'; - +import Irys from "@irys/sdk"; const argv = yargs(hideBin(process.argv)).parseSync(); const envPath = argv.env_path || '.secrets/prod.env'; const replica = (argv.replica as boolean) || false; @@ -47,7 +46,7 @@ export interface GatewayContext { sLogger: WarpLogger; accessLogger: WarpLogger; arweave: Arweave; - bundlr: Bundlr; + bundlr: Irys; jwk: JWKInterface; arweaveWrapper: ArweaveWrapper; arweaveWrapperGqlGoldsky: ArweaveWrapper; diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 417954e5..980d4e1b 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -11,14 +11,13 @@ import { WARP_TAGS, WarpLogger, } from 'warp-contracts'; -import Bundlr from '@bundlr-network/client'; import { isTxIdValid, parseFunctionName } from '../../../utils'; import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { VRF } from '../../init'; import { DataItem, serializeTags } from 'arbundles'; - +import Irys from "@irys/sdk"; const { Evaluate } = require('@idena/vrf-js'); export type VrfData = { @@ -388,7 +387,7 @@ async function prepareTags(logger: any, transaction: Transaction, originalOwner: export async function uploadToBundlr( transaction: Transaction, - bundlr: Bundlr, + bundlr: Irys, tags: GQLTagInterface[], logger: WarpLogger ) { @@ -396,7 +395,7 @@ export async function uploadToBundlr( const bTx = bundlr.createTransaction(JSON.stringify(transaction), { tags }); await bTx.sign(); - const bundlrResponse = await bundlr.uploader.uploadTransaction(bTx, { getReceiptSignature: true }); + const bundlrResponse = await bundlr.uploader.uploadTransaction(bTx); logger.debug('Uploading to bundlr', { elapsed: uploadBenchmark.elapsed(), diff --git a/yarn.lock b/yarn.lock index 0f04a117..978aa839 100644 --- a/yarn.lock +++ b/yarn.lock @@ -916,32 +916,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@bundlr-network/client@0.9.6": - version "0.9.6" - resolved "https://registry.yarnpkg.com/@bundlr-network/client/-/client-0.9.6.tgz#89464a697351aecb8071bbdb9f9b1a1e71a5fd60" - integrity sha512-4AhYsUAhqzpHxhGkgVpR2x7o5Kk+T8qxGba3wq/0kvMPnEGBdl1ramEN6B6cgdCGmgp5n+ov/hH5+q1sTvo9IQ== - dependencies: - "@solana/wallet-adapter-base" "^0.9.2" - "@solana/web3.js" "^1.36.0" - "@supercharge/promise-pool" "^2.1.0" - algosdk "^1.13.1" - aptos "^1.3.14" - arbundles "^0.7.0" - arweave "^1.11.4" - async-retry "^1.3.3" - axios "^0.25.0" - base64url "^3.0.1" - bignumber.js "^9.0.1" - bs58 "^4.0.1" - commander "^8.2.0" - csv "^6.0.5" - ethers "^5.5.1" - inquirer "^8.2.0" - js-sha256 "^0.9.0" - mime-types "^2.1.34" - near-api-js "^0.44.2" - near-seed-phrase "^0.2.0" - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -1057,7 +1031,7 @@ dependencies: "@ethersproject/bignumber" "^5.7.0" -"@ethersproject/contracts@5.7.0": +"@ethersproject/contracts@5.7.0", "@ethersproject/contracts@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== @@ -1346,6 +1320,56 @@ resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== +"@irys/arweave@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@irys/arweave/-/arweave-0.0.2.tgz#c0e73eb8c15e323342d33ea92701d4036fd22ae3" + integrity sha512-ddE5h4qXbl0xfGlxrtBIwzflaxZUDlDs43TuT0u1OMfyobHul4AA1VEX72Rpzw2bOh4vzoytSqA1jCM7x9YtHg== + dependencies: + asn1.js "^5.4.1" + async-retry "^1.3.3" + axios "^1.4.0" + base64-js "^1.5.1" + bignumber.js "^9.1.1" + +"@irys/query@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@irys/query/-/query-0.0.1.tgz#c0aa3eff9eef585d2b3d8d9e358b1c5942015414" + integrity sha512-7TCyR+Qn+F54IQQx5PlERgqNwgIQik8hY55iZl/silTHhCo1MI2pvx5BozqPUVCc8/KqRsc2nZd8Bc29XGUjRQ== + dependencies: + async-retry "^1.3.3" + axios "^1.4.0" + +"@irys/sdk@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@irys/sdk/-/sdk-0.1.1.tgz#c6ed31be5ffd5069db34f7d6c80b7c7a86f0b35b" + integrity sha512-GqyQX1HaXiHcux/VF9VlCX6yh+EQg4JqzqtCElq6BJZvnO7RasOsSjIq9Ie0NbdXXphEG/XP2saV5RR3zFKTIw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/contracts" "^5.7.0" + "@ethersproject/providers" "^5.7.2" + "@ethersproject/wallet" "^5.7.0" + "@irys/query" "^0.0.1" + "@near-js/crypto" "^0.0.3" + "@near-js/keystores-browser" "^0.0.3" + "@near-js/providers" "^0.0.4" + "@near-js/transactions" "^0.1.0" + "@solana/web3.js" "^1.36.0" + "@supercharge/promise-pool" "^3.0.0" + algosdk "^1.13.1" + aptos "=1.8.5" + arbundles "^0.10.0" + async-retry "^1.3.3" + axios "^1.4.0" + base64url "^3.0.1" + bignumber.js "^9.0.1" + bs58 "5.0.0" + commander "^8.2.0" + csv "5.5.3" + inquirer "^8.2.0" + js-sha256 "^0.9.0" + mime-types "^2.1.34" + near-seed-phrase "^0.2.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1636,6 +1660,142 @@ resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c" integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q== +"@near-js/crypto@0.0.3", "@near-js/crypto@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@near-js/crypto/-/crypto-0.0.3.tgz#4a33e526ab5fa75b703427067985694a279ff8bd" + integrity sha512-3WC2A1a1cH8Cqrx+0iDjp1ASEEhxN/KHEMENYb0KZH6Hp5bXIY7Akt4quC7JlgJS5ESvEiLa40tS5h0zAhBWGw== + dependencies: + "@near-js/types" "0.0.3" + bn.js "5.2.1" + borsh "^0.7.0" + tweetnacl "^1.0.1" + +"@near-js/crypto@0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-js/crypto/-/crypto-0.0.4.tgz#7bb991da25f06096de51466c6331cb185314fad8" + integrity sha512-2mSIVv6mZway1rQvmkktrXAFoUvy7POjrHNH3LekKZCMCs7qMM/23Hz2+APgxZPqoV2kjarSNOEYJjxO7zQ/rQ== + dependencies: + "@near-js/types" "0.0.4" + bn.js "5.2.1" + borsh "^0.7.0" + tweetnacl "^1.0.1" + +"@near-js/keystores-browser@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@near-js/keystores-browser/-/keystores-browser-0.0.3.tgz#110b847cd9c358076c2401e9462cc1140e12a908" + integrity sha512-Ve/JQ1SBxdNk3B49lElJ8Y54AoBY+yOStLvdnUIpe2FBOczzwDCkcnPcMDV0NMwVlHpEnOWICWHbRbAkI5Vs+A== + dependencies: + "@near-js/crypto" "0.0.3" + "@near-js/keystores" "0.0.3" + +"@near-js/keystores@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@near-js/keystores/-/keystores-0.0.3.tgz#eb1e8e06936da166b5ed8dab3123eaa1bf7a8dab" + integrity sha512-mnwLYUt4Td8u1I4QE1FBx2d9hMt3ofiriE93FfOluJ4XiqRqVFakFYiHg6pExg5iEkej/sXugBUFeQ4QizUnew== + dependencies: + "@near-js/crypto" "0.0.3" + "@near-js/types" "0.0.3" + +"@near-js/keystores@0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-js/keystores/-/keystores-0.0.4.tgz#da03069497bb14741a4d97f7ad4746baf9a09ea7" + integrity sha512-+vKafmDpQGrz5py1liot2hYSjPGXwihveeN+BL11aJlLqZnWBgYJUWCXG+uyGjGXZORuy2hzkKK6Hi+lbKOfVA== + dependencies: + "@near-js/crypto" "0.0.4" + "@near-js/types" "0.0.4" + +"@near-js/providers@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-js/providers/-/providers-0.0.4.tgz#90f84d765ff90370599d027f47c098a3e7e745d0" + integrity sha512-g/2pJTYmsIlTW4mGqeRlqDN9pZeN+1E2/wfoMIf3p++boBVxVlaSebtQgawXAf2lkfhb9RqXz5pHqewXIkTBSw== + dependencies: + "@near-js/transactions" "0.1.0" + "@near-js/types" "0.0.3" + "@near-js/utils" "0.0.3" + bn.js "5.2.1" + borsh "^0.7.0" + http-errors "^1.7.2" + optionalDependencies: + node-fetch "^2.6.1" + +"@near-js/signers@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@near-js/signers/-/signers-0.0.3.tgz#bfc8386613295fc6b51982cf65c79bdc9307aa5e" + integrity sha512-u1R+DDIua5PY1PDFnpVYqdMgQ7c4dyeZsfqMjE7CtgzdqupgTYCXzJjBubqMlAyAx843PoXmLt6CSSKcMm0WUA== + dependencies: + "@near-js/crypto" "0.0.3" + "@near-js/keystores" "0.0.3" + js-sha256 "^0.9.0" + +"@near-js/signers@0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-js/signers/-/signers-0.0.4.tgz#a1904ccc718d6f87b05cd2e168f33bde0cfb269a" + integrity sha512-xCglo3U/WIGsz/izPGFMegS5Q3PxOHYB8a1E7RtVhNm5QdqTlQldLCm/BuMg2G/u1l1ZZ0wdvkqRTG9joauf3Q== + dependencies: + "@near-js/crypto" "0.0.4" + "@near-js/keystores" "0.0.4" + js-sha256 "^0.9.0" + +"@near-js/transactions@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@near-js/transactions/-/transactions-0.1.0.tgz#a03f529da6bb2eaf9dd0590093f2d0763b8ae72a" + integrity sha512-OrrDFqhX0rtH+6MV3U3iS+zmzcPQI+L4GJi9na4Uf8FgpaVPF0mtSmVrpUrS5CC3LwWCzcYF833xGYbXOV4Kfg== + dependencies: + "@near-js/crypto" "0.0.3" + "@near-js/signers" "0.0.3" + "@near-js/types" "0.0.3" + "@near-js/utils" "0.0.3" + bn.js "5.2.1" + borsh "^0.7.0" + js-sha256 "^0.9.0" + +"@near-js/transactions@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@near-js/transactions/-/transactions-0.1.1.tgz#3d4c9d8e3cf2543642d660c0c0b126f0a97d5d43" + integrity sha512-Fk83oLLFK7nz4thawpdv9bGyMVQ2i48iUtZEVYhuuuqevl17tSXMlhle9Me1ZbNyguJG/cWPdNybe1UMKpyGxA== + dependencies: + "@near-js/crypto" "0.0.4" + "@near-js/signers" "0.0.4" + "@near-js/types" "0.0.4" + "@near-js/utils" "0.0.4" + bn.js "5.2.1" + borsh "^0.7.0" + js-sha256 "^0.9.0" + +"@near-js/types@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@near-js/types/-/types-0.0.3.tgz#d504222469f4d50a6299c522fb6905ba10905bd6" + integrity sha512-gC3iGUT+r2JjVsE31YharT+voat79ToMUMLCGozHjp/R/UW1M2z4hdpqTUoeWUBGBJuVc810gNTneHGx0jvzwQ== + dependencies: + bn.js "5.2.1" + +"@near-js/types@0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-js/types/-/types-0.0.4.tgz#d941689df41c850aeeeaeb9d498418acec515404" + integrity sha512-8TTMbLMnmyG06R5YKWuS/qFG1tOA3/9lX4NgBqQPsvaWmDsa+D+QwOkrEHDegped0ZHQwcjAXjKML1S1TyGYKg== + dependencies: + bn.js "5.2.1" + +"@near-js/utils@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@near-js/utils/-/utils-0.0.3.tgz#5e631f3dbdb7f0c6985bcbef08644db83b519978" + integrity sha512-J72n/EL0VfLRRb4xNUF4rmVrdzMkcmkwJOhBZSTWz3PAZ8LqNeU9ZConPfMvEr6lwdaD33ZuVv70DN6IIjPr1A== + dependencies: + "@near-js/types" "0.0.3" + bn.js "5.2.1" + depd "^2.0.0" + mustache "^4.0.0" + +"@near-js/utils@0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@near-js/utils/-/utils-0.0.4.tgz#1a387f81974ebbfa4521c92590232be97e3335dd" + integrity sha512-mPUEPJbTCMicGitjEGvQqOe8AS7O4KkRCxqd0xuE/X6gXF1jz1pYMZn4lNUeUz2C84YnVSGLAM0o9zcN6Y4hiA== + dependencies: + "@near-js/types" "0.0.4" + bn.js "5.2.1" + depd "^2.0.0" + mustache "^4.0.0" + "@noble/ed25519@^1.6.1", "@noble/ed25519@^1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.1.tgz#6899660f6fbb97798a6fbd227227c4589a454724" @@ -1718,13 +1878,6 @@ dependencies: buffer "~6.0.3" -"@solana/wallet-adapter-base@^0.9.2": - version "0.9.18" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.18.tgz#9365304a76977b4446a1167b240d588f2c5448d5" - integrity sha512-5HQFytLmb64j1Nzc6dwddZx+IUePN/PYqVMyf/ok7fN3z8Vw3EIFS8b+RFfBpj4HWbc2kqv5fpnLlaAH7q67pA== - dependencies: - eventemitter3 "^4.0.0" - "@solana/web3.js@^1.36.0": version "1.66.2" resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.66.2.tgz#80b43c5868b846124fe3ebac7d3943930c3fa60c" @@ -1746,10 +1899,10 @@ rpc-websockets "^7.5.0" superstruct "^0.14.2" -"@supercharge/promise-pool@^2.1.0": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@supercharge/promise-pool/-/promise-pool-2.3.2.tgz#6366894a7e7bc699bb65e58d8c828113729cf481" - integrity sha512-f5+C7zv+QQivcUO1FH5lXi7GcuJ3CFuJF3Eg06iArhUs5ma0szCLEQwIY4+VQyh7m/RLVZdzvr4E4ZDnLe9MNg== +"@supercharge/promise-pool@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@supercharge/promise-pool/-/promise-pool-3.1.0.tgz#308b9f4d4bf1d607695f916d9454a3556cd4c2b4" + integrity sha512-gB3NukbIcYzRtPoE6dx9svQYPodxvnfQlaaQd8N/z87E6WaMfRE7o5HwB+LZ+KeM0nsNAq1n4TmBtfz1VCUR+Q== "@tootallnate/once@1": version "1.1.2" @@ -2335,10 +2488,10 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -aptos@^1.3.13, aptos@^1.3.14: - version "1.3.17" - resolved "https://registry.yarnpkg.com/aptos/-/aptos-1.3.17.tgz#bdfb8ab9790b52abbeefd862721007b4d13c9302" - integrity sha512-SPgWR9D0nHwLNpvxH943T9ieA2/Q0AVVsvT/qTUuWQSImxkxMVkb++XyWhiFyQpnZDqo6o2o0/fZakeUkqrc8w== +aptos@=1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/aptos/-/aptos-1.8.5.tgz#a17ac721066914785902b03cf1e7304495f6cd9d" + integrity sha512-iQxliWesNHjGQ5YYXCyss9eg4+bDGQWqAZa73vprqGQ9tungK0cRjUI2fmnp63Ed6UG6rurHrL+b0ckbZAOZZQ== dependencies: "@noble/hashes" "1.1.3" "@scure/bip39" "1.1.0" @@ -2346,27 +2499,28 @@ aptos@^1.3.13, aptos@^1.3.14: form-data "4.0.0" tweetnacl "1.0.3" -arbundles@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/arbundles/-/arbundles-0.7.0.tgz#6378feae67cde2b61489d05932fc3833caea7040" - integrity sha512-VPrV4MP2PQyVnt140gv0zESQxdNKT1lhY8J+ngeS0DqLCCU964PBUK1W4lRcV6cMgdOwfY8RiFvNYz5mRoLSBQ== +arbundles@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/arbundles/-/arbundles-0.10.0.tgz#b3b0b86a3618bf5b967d2961647c3a4259cb6014" + integrity sha512-Prbkjb0RSR6ToXPaBFhsBiMYSq78vHWbG/Zzy1tALRGvnKYlNLq93cqtmCNHqaYP6YCBZZV05ZpbO5C6269saw== dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/providers" "^5.7.2" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wallet" "^5.7.0" + "@irys/arweave" "^0.0.2" "@noble/ed25519" "^1.6.1" - "@randlabs/myalgo-connect" "^1.1.2" - "@solana/wallet-adapter-base" "^0.9.2" - algosdk "^1.13.1" - aptos "^1.3.13" - arweave "^1.11.4" - arweave-stream-tx "^1.1.0" - avsc "https://github.com/Bundlr-Network/avsc#csp-fixes" - axios "^0.21.3" base64url "^3.0.1" bs58 "^4.0.1" - ethers "^5.5.1" keccak "^3.0.2" + secp256k1 "^5.0.0" + optionalDependencies: + "@randlabs/myalgo-connect" "^1.1.2" + algosdk "^1.13.1" + arweave-stream-tx "^1.1.0" multistream "^4.1.0" - process "^0.11.10" - secp256k1 "^4.0.2" tmp-promise "^3.0.2" arbundles@^0.9.6: @@ -2482,7 +2636,7 @@ arweave-stream-tx@^1.1.0: dependencies: exponential-backoff "^3.1.0" -arweave@1.11.6, arweave@^1.10.13, arweave@^1.11.4, arweave@^1.11.6: +arweave@1.11.6, arweave@^1.10.13, arweave@^1.11.6: version "1.11.6" resolved "https://registry.yarnpkg.com/arweave/-/arweave-1.11.6.tgz#5afcded201c6f123dd62e5bfae1b72ca793ec7c2" integrity sha512-D6N6e2z7oZoxFhu/qElLwQ2T8DxZ8xIqDB+Y16KHvZbassIrrS9iALwxLdaFYNInuyElg6i7qotBMcShWbFSTw== @@ -2594,10 +2748,6 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -"avsc@https://github.com/Bundlr-Network/avsc#csp-fixes": - version "5.4.7" - resolved "https://github.com/Bundlr-Network/avsc#a730cc8018b79e114b6a3381bbb57760a24c6cef" - axios@0.26.0: version "0.26.0" resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928" @@ -2613,20 +2763,6 @@ axios@0.27.2, axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axios@^0.21.3: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -axios@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a" - integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g== - dependencies: - follow-redirects "^1.14.7" - axios@^0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" @@ -2634,6 +2770,15 @@ axios@^0.26.1: dependencies: follow-redirects "^1.14.8" +axios@^1.4.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" + integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-jest@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" @@ -2707,6 +2852,11 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base-x@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" + integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== + base64-js@^1.0.2, base64-js@^1.2.0, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -2739,6 +2889,11 @@ bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.0.2: resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.0.tgz#8d340146107fe3a6cb8d40699643c302e8773b62" integrity sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A== +bignumber.js@^9.1.1: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -2778,30 +2933,16 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -bn.js@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@5.2.1, bn.js@^5.0.0, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== bn.js@^4.0.0, bn.js@^4.11.6, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -borsh@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.6.0.tgz#a7c9eeca6a31ca9e0607cb49f329cb659eb791e1" - integrity sha512-sl5k89ViqsThXQpYa9XDtz1sBl3l1lI313cFUY1HKr+wvMILnb+58xpkqTNrYbelh99dY7K8usxoCusQmqix9Q== - dependencies: - bn.js "^5.2.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - borsh@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" @@ -2880,6 +3021,13 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "2.x" +bs58@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== + dependencies: + base-x "^4.0.0" + bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" @@ -3011,11 +3159,6 @@ caniuse-lite@^1.0.30001400: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz#ec1ec1cfb0a93a34a0600d37903853030520a4e5" integrity sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA== -capability@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/capability/-/capability-0.2.5.tgz#51ad87353f1936ffd77f2f21c74633a4dea88801" - integrity sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg== - catering@^2.1.0, catering@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" @@ -3388,30 +3531,30 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csv-generate@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-4.2.1.tgz#2a0c5f0d9a5b6f7a0c1fee40f028707af048b31b" - integrity sha512-w6GFHjvApv6bcJ2xdi9JGsH6ZvUBfC+vUdfefnEzurXG6hMRwzkBLnhztU2H7v7+zfCk1I/knnQ+tGbgpxWrBw== +csv-generate@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-3.4.3.tgz#bc42d943b45aea52afa896874291da4b9108ffff" + integrity sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw== -csv-parse@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-5.3.2.tgz#a8ce2f8dec1b9c1013c9e73c6102fe0d2d436dbb" - integrity sha512-3jQ/JMs+voKxr4vwpmElS1d37J0o6rQdQyEKoPyA9HG8fYczpLaBJnmp5ykvkXL8ZeEGVP0qwLU645BZVykXKw== +csv-parse@^4.16.3: + version "4.16.3" + resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-4.16.3.tgz#7ca624d517212ebc520a36873c3478fa66efbaf7" + integrity sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg== -csv-stringify@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-6.2.2.tgz#3f398c79e14353f799c9d2583bafa06ebe68ac21" - integrity sha512-spGNdHxkAgoKk9ChAIR/k8JSFmvAyUQvODPUss5Djqgm/wBuU9qBRuGZ04LTAsGGnClQ8hD4TFz+hbBf1gpTMg== +csv-stringify@^5.6.5: + version "5.6.5" + resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-5.6.5.tgz#c6d74badda4b49a79bf4e72f91cce1e33b94de00" + integrity sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A== -csv@^6.0.5: - version "6.2.3" - resolved "https://registry.yarnpkg.com/csv/-/csv-6.2.3.tgz#4d78de93fc5a3ff4a93dc752c1cc2af781991905" - integrity sha512-LwpMgclTH2T386Ug/QgpJGtvWdQrg7ARO2BoYkevQ4H/zhiRCaDol4W2RyGoCSj+yKTeIf866mUnQAnmH0KhHA== +csv@5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/csv/-/csv-5.5.3.tgz#cd26c1e45eae00ce6a9b7b27dcb94955ec95207d" + integrity sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g== dependencies: - csv-generate "^4.2.1" - csv-parse "^5.3.2" - csv-stringify "^6.2.2" - stream-transform "^3.2.1" + csv-generate "^3.4.3" + csv-parse "^4.16.3" + csv-stringify "^5.6.5" + stream-transform "^2.1.3" data-urls@^2.0.0: version "2.0.0" @@ -3618,15 +3761,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error-polyfill@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/error-polyfill/-/error-polyfill-0.1.3.tgz#df848b61ad8834f7a5db69a70b9913df86721d15" - integrity sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg== - dependencies: - capability "^0.2.5" - o3 "^1.0.3" - u3 "^0.1.1" - es6-promise@^4.0.3: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -3808,7 +3942,7 @@ eth-rpc-errors@^4.0.2: dependencies: fast-safe-stringify "^2.0.6" -ethers@^5.5.1, ethers@^5.7.2: +ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -3844,7 +3978,7 @@ ethers@^5.5.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -eventemitter3@^4.0.0, eventemitter3@^4.0.7: +eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -4035,11 +4169,16 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -follow-redirects@^1.14.0, follow-redirects@^1.14.7, follow-redirects@^1.14.8, follow-redirects@^1.14.9: +follow-redirects@^1.14.8, follow-redirects@^1.14.9: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.15.0: + version "1.15.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" + integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -5610,6 +5749,11 @@ minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +mixme@^0.5.1: + version "0.5.10" + resolved "https://registry.yarnpkg.com/mixme/-/mixme-0.5.10.tgz#d653b2984b75d9018828f1ea333e51717ead5f51" + integrity sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q== + mocha@^8.1.2: version "8.4.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" @@ -5689,23 +5833,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -near-api-js@^0.44.2: - version "0.44.2" - resolved "https://registry.yarnpkg.com/near-api-js/-/near-api-js-0.44.2.tgz#e451f68f2c56bd885c7b918db5818a3e6e9423d0" - integrity sha512-eMnc4V+geggapEUa3nU2p8HSHn/njtloI4P2mceHQWO8vDE1NGpnAw8FuTBrLmXSgIv9m6oocgFc9t3VNf5zwg== - dependencies: - bn.js "5.2.0" - borsh "^0.6.0" - bs58 "^4.0.0" - depd "^2.0.0" - error-polyfill "^0.1.3" - http-errors "^1.7.2" - js-sha256 "^0.9.0" - mustache "^4.0.0" - node-fetch "^2.6.1" - text-encoding-utf-8 "^1.0.2" - tweetnacl "^1.0.1" - near-hd-key@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/near-hd-key/-/near-hd-key-1.2.1.tgz#f508ff15436cf8a439b543220f3cc72188a46756" @@ -5735,6 +5862,11 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + node-fetch@2, node-fetch@2.6.7, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -5779,13 +5911,6 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== -o3@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/o3/-/o3-1.0.3.tgz#192ce877a882dfa6751f0412a865fafb2da1dac0" - integrity sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ== - dependencies: - capability "^0.2.5" - object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" @@ -6128,11 +6253,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - progress@^2.0.0, progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -6146,6 +6266,11 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -6484,6 +6609,15 @@ secp256k1@^4.0.2: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" +secp256k1@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7" + integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^5.0.0" + node-gyp-build "^4.2.0" + semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" @@ -6607,10 +6741,12 @@ stream-buffers@^3.0.2: resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-3.0.2.tgz#5249005a8d5c2d00b3a32e6e0a6ea209dc4f3521" integrity sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ== -stream-transform@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-3.2.1.tgz#4c8cbdd3e4fa7254c770ef34a962cec68349fcb0" - integrity sha512-ApK+WTJ5bCOf0A2tlec1qhvr8bGEBM/sgXXB7mysdCYgZJO5DZeaV3h3G+g0HnAQ372P5IhiGqnW29zoLOfTzQ== +stream-transform@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-2.1.3.tgz#a1c3ecd72ddbf500aa8d342b0b9df38f5aa598e3" + integrity sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ== + dependencies: + mixme "^0.5.1" streamsearch@^1.1.0: version "1.1.0" @@ -6988,15 +7124,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998" - integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw== - -u3@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/u3/-/u3-0.1.1.tgz#5f52044f42ee76cd8de33148829e14528494b73b" - integrity sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w== +typescript@4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== undici@5.21.0: version "5.21.0" From 29721c216cef8ac1850481fbd5cfa08a9894a6ca Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 4 Dec 2023 12:27:57 +0100 Subject: [PATCH 78/95] contracts-by-source - add optional total interactions count (#192) --- .../router/routes/contracts/contractsBySourceRoute.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gateway/router/routes/contracts/contractsBySourceRoute.ts b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts index a9fa1395..2c76bcaa 100644 --- a/src/gateway/router/routes/contracts/contractsBySourceRoute.ts +++ b/src/gateway/router/routes/contracts/contractsBySourceRoute.ts @@ -8,7 +8,7 @@ const MAX_INTERACTIONS_PER_PAGE = 5000; export async function contractsBySourceRoute(ctx: Router.RouterContext) { const { logger, dbSource } = ctx; - const { id, page, limit, sort } = ctx.query; + const { id, page, limit, sort, totalInteractions } = ctx.query; const parsedPage = page ? parseInt(page as string) : 1; @@ -43,13 +43,21 @@ export async function contractsBySourceRoute(ctx: Router.RouterContext) { where src_tx_id = ? and type <> 'error') + ${totalInteractions == 'true' ? + `, interactions as (select c.contract_id, count(*) as interactions + from c + join interactions on interactions.contract_id = c.contract_id + group by c.contract_id)` : ''} + SELECT c.contract_id AS "contractId", c.owner AS "owner", c.bundler_contract_tx_id AS "bundlerTxId", c.block_height AS "blockHeight", c.block_timestamp AS "blockTimestamp", + ${totalInteractions ? 'coalesce(i.interactions, 0) AS "interactions",' : ''} coalesce(src.total, 0) AS "total" from c + ${totalInteractions ? 'LEFT JOIN interactions i ON c.contract_id = i.contract_id' : ''} LEFT JOIN src ON TRUE ${sort == 'desc' || sort == 'asc' ? `ORDER BY c.block_height ${sort.toUpperCase()}, c.contract_id` : ''}; `, From 579a662bdc741b7b36c1d319af23838f4222e877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szynwelski?= Date: Fri, 8 Dec 2023 08:18:19 +0100 Subject: [PATCH 79/95] sequencer node list --- src/gateway/router/routes/sequencerAddress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/router/routes/sequencerAddress.ts b/src/gateway/router/routes/sequencerAddress.ts index 214bcd9c..d35bc8a0 100644 --- a/src/gateway/router/routes/sequencerAddress.ts +++ b/src/gateway/router/routes/sequencerAddress.ts @@ -2,7 +2,7 @@ import Router from '@koa/router'; export async function sequencerAddressRoute(ctx: Router.RouterContext) { ctx.body = { - url: 'https://gw.warp.cc', + urls: ['https://gw.warp.cc'], type: 'centralized' }; } From b27a443bc054ba633a533844064b2c1afb6cf71c Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Thu, 21 Dec 2023 12:03:54 +0100 Subject: [PATCH 80/95] interactionsSortKeyRoute_v3 search starts from min sk --- src/gateway/router/gatewayRouter.ts | 2 + .../interactionsSortKeyRoute_v3.ts | 108 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/gateway/router/routes/interactions/interactionsSortKeyRoute_v3.ts diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 35fef8f4..34604fcf 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -18,6 +18,7 @@ import { contractDataRoute } from './routes/contracts/contractDataRoute'; import { nftsOwnedByAddressRoute } from './routes/nftsOwnedByAddressRoute'; import { txsPerDayRoute } from './routes/stats/txsPerDayRoute'; import { interactionsSortKeyRoute_v2 } from './routes/interactions/interactionsSortKeyRoute_v2'; +import { interactionsSortKeyRoute_v3 } from './routes/interactions/interactionsSortKeyRoute_v3'; import { contractSourceRoute } from './routes/contracts/contractSourceRoute'; import { contractsBySourceRoute } from './routes/contracts/contractsBySourceRoute'; import { creatorRoute } from './routes/creatorRoute'; @@ -49,6 +50,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/interactions-sonar', interactionsSonar); router.get('/interactions-sort-key', interactionsSortKeyRoute); router.get('/v2/interactions-sort-key', interactionsSortKeyRoute_v2); + router.get('/v3/interactions-sort-key', interactionsSortKeyRoute_v3); router.get('/interactions-stream', interactionsStreamRoute); router.get('/interactions/:id', interactionRoute); router.get('/stats', totalTxsRoute); diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v3.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v3.ts new file mode 100644 index 00000000..9bd1d7aa --- /dev/null +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute_v3.ts @@ -0,0 +1,108 @@ +import Router from '@koa/router'; + +const MAX_INTERACTIONS_PER_PAGE = 5000; + +export async function interactionsSortKeyRoute_v3(ctx: Router.RouterContext) { + const { dbSource, logger } = ctx; + + const { contractId, confirmationStatus, limit, from, to, totalCount, source, fromSdk } = ctx.query; + + const parsedLimit = limit + ? Math.min(parseInt(limit as string), MAX_INTERACTIONS_PER_PAGE) + : MAX_INTERACTIONS_PER_PAGE; + + const parsedConfirmationStatus = confirmationStatus + ? confirmationStatus == 'not_corrupted' + ? undefined // ['confirmed', 'not_processed'] + : [confirmationStatus] + : undefined; + + // 'isFromSdk' means that we're making a call from the SDK + // this affects: + // 1. the amount of returned data (we're trying to minimize amount of data in this case) + // 2. sorting order (SDK requires ASC order, SonAR requires DESC order) + const isFromSdk = fromSdk === 'true'; + + const bindings: any[] = []; + bindings.push(contractId); + bindings.push(contractId); + bindings.push(contractId); + // cannot use IN with bindings https://github.com/knex/knex/issues/791 + // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) + from && bindings.push(from as string); + to && bindings.push(to as string); + source && bindings.push(source as string); + bindings.push(parsedLimit); + + const query = ` + SELECT interaction, + confirmation_status, + sort_key + ${isFromSdk ? '' : ',confirming_peer, confirmations, bundler_tx_id '} + ${isFromSdk ? '' : ',count(*) OVER () AS total'} + FROM interactions + WHERE (contract_id = ? + OR interact_write @> ARRAY [?]) + AND sort_key >= COALESCE((SELECT min_sk FROM contracts_info WHERE contract_id = ?), '0') ${ + parsedConfirmationStatus + ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + : '' + } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} + ORDER BY sort_key ${isFromSdk ? 'ASC' : 'DESC'} + LIMIT ?; + `; + + const result: any = await dbSource.raw(query, bindings); + + const totalInteractions: any = + totalCount == 'true' && + (await dbSource.raw( + ` + SELECT count(case when confirmation_status = 'corrupted' then 1 else null end) AS corrupted, + count(case when confirmation_status = 'confirmed' then 1 else null end) AS confirmed, + count(case when confirmation_status = 'not_processed' then 1 else null end) AS not_processed, + count(case when confirmation_status = 'forked' then 1 else null end) AS forked + FROM interactions + WHERE contract_id = ?; + `, + contractId + )); + + const total = result?.rows?.length > 0 ? parseInt(result?.rows[0].total) : 0; + + const mappedInteractions = isFromSdk + ? result?.rows?.map((r: any) => ({ + ...r.interaction, + sortKey: r.sort_key, + confirmationStatus: r.confirmation_status, + })) + : result?.rows?.map((r: any) => ({ + status: r.confirmation_status, + confirming_peers: r.confirming_peer, + confirmations: r.confirmations, + interaction: { + ...r.interaction, + bundlerTxId: r.bundler_tx_id, + sortKey: r.sort_key, + }, + })); + + ctx.body = { + paging: { + total, + limit: parsedLimit, + items: result?.rows.length, + pages: Math.ceil(total / parsedLimit), + }, + ...(totalInteractions && { + total: { + confirmed: totalInteractions?.rows[0].confirmed, + corrupted: totalInteractions?.rows[0].corrupted, + not_processed: totalInteractions?.rows[0].not_processed, + forked: totalInteractions?.rows[0].forked, + }, + }), + // TODO: this mapping here is kinda dumb. + interactions: mappedInteractions, + }; +} From 018454dc9493cae8780959a9bd0cc1dfa5db8535 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 26 Dec 2023 10:54:23 +0100 Subject: [PATCH 81/95] block view --- src/gateway/router/routes/sequencerRoute.ts | 14 ++++++++++++++ src/gateway/router/routes/sequencerRoute_v2.ts | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 980d4e1b..f1d2092a 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -148,6 +148,9 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const parsedInput = JSON.parse(inputTag); const functionName = parseFunctionName(inputTag, sLogger); + + checkBlacklistedFunction(functionName, contractTag); + let evolve: string | null; evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; @@ -430,3 +433,14 @@ export async function createSortKey( return `${blockHeightString},${mills},${hashed}`; } + +export function checkBlacklistedFunction(functionName: string, contractTxId: string) { + const blacklistedFunctions: string[] = [ + "getAddress", "getCounter", "balance", "getBoost", "getRoulettePick", "getRouletteSwitch", "getRanking" + ]; + + if (contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' + && blacklistedFunctions.includes(functionName?.trim())) { + throw new Error("\"View\" function blacklisted"); + } +} diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 69ea9072..0a04642b 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -5,7 +5,7 @@ import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { DataItem } from 'arbundles'; -import { createInteraction, generateVrfTags, SequencerResult } from './sequencerRoute'; +import { checkBlacklistedFunction, createInteraction, generateVrfTags, SequencerResult } from "./sequencerRoute"; import { createSortKey } from './sequencerRoute'; import { tagsExceedLimit } from 'warp-arbundles'; import rawBody from 'raw-body'; @@ -156,6 +156,8 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const parsedInput = safeParse(input, sLogger); const functionName = parseFunctionName(input, sLogger); + checkBlacklistedFunction(functionName, contractTag); + let evolve: string | null; evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; const manifest = safeParse(data, sLogger)?.manifest || null; From d92eb7913bad470f46a8caf2a135d9e1e694005f Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Tue, 26 Dec 2023 11:25:02 +0100 Subject: [PATCH 82/95] whitelisted wallet --- src/gateway/router/routes/sequencerRoute.ts | 10 +++++++++- src/gateway/router/routes/sequencerRoute_v2.ts | 12 ++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index f1d2092a..491b1629 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -149,6 +149,7 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const parsedInput = JSON.parse(inputTag); const functionName = parseFunctionName(inputTag, sLogger); + checkWhitelistedWallet(originalAddress, contractTag); checkBlacklistedFunction(functionName, contractTag); let evolve: string | null; @@ -434,6 +435,13 @@ export async function createSortKey( return `${blockHeightString},${mills},${hashed}`; } +export function checkWhitelistedWallet(walletAddr: string, contractTxId: string) { + if (contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' + && walletAddr !== 'jnioZFibZSCcV8o-HkBXYPYEYNib4tqfexP0kCBXX_M') { + throw new Error(`Wallet blacklisted: ${walletAddr}`); + } +} + export function checkBlacklistedFunction(functionName: string, contractTxId: string) { const blacklistedFunctions: string[] = [ "getAddress", "getCounter", "balance", "getBoost", "getRoulettePick", "getRouletteSwitch", "getRanking" @@ -441,6 +449,6 @@ export function checkBlacklistedFunction(functionName: string, contractTxId: str if (contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' && blacklistedFunctions.includes(functionName?.trim())) { - throw new Error("\"View\" function blacklisted"); + throw new Error(`"View" function blacklisted: ${functionName}`); } } diff --git a/src/gateway/router/routes/sequencerRoute_v2.ts b/src/gateway/router/routes/sequencerRoute_v2.ts index 0a04642b..fba030b6 100644 --- a/src/gateway/router/routes/sequencerRoute_v2.ts +++ b/src/gateway/router/routes/sequencerRoute_v2.ts @@ -5,7 +5,13 @@ import { BUNDLR_NODE1_URL } from '../../../constants'; import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { DataItem } from 'arbundles'; -import { checkBlacklistedFunction, createInteraction, generateVrfTags, SequencerResult } from "./sequencerRoute"; +import { + checkBlacklistedFunction, + checkWhitelistedWallet, + createInteraction, + generateVrfTags, + SequencerResult +} from "./sequencerRoute"; import { createSortKey } from './sequencerRoute'; import { tagsExceedLimit } from 'warp-arbundles'; import rawBody from 'raw-body'; @@ -156,8 +162,10 @@ async function doGenerateSequence(ctx: Router.RouterContext, trx: Knex.Transacti const parsedInput = safeParse(input, sLogger); const functionName = parseFunctionName(input, sLogger); + + checkWhitelistedWallet(originalAddress, contractTag); checkBlacklistedFunction(functionName, contractTag); - + let evolve: string | null; evolve = functionName == 'evolve' && parsedInput.value && isTxIdValid(parsedInput.value) ? parsedInput.value : null; const manifest = safeParse(data, sLogger)?.manifest || null; From 606d79ddd30c422ed9e5680b98e50f649e93b2da Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Thu, 29 Feb 2024 09:56:38 +0100 Subject: [PATCH 83/95] chore: remove 2nd redis publisher --- src/gateway/init.ts | 30 ------------------------------ src/gateway/publisher.ts | 2 -- 2 files changed, 32 deletions(-) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 75cccb54..f27819f7 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -53,7 +53,6 @@ export interface GatewayContext { vrf: VRF; sorter: LexicographicalInteractionsSorter; publisher: Redis; - publisher_v2: Redis; pgAdvisoryLocks: PgAdvisoryLocks; env: EnvType; appSync?: string; @@ -214,35 +213,6 @@ export interface GatewayContext { }); app.context.publisher = publisher; } - - // temporary.. - const connectionOptions2 = readGwPubSubConfig('gw-pubsub_2.json'); - if (connectionOptions2) { - console.log({ - ...connectionOptions2, - tls: { - ca: [process.env.GW_TLS_CA_CERT], - checkServerIdentity: () => { - return null; - }, - }, - }); - const publisher2 = new Redis({ - ...connectionOptions2, - tls: { - ca: [process.env.GW_TLS_CA_CERT], - checkServerIdentity: () => { - return null; - }, - }, - }); - await publisher2.connect(); - logger.info(`Publisher 2 status`, { - host: connectionOptions2.host, - status: publisher2.status, - }); - app.context.publisher_v2 = publisher2; - } } await runNetworkInfoCacheTask(app.context); } diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index ae6852f3..0397829b 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -43,8 +43,6 @@ export function sendNotification( ctx.publisher.publish(contractsChannel, stringified); logger.debug(`Published ${contractsChannel}`); - ctx.publisher_v2.publish(contractsChannel, stringified); - logger.debug(`Published v2 ${contractsChannel}`); } catch (e) { logger.error('Error while publishing message', e); } From 6cc57f029b6134c3462545b20cd213ae2d46e7ad Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Fri, 22 Mar 2024 14:25:27 +0100 Subject: [PATCH 84/95] Revert "chore: remove 2nd redis publisher" This reverts commit 606d79ddd30c422ed9e5680b98e50f649e93b2da. --- src/gateway/init.ts | 30 ++++++++++++++++++++++++++++++ src/gateway/publisher.ts | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index f27819f7..75cccb54 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -53,6 +53,7 @@ export interface GatewayContext { vrf: VRF; sorter: LexicographicalInteractionsSorter; publisher: Redis; + publisher_v2: Redis; pgAdvisoryLocks: PgAdvisoryLocks; env: EnvType; appSync?: string; @@ -213,6 +214,35 @@ export interface GatewayContext { }); app.context.publisher = publisher; } + + // temporary.. + const connectionOptions2 = readGwPubSubConfig('gw-pubsub_2.json'); + if (connectionOptions2) { + console.log({ + ...connectionOptions2, + tls: { + ca: [process.env.GW_TLS_CA_CERT], + checkServerIdentity: () => { + return null; + }, + }, + }); + const publisher2 = new Redis({ + ...connectionOptions2, + tls: { + ca: [process.env.GW_TLS_CA_CERT], + checkServerIdentity: () => { + return null; + }, + }, + }); + await publisher2.connect(); + logger.info(`Publisher 2 status`, { + host: connectionOptions2.host, + status: publisher2.status, + }); + app.context.publisher_v2 = publisher2; + } } await runNetworkInfoCacheTask(app.context); } diff --git a/src/gateway/publisher.ts b/src/gateway/publisher.ts index 0397829b..ae6852f3 100644 --- a/src/gateway/publisher.ts +++ b/src/gateway/publisher.ts @@ -43,6 +43,8 @@ export function sendNotification( ctx.publisher.publish(contractsChannel, stringified); logger.debug(`Published ${contractsChannel}`); + ctx.publisher_v2.publish(contractsChannel, stringified); + logger.debug(`Published v2 ${contractsChannel}`); } catch (e) { logger.error('Error while publishing message', e); } From 98f41de1b50bc6f47f17d09eed8d81d2e4660583 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 20 May 2024 15:20:52 +0200 Subject: [PATCH 85/95] fix: set env in app's context --- src/gateway/init.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gateway/init.ts b/src/gateway/init.ts index 75cccb54..a0f1b4a6 100644 --- a/src/gateway/init.ts +++ b/src/gateway/init.ts @@ -163,6 +163,7 @@ export interface GatewayContext { app.context.appSync = appSync; app.context.signatureVerification = new EvmSignatureVerificationServerPlugin(); app.context.replica = replica; + app.context.env = env as EnvType; app.use(errorHandlerMiddleware); app.use(accessLogMiddleware); From 55ae1c960280f49e5a9a19d8b0c61ec00e53eff8 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 1 Jul 2024 11:29:15 +0200 Subject: [PATCH 86/95] Warpy - registration date --- src/gateway/router/gatewayRouter.ts | 6 +++-- .../router/routes/warpy/registrationDate.ts | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/gateway/router/routes/warpy/registrationDate.ts diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 34604fcf..636b4700 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -7,7 +7,7 @@ import { contractRoute } from './routes/contracts/contractRoute'; import { contractWithSourceRoute } from './routes/contracts/contractWithSourceRoute'; import { contractWithSourceRoute_v2 } from './routes/contracts/contractWithSourceRoute_v2'; import { interactionRoute } from './routes/interactions/interactionRoute'; -import { sequencerAddressRoute } from './routes/sequencerAddress' +import { sequencerAddressRoute } from './routes/sequencerAddress'; import { sequencerRoute } from './routes/sequencerRoute'; import { sequencerRoute_v2 } from './routes/sequencerRoute_v2'; import { interactionsStreamRoute } from './routes/interactions/interactionsStreamRoute'; @@ -31,6 +31,7 @@ import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; import { gcpAliveRoute } from './routes/gcpAliveRoute'; import { contractsByTags } from './routes/contracts/contractsByTags'; +import { registrationDate } from './routes/warpy/registrationDate'; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -61,8 +62,9 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/contracts-by-source', contractsBySourceRoute); router.get('/creator', creatorRoute); router.get('/gcp/alive', gcpAliveRoute); - router.get('/sequencer/address', sequencerAddressRoute) + router.get('/sequencer/address', sequencerAddressRoute); router.get('/contracts-by-tags', contractsByTags); + router.get('/warpy/registration-date', registrationDate); // post if (!replica) { diff --git a/src/gateway/router/routes/warpy/registrationDate.ts b/src/gateway/router/routes/warpy/registrationDate.ts new file mode 100644 index 00000000..242a1b45 --- /dev/null +++ b/src/gateway/router/routes/warpy/registrationDate.ts @@ -0,0 +1,27 @@ +import Router from '@koa/router'; +import { Benchmark } from 'warp-contracts'; + +export async function registrationDate(ctx: Router.RouterContext) { + const { logger, dbSource } = ctx; + + const { contractId, userId } = ctx.query; + + const bindings: any[] = []; + bindings.push(contractId); + bindings.push(userId); + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + `select sync_timestamp + from interactions, + jsonb_array_elements(interaction -> 'tags') tags + where contract_id = ? and function = 'registerUser' + and tags ->> 'name' = 'Input' + and (tags ->> 'value')::jsonb ->> 'id' = ?;`, + bindings + ); + + ctx.body = result.rows[0].sync_timestamp; + + logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); +} From 7e4359fc55a64f2f1b566ea15d959ec6b4cdb9ce Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 1 Jul 2024 12:02:51 +0200 Subject: [PATCH 87/95] Warpy - registration date, null when not found --- src/gateway/router/routes/warpy/registrationDate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateway/router/routes/warpy/registrationDate.ts b/src/gateway/router/routes/warpy/registrationDate.ts index 242a1b45..ccd16fdb 100644 --- a/src/gateway/router/routes/warpy/registrationDate.ts +++ b/src/gateway/router/routes/warpy/registrationDate.ts @@ -21,7 +21,7 @@ export async function registrationDate(ctx: Router.RouterContext) { bindings ); - ctx.body = result.rows[0].sync_timestamp; + ctx.body = result.rows[0]?.sync_timestamp; logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); } From 6ace18a228832f9be04973c73b543300d51e6217 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 1 Jul 2024 12:07:29 +0200 Subject: [PATCH 88/95] Warpy - registration date, name result --- src/gateway/router/routes/warpy/registrationDate.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gateway/router/routes/warpy/registrationDate.ts b/src/gateway/router/routes/warpy/registrationDate.ts index ccd16fdb..610e192d 100644 --- a/src/gateway/router/routes/warpy/registrationDate.ts +++ b/src/gateway/router/routes/warpy/registrationDate.ts @@ -21,7 +21,9 @@ export async function registrationDate(ctx: Router.RouterContext) { bindings ); - ctx.body = result.rows[0]?.sync_timestamp; + ctx.body = { + date: result.rows[0]?.sync_timestamp, + }; logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); } From 248611865ba75a9d5a9bf2e635569b7ccf25c3a7 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 1 Jul 2024 15:09:34 +0200 Subject: [PATCH 89/95] Warpy - joinSeason2 endpoint --- src/gateway/router/gatewayRouter.ts | 4 +- .../router/routes/warpy/joinSeason2.ts | 39 +++++++++++++++++++ .../router/routes/warpy/registrationDate.ts | 29 -------------- 3 files changed, 41 insertions(+), 31 deletions(-) create mode 100644 src/gateway/router/routes/warpy/joinSeason2.ts delete mode 100644 src/gateway/router/routes/warpy/registrationDate.ts diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 636b4700..6e7b13b4 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -31,7 +31,7 @@ import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; import { gcpAliveRoute } from './routes/gcpAliveRoute'; import { contractsByTags } from './routes/contracts/contractsByTags'; -import { registrationDate } from './routes/warpy/registrationDate'; +import { joinSeason2 } from './routes/warpy/joinSeason2'; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -64,7 +64,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/gcp/alive', gcpAliveRoute); router.get('/sequencer/address', sequencerAddressRoute); router.get('/contracts-by-tags', contractsByTags); - router.get('/warpy/registration-date', registrationDate); + router.get('/warpy/join-season-2', joinSeason2); // post if (!replica) { diff --git a/src/gateway/router/routes/warpy/joinSeason2.ts b/src/gateway/router/routes/warpy/joinSeason2.ts new file mode 100644 index 00000000..9710ca47 --- /dev/null +++ b/src/gateway/router/routes/warpy/joinSeason2.ts @@ -0,0 +1,39 @@ +import Router from '@koa/router'; +import { Benchmark } from 'warp-contracts'; + +export async function joinSeason2(ctx: Router.RouterContext) { + const { logger, dbSource } = ctx; + + const { contractId, userId } = ctx.query; + + const benchmark = Benchmark.measure(); + const result: any = await dbSource.raw( + `select id, max(joined::int)::boolean as joined, max(timestamp) as timestamp from( + with joined_table as ( + select interaction_id, interaction + from interactions, + jsonb_array_elements(interaction -> 'tags') tags + where contract_id = ${contractId} and function = 'addPoints' + and tags ->> 'name' = 'Reward-For' and tags ->> 'value' = 'Join-Season-2' + ) + select ${userId} as id, true as joined, null as timestamp + from joined_table, jsonb_array_elements(interaction -> 'tags') as tags, jsonb_array_elements((tags ->> 'value')::jsonb -> 'members') as members + where tags ->> 'name' = 'Input' + and members::jsonb ->> 'id' = ${userId} + union ALL + select ${userId} as id, null as joined, sync_timestamp as timestamp + from interactions, + jsonb_array_elements(interaction -> 'tags') tags + where contract_id = ${contractId} and function = 'registerUser' + and tags ->> 'name' = 'Input' + and (tags ->> 'value')::jsonb ->> 'id' = ${userId} + ) jt + group by id;` + ); + + ctx.body = { + date: result.rows[0]?.sync_timestamp, + }; + + logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); +} diff --git a/src/gateway/router/routes/warpy/registrationDate.ts b/src/gateway/router/routes/warpy/registrationDate.ts deleted file mode 100644 index 610e192d..00000000 --- a/src/gateway/router/routes/warpy/registrationDate.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Router from '@koa/router'; -import { Benchmark } from 'warp-contracts'; - -export async function registrationDate(ctx: Router.RouterContext) { - const { logger, dbSource } = ctx; - - const { contractId, userId } = ctx.query; - - const bindings: any[] = []; - bindings.push(contractId); - bindings.push(userId); - - const benchmark = Benchmark.measure(); - const result: any = await dbSource.raw( - `select sync_timestamp - from interactions, - jsonb_array_elements(interaction -> 'tags') tags - where contract_id = ? and function = 'registerUser' - and tags ->> 'name' = 'Input' - and (tags ->> 'value')::jsonb ->> 'id' = ?;`, - bindings - ); - - ctx.body = { - date: result.rows[0]?.sync_timestamp, - }; - - logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); -} From ddeeee8c920f696b79b63ecad8e993e28df98129 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 1 Jul 2024 15:20:50 +0200 Subject: [PATCH 90/95] Warpy - joinSeason2 with left join --- .../router/routes/warpy/joinSeason2.ts | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/gateway/router/routes/warpy/joinSeason2.ts b/src/gateway/router/routes/warpy/joinSeason2.ts index 9710ca47..929eff72 100644 --- a/src/gateway/router/routes/warpy/joinSeason2.ts +++ b/src/gateway/router/routes/warpy/joinSeason2.ts @@ -8,31 +8,35 @@ export async function joinSeason2(ctx: Router.RouterContext) { const benchmark = Benchmark.measure(); const result: any = await dbSource.raw( - `select id, max(joined::int)::boolean as joined, max(timestamp) as timestamp from( - with joined_table as ( + `with joined_table as ( select interaction_id, interaction - from interactions, - jsonb_array_elements(interaction -> 'tags') tags - where contract_id = ${contractId} and function = 'addPoints' - and tags ->> 'name' = 'Reward-For' and tags ->> 'value' = 'Join-Season-2' + from interactions, + jsonb_array_elements(interaction -> 'tags') tags + where contract_id = '${contractId}' and function = 'addPoints' + and tags ->> 'name' = 'Reward-For' and tags ->> 'value' = 'Join-Season-2' + ), + joined_table_res as ( + select true as joined + from joined_table, jsonb_array_elements(interaction -> 'tags') as tags, jsonb_array_elements((tags ->> 'value')::jsonb -> 'members') as members + where tags ->> 'name' = 'Input' + and members::jsonb ->> 'id' = '${userId}' + ), + registration_table as ( + select '${userId}' as id, sync_timestamp as timestamp + from interactions, + jsonb_array_elements(interaction -> 'tags') tags + where contract_id = '${contractId}' and function = 'registerUser' + and tags ->> 'name' = 'Input' + and (tags ->> 'value')::jsonb ->> 'id' = '${userId}' ) - select ${userId} as id, true as joined, null as timestamp - from joined_table, jsonb_array_elements(interaction -> 'tags') as tags, jsonb_array_elements((tags ->> 'value')::jsonb -> 'members') as members - where tags ->> 'name' = 'Input' - and members::jsonb ->> 'id' = ${userId} - union ALL - select ${userId} as id, null as joined, sync_timestamp as timestamp - from interactions, - jsonb_array_elements(interaction -> 'tags') tags - where contract_id = ${contractId} and function = 'registerUser' - and tags ->> 'name' = 'Input' - and (tags ->> 'value')::jsonb ->> 'id' = ${userId} - ) jt - group by id;` + select * from registration_table left join joined_table_res on true;` ); + const { id, joined, timestamp } = result.rows[0]; ctx.body = { - date: result.rows[0]?.sync_timestamp, + id, + joined, + timestamp, }; logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); From 3733813bf06bca4ae9225a87a650a8ba6278c1e8 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 1 Jul 2024 15:24:24 +0200 Subject: [PATCH 91/95] Warpy - joinSeason2 res fix --- src/gateway/router/routes/warpy/joinSeason2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gateway/router/routes/warpy/joinSeason2.ts b/src/gateway/router/routes/warpy/joinSeason2.ts index 929eff72..e0575f57 100644 --- a/src/gateway/router/routes/warpy/joinSeason2.ts +++ b/src/gateway/router/routes/warpy/joinSeason2.ts @@ -32,11 +32,11 @@ export async function joinSeason2(ctx: Router.RouterContext) { select * from registration_table left join joined_table_res on true;` ); - const { id, joined, timestamp } = result.rows[0]; + const joinSeason2Result = result.rows[0]; ctx.body = { - id, - joined, - timestamp, + id: joinSeason2Result?.id, + joined: joinSeason2Result?.joined, + timestamp: joinSeason2Result?.timestamp, }; logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`); From c38cd79f40fb657f5a2691f852cf4668fe0b0a67 Mon Sep 17 00:00:00 2001 From: Asia Date: Tue, 6 Aug 2024 11:58:32 +0200 Subject: [PATCH 92/95] add new wallet to the whitelist --- src/gateway/router/routes/sequencerRoute.ts | 23 +++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 491b1629..33fd68a7 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -17,7 +17,7 @@ import { Knex } from 'knex'; import { GatewayError } from '../../errorHandlerMiddleware'; import { VRF } from '../../init'; import { DataItem, serializeTags } from 'arbundles'; -import Irys from "@irys/sdk"; +import Irys from '@irys/sdk'; const { Evaluate } = require('@idena/vrf-js'); export type VrfData = { @@ -436,19 +436,30 @@ export async function createSortKey( } export function checkWhitelistedWallet(walletAddr: string, contractTxId: string) { - if (contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' - && walletAddr !== 'jnioZFibZSCcV8o-HkBXYPYEYNib4tqfexP0kCBXX_M') { + if ( + contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' && + walletAddr !== 'jnioZFibZSCcV8o-HkBXYPYEYNib4tqfexP0kCBXX_M' && + walletAddr !== 'ESCLmn6txFGgK-XO2U6svB1543n2SoGTB29Aptnj9v0' + ) { throw new Error(`Wallet blacklisted: ${walletAddr}`); } } export function checkBlacklistedFunction(functionName: string, contractTxId: string) { const blacklistedFunctions: string[] = [ - "getAddress", "getCounter", "balance", "getBoost", "getRoulettePick", "getRouletteSwitch", "getRanking" + 'getAddress', + 'getCounter', + 'balance', + 'getBoost', + 'getRoulettePick', + 'getRouletteSwitch', + 'getRanking', ]; - if (contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' - && blacklistedFunctions.includes(functionName?.trim())) { + if ( + contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' && + blacklistedFunctions.includes(functionName?.trim()) + ) { throw new Error(`"View" function blacklisted: ${functionName}`); } } From b595bb5897888cffaf5456d62dcfc8cbc3071325 Mon Sep 17 00:00:00 2001 From: Asia Date: Tue, 6 Aug 2024 13:04:27 +0200 Subject: [PATCH 93/95] remove wallet from whitelist --- src/gateway/router/routes/sequencerRoute.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gateway/router/routes/sequencerRoute.ts b/src/gateway/router/routes/sequencerRoute.ts index 33fd68a7..17be0471 100644 --- a/src/gateway/router/routes/sequencerRoute.ts +++ b/src/gateway/router/routes/sequencerRoute.ts @@ -438,7 +438,6 @@ export async function createSortKey( export function checkWhitelistedWallet(walletAddr: string, contractTxId: string) { if ( contractTxId === 'p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU' && - walletAddr !== 'jnioZFibZSCcV8o-HkBXYPYEYNib4tqfexP0kCBXX_M' && walletAddr !== 'ESCLmn6txFGgK-XO2U6svB1543n2SoGTB29Aptnj9v0' ) { throw new Error(`Wallet blacklisted: ${walletAddr}`); From 341b734eb33958c55bc5431de9f61f89fda093ae Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Fri, 27 Sep 2024 12:03:24 +0200 Subject: [PATCH 94/95] sql injection fix for v1 interactions --- .../routes/interactions/interactionsSortKeyRoute.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts b/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts index db0adfa5..ebc0d451 100644 --- a/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts +++ b/src/gateway/router/routes/interactions/interactionsSortKeyRoute.ts @@ -31,7 +31,7 @@ export async function interactionsSortKeyRoute(ctx: Router.RouterContext) { bindings.push(contractId); bindings.push(contractId); // cannot use IN with bindings https://github.com/knex/knex/issues/791 - // parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) + parsedConfirmationStatus && bindings.push(parsedConfirmationStatus) from && bindings.push(from as string); to && bindings.push(to as string); source && bindings.push(source as string); @@ -48,9 +48,12 @@ export async function interactionsSortKeyRoute(ctx: Router.RouterContext) { WHERE (contract_id = ? OR interact_write @> ARRAY [?]) ${ parsedConfirmationStatus - ? ` AND confirmation_status IN (${parsedConfirmationStatus.map((status) => `'${status}'`).join(', ')})` + ? ` AND confirmation_status IN (` + parsedConfirmationStatus.map((_) => '?').join(',') + `) ` : '' - } ${from ? ' AND sort_key > ?' : ''} ${to ? ' AND sort_key <= ?' : ''} ${source ? `AND source = ?` : ''} + } + ${from ? ' AND sort_key > ?' : ''} + ${to ? ' AND sort_key <= ?' : ''} + ${source ? `AND source = ?` : ''} ORDER BY sort_key ${shouldMinimize ? 'ASC' : 'DESC'} ${parsedPage ? ' LIMIT ? OFFSET ?' : ''}; `; From 1a2594e2c36d50f3c5b3daecf71952f660d07d69 Mon Sep 17 00:00:00 2001 From: Asia Date: Mon, 25 Nov 2024 13:56:31 +0100 Subject: [PATCH 95/95] Warpy - join-season-3 --- src/gateway/router/gatewayRouter.ts | 4 ++-- .../routes/warpy/{joinSeason2.ts => joinSeason3.ts} | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) rename src/gateway/router/routes/warpy/{joinSeason2.ts => joinSeason3.ts} (85%) diff --git a/src/gateway/router/gatewayRouter.ts b/src/gateway/router/gatewayRouter.ts index 6e7b13b4..3971e610 100644 --- a/src/gateway/router/gatewayRouter.ts +++ b/src/gateway/router/gatewayRouter.ts @@ -31,7 +31,7 @@ import { registerContractRoute } from './routes/deploy/registerContractRoute'; import { dashboardRoute } from './routes/dashboardRoute'; import { gcpAliveRoute } from './routes/gcpAliveRoute'; import { contractsByTags } from './routes/contracts/contractsByTags'; -import { joinSeason2 } from './routes/warpy/joinSeason2'; +import { joinSeason3 } from './routes/warpy/joinSeason3'; const gatewayRouter = (replica: boolean): Router => { const router = new Router({ prefix: '/gateway' }); @@ -64,7 +64,7 @@ const gatewayRouter = (replica: boolean): Router => { router.get('/gcp/alive', gcpAliveRoute); router.get('/sequencer/address', sequencerAddressRoute); router.get('/contracts-by-tags', contractsByTags); - router.get('/warpy/join-season-2', joinSeason2); + router.get('/warpy/join-season-3', joinSeason3); // post if (!replica) { diff --git a/src/gateway/router/routes/warpy/joinSeason2.ts b/src/gateway/router/routes/warpy/joinSeason3.ts similarity index 85% rename from src/gateway/router/routes/warpy/joinSeason2.ts rename to src/gateway/router/routes/warpy/joinSeason3.ts index e0575f57..e6733407 100644 --- a/src/gateway/router/routes/warpy/joinSeason2.ts +++ b/src/gateway/router/routes/warpy/joinSeason3.ts @@ -1,7 +1,7 @@ import Router from '@koa/router'; import { Benchmark } from 'warp-contracts'; -export async function joinSeason2(ctx: Router.RouterContext) { +export async function joinSeason3(ctx: Router.RouterContext) { const { logger, dbSource } = ctx; const { contractId, userId } = ctx.query; @@ -13,7 +13,7 @@ export async function joinSeason2(ctx: Router.RouterContext) { from interactions, jsonb_array_elements(interaction -> 'tags') tags where contract_id = '${contractId}' and function = 'addPoints' - and tags ->> 'name' = 'Reward-For' and tags ->> 'value' = 'Join-Season-2' + and tags ->> 'name' = 'Reward-For' and tags ->> 'value' = 'Join-Season-3' ), joined_table_res as ( select true as joined @@ -32,11 +32,11 @@ export async function joinSeason2(ctx: Router.RouterContext) { select * from registration_table left join joined_table_res on true;` ); - const joinSeason2Result = result.rows[0]; + const joinSeason3Result = result.rows[0]; ctx.body = { - id: joinSeason2Result?.id, - joined: joinSeason2Result?.joined, - timestamp: joinSeason2Result?.timestamp, + id: joinSeason3Result?.id, + joined: joinSeason3Result?.joined, + timestamp: joinSeason3Result?.timestamp, }; logger.debug(`User's registration date loaded in ${benchmark.elapsed()}`);