diff --git a/modules/test-runner/src/load/helpers/dockerNodeConfig.ts b/modules/test-runner/src/load/helpers/dockerNodeConfig.ts new file mode 100644 index 000000000..1edbf63bb --- /dev/null +++ b/modules/test-runner/src/load/helpers/dockerNodeConfig.ts @@ -0,0 +1,351 @@ +const router_server_config = { + internal_port:"9002", + public_port:"9002", + public_url:`http://127.0.0.1:9002/ping`, + +} + +export const messaging_config = +`version: '3.4' + +secrets: + vector_jwt_public_key: + external: true + vector_jwt_private_key: + external: true + +networks: + vector: + external: true + +volumes: + certs: + +services: + + auth: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '100m' + image: 'vector_builder:latest' + entrypoint: 'bash modules/auth/ops/entry.sh' + ports: + - '5040:5040' + volumes: + - '/home/z/Development/vector:/app' + environment: + VECTOR_JWT_SIGNER_PUBLIC_KEY_FILE: '/run/secrets/vector_jwt_public_key' + VECTOR_JWT_SIGNER_PRIVATE_KEY_FILE: '/run/secrets/vector_jwt_private_key' + VECTOR_NATS_URL: 'nats://nats:4222' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PORT: '5040' + VECTOR_PROD: 'false' + secrets: + - 'vector_jwt_private_key' + - 'vector_jwt_public_key' + + nats: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '100m' + image: 'vector_nats:latest' + environment: + JWT_SIGNER_PUBLIC_KEY_FILE: '/run/secrets/vector_jwt_public_key' + secrets: + - 'vector_jwt_public_key' + ports: + - '4222:4222' + - '4221:4221' +` +export const node_config_json:string = + `{ + "adminToken": "cxt1234", + "chainAddresses": { + "1337": { + "channelFactoryAddress": "0x345cA3e014Aaf5dcA488057592ee47305D9B3e10", + "testTokenAddress": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", + "transferRegistryAddress": "0x9FBDa871d559710256a2502A2517b794B482Db40" + }, + "1338": { + "channelFactoryAddress": "0x345cA3e014Aaf5dcA488057592ee47305D9B3e10", + "testTokenAddress": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", + "transferRegistryAddress": "0x9FBDa871d559710256a2502A2517b794B482Db40" + } + }, + "chainProviders": { + "1337": "http://evm_1337:8545", + "1338": "http://evm_1338:8545" + }, + "logLevel": "info", + "messagingUrl": "", + "authUrl": "172.17.0.1:4222", + "natsUrl":"172.17.0.1:4221", + "production": false +} +` + +export const router_config:string = `{ + "allowedSwaps": [ + { + "fromChainId": 1337, + "toChainId": 1338, + "fromAssetId": "0x0000000000000000000000000000000000000000", + "toAssetId": "0x0000000000000000000000000000000000000000", + "priceType": "hardcoded", + "hardcodedRate": "1" + }, + { + "fromChainId": 1337, + "toChainId": 1338, + "fromAssetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", + "toAssetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", + "priceType": "hardcoded", + "hardcodedRate": "1" + } + ], + "messagingUrl": "", + "production": false, + "rebalanceProfiles": [ + { + "chainId": 1337, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "200000000000000000", + "target": "100000000000000000", + "collateralizeThreshold": "50000000000000000" + }, + { + "chainId": 1338, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "200000000000000000", + "target": "100000000000000000", + "collateralizeThreshold": "50000000000000000" + }, + { + "chainId": 1337, + "assetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", + "reclaimThreshold": "2000000000000000000", + "target": "1000000000000000000", + "collateralizeThreshold": "500000000000000000" + }, + { + "chainId": 1338, + "assetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", + "reclaimThreshold": "2000000000000000000", + "target": "1000000000000000000", + "collateralizeThreshold": "500000000000000000" + } + ] +} +` +const eth_mnemonic = 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat' + +const router_image_name = "vector_builder:0.2.2-beta.2" + +export const pull_router_image_opts = ["./ops/pull-images.sh", `${router_image_name}`, '> /dev/null'] + + +// const msg_url = `{ adminToken: cxt1234, chainAddresses: { 1337: { channelFactoryAddress: 0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da, testTokenAddress: 0x9FBDa871d559710256a2502A2517b794B482Db40, transferRegistryAddress: 0x8f0483125FCb9aaAEFA9209D8E9d7b9C8B9Fb90F, hashlockTransferAddress: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10 }, 1338: { channelFactoryAddress: 0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da, testTokenAddress: 0x9FBDa871d559710256a2502A2517b794B482Db40, transferRegistryAddress: 0x8f0483125FCb9aaAEFA9209D8E9d7b9C8B9Fb90F, hashlockTransferAddress: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10 } }, chainProviders: { 1337: http://evm_1337:8545, 1338: http://evm_1338:8545 }, logLevel: info, messagingUrl:"", "authUrl": "172.17.0.1:4222","natsUrl":"172.17.0.1:4221", production: false, allowedSwaps: [ { fromChainId: 1337, toChainId: 1338, fromAssetId: 0x0000000000000000000000000000000000000000, toAssetId: 0x0000000000000000000000000000000000000000, priceType: hardcoded, hardcodedRate: 1 }, { fromChainId: 1337, toChainId: 1338, fromAssetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, toAssetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, priceType: hardcoded, hardcodedRate: 1 } ], rebalanceProfiles: [ { chainId: 1337, assetId: 0x0000000000000000000000000000000000000000, reclaimThreshold: 200000000000000000, target: 100000000000000000, collateralizeThreshold: 50000000000000000 }, { chainId: 1338, assetId: 0x0000000000000000000000000000000000000000, reclaimThreshold: 200000000000000000, target: 100000000000000000, collateralizeThreshold: 50000000000000000 }, { chainId: 1337, assetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, reclaimThreshold: 2000000000000000000, target: 1000000000000000000, collateralizeThreshold: 500000000000000000 }, { chainId: 1338, assetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, reclaimThreshold: 2000000000000000000, target: 1000000000000000000, collateralizeThreshold: 500000000000000000 } ]}` +const msg_url = `{ adminToken: cxt1234, chainAddresses: { 1337: { channelFactoryAddress: 0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da, testTokenAddress: 0x9FBDa871d559710256a2502A2517b794B482Db40, transferRegistryAddress: 0x8f0483125FCb9aaAEFA9209D8E9d7b9C8B9Fb90F, hashlockTransferAddress: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10 }, 1338: { channelFactoryAddress: 0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da, testTokenAddress: 0x9FBDa871d559710256a2502A2517b794B482Db40, transferRegistryAddress: 0x8f0483125FCb9aaAEFA9209D8E9d7b9C8B9Fb90F, hashlockTransferAddress: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10 } }, chainProviders: { 1337: http://evm_1337:8545, 1338: http://evm_1338:8545 }, logLevel: info, messagingUrl: , production: false, allowedSwaps: [ { fromChainId: 1337, toChainId: 1338, fromAssetId: 0x0000000000000000000000000000000000000000, toAssetId: 0x0000000000000000000000000000000000000000, priceType: hardcoded, hardcodedRate: 1 }, { fromChainId: 1337, toChainId: 1338, fromAssetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, toAssetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, priceType: hardcoded, hardcodedRate: 1 } ], rebalanceProfiles: [ { chainId: 1337, assetId: 0x0000000000000000000000000000000000000000, reclaimThreshold: 200000000000000000, target: 100000000000000000, collateralizeThreshold: 50000000000000000 }, { chainId: 1338, assetId: 0x0000000000000000000000000000000000000000, reclaimThreshold: 200000000000000000, target: 100000000000000000, collateralizeThreshold: 50000000000000000 }, { chainId: 1337, assetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, reclaimThreshold: 2000000000000000000, target: 1000000000000000000, collateralizeThreshold: 500000000000000000 }, { chainId: 1338, assetId: 0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0, reclaimThreshold: 2000000000000000000, target: 1000000000000000000, collateralizeThreshold: 500000000000000000 } ]}` +const v_config = `{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "4": "https://rinkeby.infura.io" + }, + "logLevel": "info", + "messagingUrl": "", + "production": false, + "allowedSwaps": [ + { + "fromChainId": 4, + "toChainId": 4, + "fromAssetId": "0x0000000000000000000000000000000000000000", + "toAssetId": "0x0000000000000000000000000000000000000000", + "priceType": "hardcoded", + "hardcodedRate": "1" + } + ], + "rebalanceProfiles": [ + { + "chainId": 4, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "1", + "target": "0", + "collateralizeThreshold": "0" + } + ] +}` + +const getMnemonic = () => {return `'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat'`} +const getVectorConfig = ()=>{ + const n_config = node_config_json.replace(/\n/g, ''); + const r_config = router_config.replace(/\n/g, '') + return `${n_config},${r_config}` + +} + +export const test_docker_compose_configuration = `version: '3.4' + +networks: + vector: + external: true + + + +volumes: + certs: + database_node: + database_router: + prometheus: + grafana: + +services: + + node: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_builder:latest' + entrypoint: 'bash modules/server-node/ops/entry.sh' + volumes: + - '/home/z/Development/vector:/app' + ports: + + environment: + VECTOR_CONFIG:'${v_config}' + VECTOR_PROD: 'false' + VECTOR_MNEMONIC: ${getMnemonic()} + VECTOR_MNEMONIC_FILE: '' + VECTOR_DATABASE_URL: '' + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database-node' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PASSWORD_FILE: '' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + + router: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_builder:latest' + entrypoint: 'bash modules/router/ops/entry.sh' + volumes: + - '/home/z/Development/vector:/app' + ports: + + environment: + VECTOR_CONFIG: '{ "adminToken": "cxt1234", "chainAddresses": { "1337": { "channelFactoryAddress": "0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da", "testTokenAddress": "0x9FBDa871d559710256a2502A2517b794B482Db40", "transferRegistryAddress": "0x8f0483125FCb9aaAEFA9209D8E9d7b9C8B9Fb90F", "hashlockTransferAddress": "0x345cA3e014Aaf5dcA488057592ee47305D9B3e10" }, "1338": { "channelFactoryAddress": "0xF12b5dd4EAD5F743C6BaA640B0216200e89B60Da", "testTokenAddress": "0x9FBDa871d559710256a2502A2517b794B482Db40", "transferRegistryAddress": "0x8f0483125FCb9aaAEFA9209D8E9d7b9C8B9Fb90F", "hashlockTransferAddress": "0x345cA3e014Aaf5dcA488057592ee47305D9B3e10" } }, "chainProviders": { "1337": "http://evm_1337:8545", "1338": "http://evm_1338:8545" }, "logLevel": "info", "messagingUrl": "", "production": false, "allowedSwaps": [ { "fromChainId": 1337, "toChainId": 1338, "fromAssetId": "0x0000000000000000000000000000000000000000", "toAssetId": "0x0000000000000000000000000000000000000000", "priceType": "hardcoded", "hardcodedRate": "1" }, { "fromChainId": 1337, "toChainId": 1338, "fromAssetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", "toAssetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", "priceType": "hardcoded", "hardcodedRate": "1" } ], "rebalanceProfiles": [ { "chainId": 1337, "assetId": "0x0000000000000000000000000000000000000000", "reclaimThreshold": "200000000000000000", "target": "100000000000000000", "collateralizeThreshold": "50000000000000000" }, { "chainId": 1338, "assetId": "0x0000000000000000000000000000000000000000", "reclaimThreshold": "200000000000000000", "target": "100000000000000000", "collateralizeThreshold": "50000000000000000" }, { "chainId": 1337, "assetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", "reclaimThreshold": "2000000000000000000", "target": "1000000000000000000", "collateralizeThreshold": "500000000000000000" }, { "chainId": 1338, "assetId": "0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0", "reclaimThreshold": "2000000000000000000", "target": "1000000000000000000", "collateralizeThreshold": "500000000000000000" } ]}' + VECTOR_PROD: 'false' + VECTOR_NODE_URL: 'http://node:8000' + VECTOR_DATABASE_URL: '' + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database-router' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PASSWORD_FILE: '' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + VECTOR_MNEMONIC: 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat' + VECTOR_MNEMONIC_FILE: '' + + database-node: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + ports: + - '5434:5432' + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'false' + + database-router: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + ports: + - '5435:5432' + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'false' + + prometheus: + image: prom/prometheus:latest + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + ports: + - 9090:9090 + command: + - --config.file=/etc/prometheus/prometheus.yml + volumes: + - /home/z/Development/vector/ops/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus:/prometheus + + cadvisor: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: gcr.io/google-containers/cadvisor:latest + ports: + - 8081:8080 + volumes: + - /:/rootfs:ro + - /var/run:/var/run:rw + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + + grafana: + image: grafana/grafana:latest + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + networks: + - vector + ports: + - 3008:3000 + volumes: + - /home/z/Development/vector/ops/grafana/grafana:/etc/grafana + - /home/z/Development/vector/ops/grafana/dashboards:/etc/dashboards + - grafana:/var/lib/grafana +` \ No newline at end of file diff --git a/modules/test-runner/src/load/helpers/dockerNodeMgmt.ts b/modules/test-runner/src/load/helpers/dockerNodeMgmt.ts new file mode 100644 index 000000000..58294ba65 --- /dev/null +++ b/modules/test-runner/src/load/helpers/dockerNodeMgmt.ts @@ -0,0 +1,154 @@ +import {spawn, exec} from 'child_process' +import { + messaging_config, + pull_router_image_opts, + test_docker_compose_configuration, +} from "./dockerNodeConfig"; +const swarm_init_str = 'docker swarm init 2> /dev/null || true' +const d_net_create_str = 'docker network create --attachable --driver overlay "$project" 2> /dev/null || true' + +const start_router = 'bash ops/start-router.sh' + +export const swarm_init = ()=> exec( + swarm_init_str, + ((e,r)=>(console.log(e,r)))) + +export const d_net_create = ()=> exec( + d_net_create_str, + ((e,r)=>console.log(e,r)) +) + + +export const d_start_router = ()=> exec( + start_router, + ((e,r)=>console.log(e,r)) +) + +//Start with script +// export const spawn_router_start = spawn('bash',["ops/start-router.sh"], {shell:true}) + +export const echo_router_config = spawn(`bash`, ['-c',`echo "${test_docker_compose_configuration}" > router.config.test.yml`]) + +export const spawn_router_start = spawn('docker',["stack", "deploy", "-c", "router.config.test.yml", "router"], {shell:true}) + +//Pull images +// export const pull_router_image = spawn('bash', pull_router_image_opts); +// const spawn_router_start = spawn('bash', pull_router_image_opts); + + +export const spawn_n_routers = (num_routers) => { + // spawn('bash',["ops/start-router.sh"], {shell:true}) + spawn('docker',["stack", "deploy", "-c", "router.config.test.yml", "router"], {shell:true}) + + for (let i = 0; i < num_routers; i++) { + spawn_router_start.stdout.on('data', (data) => { + console.log("Data from router node " + data) + }) + spawn_router_start.stderr.on('data', (data) => { + console.log("stderr: " + data) + }) + spawn_router_start.stdout.on('close', (code) => { + if (code) + console.log("process finished, exit code " + code) + }) + } +} + +interface Command { + cmd:string, + args:string[] +} + +class ProcessHandler{ + success_str: string; + success:boolean|undefined = undefined; + + constructor(_success_str:string) { + this.success_str = _success_str; + } + + cmp_stdout(stdout:string){ + const res_str = String(stdout); + console.log(res_str); + const res = res_str.includes(this.success_str); + if(!res){ + console.log("process handler not finding a result that makes sense") + return this.success=false; + } + console.log("Success") + return this.success=true; + } + + cb_stdout_data(data:string){ + this.cmp_stdout(data) + } + cb_stdout_close(data:string){ + console.log("process closed") + return 0; + } + +} + +class SpawnProcess { + returnCode:number|undefined = undefined; + command:Command; + handler:ProcessHandler; + process; + + constructor(_command:Command, _handler:ProcessHandler){ + this.command = _command; + this.handler = _handler; + + } + + register_events(){ + this.process.stderr.on('data', (event_data) => { + console.log("STDERR: " + event_data) + }) + + this.process.stdout.on('data', (event_data) => { + console.log("STDOUT: " + event_data) + this.handler.cb_stdout_data(event_data) + }) + this.process.stdout.on('close', (event_data) => { + console.log("PROCESS CLOSE: " + event_data) + this.returnCode = this.handler.cb_stdout_close(event_data) + }) + } + + exec(){ + this.process = spawn(this.command.cmd, this.command.args, {shell:true}) + this.register_events() + } + + async getResult():Promise{ + const delay = (ms)=>{ + return new Promise((resolve)=> + setTimeout(function(){ + console.log("waiting for process to resolve"); + resolve(); + },ms)) + + } + while(this.handler.success === undefined){ + await delay(20); + + } + return this.handler.success; + } + +} + + +// export const echo_router_config_cmd = spawn(`bash`, ['-c', `echo "${test_docker_compose_configuration}" > router.config.test.yml`]) +// export const echo_messaging_config_cmd = spawn(`bash`, ['-c',`echo "${messaging_config}" > messaging.config.test.yml`]) + +const messagingStart: Command = {cmd:'docker', args:["stack", "deploy", "-c", "messaging.config.test.yml", "messaging"]}; +const messaging_handler:ProcessHandler = new ProcessHandler(""); +export const start_messaging:SpawnProcess = new SpawnProcess(messagingStart, messaging_handler); + +const routerStart: Command = {cmd:'docker', args:["stack", "deploy", "-c", "simnet_compose.yml", "router"]}; +const test_handler:ProcessHandler = new ProcessHandler(""); +export const test_process:SpawnProcess = new SpawnProcess(routerStart, test_handler); + + diff --git a/modules/test-runner/src/load/helpers/routerLoadTest.ts b/modules/test-runner/src/load/helpers/routerLoadTest.ts new file mode 100644 index 000000000..3ff7cd2dc --- /dev/null +++ b/modules/test-runner/src/load/helpers/routerLoadTest.ts @@ -0,0 +1,372 @@ +import { utils, constants, providers, BigNumber} from "ethers"; +import { getAddress } from "@ethersproject/address"; +import {ChannelFactory} from '@connext/vector-contracts' +import {Contract} from "@ethersproject/contracts" +import { Wallet } from "@ethersproject/wallet"; + + +import {env, fundIfBelow, getRandomIndex} from "../../utils"; +import { + DEFAULT_CHANNEL_TIMEOUT, + EngineEvents, + FullChannelState, + INodeService, + TransferNames +} from "@connext/vector-types"; +import {getBalanceForAssetId, getRandomBytes32, RestServerNodeService} from "@connext/vector-utils"; +import pino from "pino"; +import {carolEvts} from "./setupServer"; +import { + chainId1, chainId2, + deposit, provider2, + setup, + wallet1, + wallet2, +} from "../../utils/channel"; + +import * as docker_api from './dockerNodeMgmt' +import { + d_net_create, + swarm_init, + d_start_router, + spawn_n_routers, + start_messaging, + test_process +} from "./dockerNodeMgmt"; +const logger = pino({ level: env.logLevel }); + +//??is there a difference between doug and carol ? + +const testName:string = 'Router Load Test' +const rogerURL:string = "http://localhost:8014" + +let routers:RestServerNodeService[] = []; +let nodes:RestServerNodeService[] = []; + +async function setupRoger() { + const routerIndex = getRandomIndex(); + //verify below + // const routerIndex = 0; + const events = undefined; + + const roger = await RestServerNodeService.connect( + rogerURL, + logger.child({testName, name:"roger"}), + events, + routerIndex + ) + //fund roger + // Default collateral is 0.1 ETH + const provider2 = new providers.JsonRpcProvider("https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9"); + const w = Wallet.fromMnemonic('program biology gasp gentle describe boring suspect raven favorite uphold salon crater').connect(provider2); + + return roger +} +async function setupNode() { + const routerIndex = getRandomIndex(); + //verify below + // const routerIndex = 0; + const events = undefined; + const min = utils.parseEther("0.1"); + + + const roger = await RestServerNodeService.connect( + rogerURL, + logger.child({testName, name:"carol"}), + carolEvts, + routerIndex + ) + //fund roger + // Default collateral is 0.1 ETH + await fundIfBelow(roger.signerAddress, constants.AddressZero, min.mul(15), wallet1); + if (wallet2) { + await fundIfBelow(roger.signerAddress, constants.AddressZero, min.mul(15), wallet2); + } + + return roger +} +async function createRouters(num_routers:number){ + for(let i = 0; i <= num_routers; i++){ + const roger = await setupRoger() + routers.push(roger); + } + return routers; +} +//non router nodes +async function createNode(num_nodes:number){ + for(let i = 0; i <= num_nodes; i++){ + const carol = await setupNode() + nodes.push(carol); + } + return nodes; +} +//get two roters to setup together +const getRandomEntity = async function(entityArr:RestServerNodeService[], num_entities:number){ + const randEntities = entityArr.map(x => ({ x, r: Math.random() })) + .sort((a, b) => a.r - b.r) + .map(a => a.x) + .slice(0, num_entities); + return randEntities; +} +const setupChannelsBetweenNodesAndRouter = async function(nodes:RestServerNodeService[], router:RestServerNodeService) { + const assetId = constants.AddressZero; + const depositAmt = utils.parseEther("1"); + + for (let i = 0; i < nodes.length; i++) { + const setup_res = await setup(nodes[i], router[0], chainId1) + await deposit(nodes[i], router[0], setup_res.channelAddress, assetId, depositAmt) + } +} +async function start(){ + + const transferAmt = utils.parseEther("0.1"); + + const num_routers = 5; + const num_nodes = 10; + + await createRouters(num_routers); + + await createNode(num_nodes); + + const randomRouter:RestServerNodeService = await getRandomEntity(routers,1)[0]; + const randomNodes:RestServerNodeService[] = await getRandomEntity(nodes, 3); + + const res = await setupChannelsBetweenNodesAndRouter(randomNodes, randomRouter) + + //setup channel between all carols and the random node +} + +// d_net_create() +// swarm_init() +// d_start_router() +// spawn_n_routers(1) + +const start_stack = async()=>{ + const messaging = start_messaging.exec(); + const router_a = test_process.exec(); +} + +const r0Address = '0x36e6dEdC5554b2e1fedFb1627Be4D703f0da2B6D' +const r1Address = '0xE3E44bd168C03393d9Ef2E8B304686023E2ca233'; +const daveAddress = '0xA383539Ae895Db1ABF4F6381eB082455366CF93c'; +const carolAddress = '0x6D9B09e55e6341B019eB5CB05067d51cb058D788'; + +const g_provider = new providers.JsonRpcProvider("https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9"); +const r_provider = new providers.JsonRpcProvider("https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9"); + +const getBalances = async function(provider){ + const addressesToCheck = [r0Address,r1Address,daveAddress,carolAddress]; + + let allAddressesHaveETH = true; + for(let i=0; i { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export const dynamicDeposit = async ( + depositor: INodeService, + counterparty: INodeService, + channelAddress: string, + assetId: string, + amount: BigNumber, + provider: providers.Provider + +): Promise => { + const channelRes = await depositor.getStateChannel({ channelAddress }); + const channel = channelRes.getValue()! as FullChannelState; + + const chainId = await provider.getNetwork().then((p)=>{return p.chainId}) + + //get depositor balance of asset + const beforeDepositBalance = (channel:FullChannelState, assetId:string)=>{ + const assetIdx = channel.assetIds.findIndex((a) => getAddress(a) === getAddress(assetId)); + if (assetIdx === -1) { + return "0"; + } + //todo: should we be looking for 0 or 1? + // return channel.balances[assetIdx].amount[participant === "alice" ? 0 : 1]; + return channel.balances[assetIdx].amount[1]; + } + + const beforeDepositBal = beforeDepositBalance(channel,assetId); + + console.log("doing a deposit for ", depositor.signerAddress) + const tx = await depositor.sendDepositTx({ + amount: amount.toString(), + assetId, + chainId: chainId, + channelAddress, + publicIdentifier: depositor.publicIdentifier + }) + + const tx_receipt = await provider.waitForTransaction(tx.getValue().txHash) + console.log("TX RECEIPT :", tx_receipt); + + const depositRes = await depositor.reconcileDeposit({ + assetId, + channelAddress: channel.channelAddress, + publicIdentifier: depositor.publicIdentifier, + }); + + console.log("Dep RES :", depositRes.getValue()!); + + const depositorChannel = ( + await depositor.getStateChannel({ + channelAddress: channel.channelAddress, + publicIdentifier: depositor.publicIdentifier, + }) + ).getValue()! as FullChannelState; + + const counterpartyChannel = ( + await counterparty.getStateChannel({ + channelAddress: channel.channelAddress, + publicIdentifier: counterparty.publicIdentifier, + }) + ).getValue()!; + + + return depositorChannel + +} + +const main = async function(){ + + const participantsHaveETH = await getBalances(g_provider) + if(!participantsHaveETH){return;} + + const urlBase = "http://localhost:" + + const net = await g_provider.getNetwork() + const chainId = net.chainId; + + const carolService = await RestServerNodeService.connect( + urlBase + carolNodeURL, + logger.child({testName, name:"Carol"}), + undefined, + 1) + + const daveService = await RestServerNodeService.connect( + urlBase + daveNodeURL, + logger.child({testName, name:"Dave"}), + undefined, + 1) + + const r0Service = await RestServerNodeService.connect( + urlBase + r0NodeUrl, + logger.child({ testName, name: "Roger" }), + undefined, + 1) + + const carolSetup = await carolService.setup({ + counterpartyIdentifier: r0Service.publicIdentifier, + chainId, + timeout: DEFAULT_CHANNEL_TIMEOUT.toString() + }); + + const daveSetup = await daveService.setup({ + counterpartyIdentifier: r0Service.publicIdentifier, + chainId: 4, + timeout: DEFAULT_CHANNEL_TIMEOUT.toString() + }) + + const carolChannel = carolSetup.getValue(); + const daveChannel = daveSetup.getValue(); + + //get carol's channel with self? + const carolChan = await r0Service.getStateChannel({ + channelAddress: carolChannel.channelAddress, + publicIdentifier: carolService.publicIdentifier, + }); + + // r0Service.getStateChannelByParticipants() + const routerChan = await r0Service.getStateChannel({ + channelAddress: carolChannel.channelAddress, + publicIdentifier: r0Service.publicIdentifier + }) + + const daveChan = await r0Service.getStateChannel({ + channelAddress: daveChannel.channelAddress, + publicIdentifier: r0Service.publicIdentifier + }) + + //carol and router chan should deep euqal + const carolSetupRes = routerChan.getValue()! as FullChannelState; + const daveSetupRes = daveChan.getValue()! as FullChannelState; + + console.log("ROUTER CHAN ", carolSetupRes) + + const depositAmt = utils.parseEther(".1"); + + const assetId = constants.AddressZero; + + const tx = await carolService.sendDepositTx({ + amount: depositAmt.toString(), + assetId, + chainId: chainId, + channelAddress: carolChannel.channelAddress, + publicIdentifier: carolService.publicIdentifier, + }) + + const tx_wait = g_provider.waitForTransaction(tx.getValue().txHash) + console.log("DEPOSIT TX ", tx_wait) + + const depositRes = await carolService.reconcileDeposit({ + assetId, + channelAddress: carolSetupRes.channelAddress, + publicIdentifier: carolService.publicIdentifier, + }) + + const deposit = await depositRes.getValue() + + console.log("DEPOSIT RECON RES ", deposit) + + const preImage = getRandomBytes32(); + const lockHash = utils.soliditySha256(["bytes32"], [preImage]); + + const transferRes = await carolService.conditionalTransfer({ + amount: depositAmt.toString(), + assetId: assetId, + channelAddress: carolSetupRes.channelAddress, + type: TransferNames.HashlockTransfer, + details: { + lockHash, + expiry: "0", + }, + recipient: daveService.publicIdentifier, + recipientChainId: 4 + }) + + console.log("Transfer Result Context", transferRes.getError()?.context.context) + + + //get tx event + // daveService.resolveTransfer(... lockHash) + + + +} + +async function run_all(){ + await start_stack(); + await timeout(45000) + await main() +} +// start_stack() +// start_stack() + +main() \ No newline at end of file diff --git a/modules/test-runner/src/utils/channel.ts b/modules/test-runner/src/utils/channel.ts index 9cb974be9..30a5ada97 100644 --- a/modules/test-runner/src/utils/channel.ts +++ b/modules/test-runner/src/utils/channel.ts @@ -44,7 +44,7 @@ export const advanceBlocktime = async (seconds: number, provider = provider1): P } }; -export const setup = async ( +export const setup = async ( bobService: INodeService, aliceService: INodeService, chainId: number, diff --git a/ops/start-router.sh b/ops/start-router.sh index f5c8fa1dd..f5eae6ceb 100644 --- a/ops/start-router.sh +++ b/ops/start-router.sh @@ -8,9 +8,9 @@ project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) docker swarm init 2> /dev/null || true docker network create --attachable --driver overlay "$project" 2> /dev/null || true -if grep -qs "$stack" <<<"$(docker stack ls --format '{{.Name}}')" -then echo "A $stack stack is already running" && exit 0; -fi +#if grep -qs "$stack" <<<"$(docker stack ls --format '{{.Name}}')" +#then echo "A $stack stack is already running" && exit 0; +#fi #################### # Load config @@ -212,8 +212,9 @@ fi ######################################## ## Router config -router_internal_port="8000" -router_public_port="9000" +router_internal_port="9002" +# change so it dosen't conflict with portainer (revert) +router_public_port="9002" public_url="http://127.0.0.1:$router_public_port/ping" if [[ $production == "true" ]] then diff --git a/simnet_compose.yml b/simnet_compose.yml new file mode 100644 index 000000000..a1fcf74ab --- /dev/null +++ b/simnet_compose.yml @@ -0,0 +1,434 @@ +version: '3.8' + +networks: + vector: + vector1: + +volumes: + database_node: + driver_opts: + type: tmpfs + device: tmpfs + database_router0: + driver_opts: + type: tmpfs + device: tmpfs + database_node1: + driver_opts: + type: tmpfs + device: tmpfs + database_carol: + driver_opts: + type: tmpfs + device: tmpfs + database_dave: + driver_opts: + type: tmpfs + device: tmpfs + database_router1: + driver_opts: + type: tmpfs + device: tmpfs + +services: + + node: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'connextproject/vector_node:0.2.5-beta.16' + restart: always + ports: + - '8002:8000' + environment: + VECTOR_CONFIG: '{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "5": "https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9", + "4": "https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9" + }, + "logLevel": "info", + "messagingUrl": "https://messaging.connext.network", + "production": true, + "allowedSwaps": [ + { + "fromChainId": 4, + "toChainId": 5, + "fromAssetId": "0x0000000000000000000000000000000000000000", + "toAssetId": "0x0000000000000000000000000000000000000000", + "priceType": "hardcoded", + "hardcodedRate": "1" + } + ], + "rebalanceProfiles": [ + { + "chainId": 4, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "1", + "target": "0", + "collateralizeThreshold": "0" + } + ] +}' + VECTOR_PROD: 'true' + VECTOR_MNEMONIC: 'glad focus asset predict monkey worth way talk unhappy hazard area squeeze' +# Address: '0x36e6dEdC5554b2e1fedFb1627Be4D703f0da2B6D' + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database-node' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + + router: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'connextproject/vector_router:0.2.5-beta.16' + environment: + VECTOR_CONFIG: '{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "5": "https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9", + "4": "https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9" + }, + "logLevel": "info", + "messagingUrl": "https://messaging.connext.network", + "production": true, + "allowedSwaps": [ + { + "fromChainId": 4, + "toChainId": 5, + "fromAssetId": "0x0000000000000000000000000000000000000000", + "toAssetId": "0x0000000000000000000000000000000000000000", + "priceType": "hardcoded", + "hardcodedRate": "1" + } + ], + "rebalanceProfiles": [ + { + "chainId": 4, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "1", + "target": "0", + "collateralizeThreshold": "0" + } + ] +}' + VECTOR_PROD: 'true' + VECTOR_NODE_URL: 'http://node:8000' + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database-router0' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + VECTOR_MNEMONIC: 'glad focus asset predict monkey worth way talk unhappy hazard area squeeze' + + database-node: + volumes: + - database_node:/var/lib/postgresql/data + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'true' + + database-router0: + volumes: + - database_router0:/var/lib/postgresql/data + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'true' + + node1: + networks: + - 'vector1' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'connextproject/vector_node:0.2.5-beta.16' + restart: always + ports: + - '8014:8000' + environment: + VECTOR_CONFIG: '{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "5": "https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9", + "4": "https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9" + + }, + "logLevel": "info", + "messagingUrl": "https://messaging.connext.network", + "production": true, + "allowedSwaps": [ + { + "fromChainId": 4, + "toChainId": 4, + "fromAssetId": "0x0000000000000000000000000000000000000000", + "toAssetId": "0x0000000000000000000000000000000000000000", + "priceType": "hardcoded", + "hardcodedRate": "1" + } + ], + "rebalanceProfiles": [ + { + "chainId": 4, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "1", + "target": "0", + "collateralizeThreshold": "0" + } + ] +}' + VECTOR_PROD: 'true' + VECTOR_MNEMONIC: 'program biology gasp gentle describe boring suspect raven favorite uphold salon crater' +# Addresss : 0xE3E44bd168C03393d9Ef2E8B304686023E2ca233 + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + + + router1: + networks: + - 'vector1' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'connextproject/vector_router:0.2.5-beta.16' + environment: + VECTOR_CONFIG: '{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "4": "https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9", + "5": "https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9" + }, + "logLevel": "info", + "messagingUrl": "https://messaging.connext.network", + "production": true, + "allowedSwaps": [ + { + "fromChainId": 4, + "toChainId": 5, + "fromAssetId": "0x0000000000000000000000000000000000000000", + "toAssetId": "0x0000000000000000000000000000000000000000", + "priceType": "hardcoded", + "hardcodedRate": "1" + } + ], + "rebalanceProfiles": [ + { + "chainId": 4, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "1", + "target": "0", + "collateralizeThreshold": "0" + }, + { + "chainId": 5, + "assetId": "0x0000000000000000000000000000000000000000", + "reclaimThreshold": "1", + "target": "0", + "collateralizeThreshold": "0" + } + ] +}' + VECTOR_PROD: 'true' + VECTOR_NODE_URL: 'http://node1:8000' + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database-router1' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + VECTOR_MNEMONIC: 'program biology gasp gentle describe boring suspect raven favorite uphold salon crater' + # Addresss : 0xE3E44bd168C03393d9Ef2E8B304686023E2ca233 + + + database-node1: + volumes: + - database_node1:/var/lib/postgresql/data + networks: + - 'vector1' + logging: + driver: 'json-file' + options: + max-size: '10m' + + image: 'vector_database:latest' + + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'true' +# + database-router1: + volumes: + - database_router1:/var/lib/postgresql/data + networks: + - 'vector1' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'true' + + + carol_node: + networks: + - 'vector1' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'connextproject/vector_node:0.2.5-beta.16' + restart: always + ports: + - '8004:8000' + environment: + VECTOR_CONFIG: '{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "5": "https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9", + "4": "https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9" + }, + "logLevel": "info", + "messagingUrl": "https://messaging.connext.network", + "production": true +}' + VECTOR_PROD: 'true' + VECTOR_MNEMONIC: 'hood path despair ranch version fiber hope people wise angle avocado suit' +# Address: '0x6D9B09e55e6341B019eB5CB05067d51cb058D788' + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database_carol' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + + database_carol: + volumes: + - database_carol:/var/lib/postgresql/data + networks: + - 'vector1' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'true' + + dave_node: + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'connextproject/vector_node:0.2.5-beta.16' + restart: always + ports: + - '8005:8000' + environment: + VECTOR_CONFIG: '{ + "adminToken": "cxt1234", + "chainAddresses": {}, + "chainProviders": { + "5": "https://goerli.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9", + "4": "https://rinkeby.infura.io/v3/af2f28bdb95d40edb06226a46106f5f9" + }, + "logLevel": "info", + "messagingUrl": "https://messaging.connext.network", + "production": true +}' + VECTOR_PROD: 'true' + VECTOR_MNEMONIC: 'apart tomorrow mango disorder amused dutch number fruit canvas hold august raise' +# Address: '0xA383539Ae895Db1ABF4F6381eB082455366CF93c' + + VECTOR_PG_DATABASE: 'vector' + VECTOR_PG_HOST: 'database_dave' + VECTOR_PG_PASSWORD: 'vector' + VECTOR_PG_PORT: '5432' + VECTOR_PG_USERNAME: 'vector' + + database_dave: + volumes: + - database_dave:/var/lib/postgresql/data + networks: + - 'vector' + logging: + driver: 'json-file' + options: + max-size: '10m' + image: 'vector_database:latest' + + environment: + AWS_ACCESS_KEY_ID: '' + AWS_SECRET_ACCESS_KEY: '' + POSTGRES_DB: 'vector' + POSTGRES_PASSWORD: 'vector' + POSTGRES_PASSWORD_FILE: '' + POSTGRES_USER: 'vector' + VECTOR_ADMIN_TOKEN: 'cxt1234' + VECTOR_PROD: 'true'