diff --git a/.env.jungle b/.env.jungle index 8cca31b7..bcb32923 100644 --- a/.env.jungle +++ b/.env.jungle @@ -26,7 +26,8 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.lacchain b/.env.lacchain index c7bcab7f..3e23fcb4 100644 --- a/.env.lacchain +++ b/.env.lacchain @@ -27,8 +27,9 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechanics HAPI_EOS_MECHANICS_PASSWORD=PW... +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION={"account":"writer","name":"run","authorization":[{"actor":"costarica","permission":"writer"}],"data":{}} -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.libre b/.env.libre index c038637f..66597d56 100644 --- a/.env.libre +++ b/.env.libre @@ -26,7 +26,8 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT=producerjson HAPI_EOS_BP_JSON_ON_CHAIN_TABLE=producerjson diff --git a/.env.libretestnet b/.env.libretestnet index eaa7ca13..339c1b90 100644 --- a/.env.libretestnet +++ b/.env.libretestnet @@ -26,7 +26,8 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION=benchmark +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT=producerjson HAPI_EOS_BP_JSON_ON_CHAIN_TABLE=producerjson @@ -81,7 +82,7 @@ REACT_APP_EOS_BP_JSON_ON_CHAIN_SCOPE=producerjson REACT_APP_SYNC_TOLERANCE_INTERVAL=180000 REACT_APP_TOKEN_SYMBOL=LIBRE REACT_APP_NETWORK_URL=[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":1},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":2},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":3},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":4},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":5},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":1},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":2},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":3},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":4},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":5},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}] -REACT_APP_DISABLED_MENU_ITEMS=["/missed-blocks", "/cpu-benchmark","/block-distribution"] +REACT_APP_DISABLED_MENU_ITEMS=["/missed-blocks","/block-distribution"] REACT_APP_BLOCK_EXPLORER_URL=https://wax-test.bloks.io/transaction/(transaction) REACT_APP_STATE_HISTORY_ENABLED=false REACT_APP_GOOGLE_ANALITIC_PAGE_ID=G-E6Y0EC9FT8 diff --git a/.env.local b/.env.local index d037ef76..b9aebd7b 100644 --- a/.env.local +++ b/.env.local @@ -26,8 +26,9 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechanics HAPI_EOS_MECHANICS_PASSWORD=PW... +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION={"account":"writer","name":"run","authorization":[{"actor":"latamlink","permission":"writer"}],"data":{}} -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.mainnet b/.env.mainnet index b57c3e0e..ae550ba8 100644 --- a/.env.mainnet +++ b/.env.mainnet @@ -24,9 +24,10 @@ HAPI_EOS_API_ENDPOINTS=["https://eos.edenia.cloud","https://api.main.alohaeos.co HAPI_EOS_API_CHAIN_ID=aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906 HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... -HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero +HAPI_EOS_MECHANICS_ACCOUNT= HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.proton b/.env.proton index 0c99aeb9..5a0c27b3 100644 --- a/.env.proton +++ b/.env.proton @@ -24,9 +24,10 @@ HAPI_EOS_API_ENDPOINTS=["https://proton.edenia.cloud","https://proton.eosusa.io" HAPI_EOS_API_CHAIN_ID=384da888112027f0321850a169f737c33e53b388aad48b5adace4bab97f437e0 HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... -HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero +HAPI_EOS_MECHANICS_ACCOUNT= HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.protontestnet b/.env.protontestnet index 6cd2bd0d..b977934c 100644 --- a/.env.protontestnet +++ b/.env.protontestnet @@ -26,7 +26,8 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.telos b/.env.telos index 578dbb86..f4d6fbe0 100644 --- a/.env.telos +++ b/.env.telos @@ -24,9 +24,10 @@ HAPI_EOS_API_ENDPOINTS=["https://telos.greymass.com","https://telos.eosphere.io" HAPI_EOS_API_CHAIN_ID=4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11 HAPI_EOS_BASE_ACCOUNT=eosmechatero HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... -HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero +HAPI_EOS_MECHANICS_ACCOUNT= HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT=producerjson HAPI_EOS_BP_JSON_ON_CHAIN_TABLE=producerjson diff --git a/.env.telostestnet b/.env.telostestnet index add57194..88793a02 100644 --- a/.env.telostestnet +++ b/.env.telostestnet @@ -26,7 +26,8 @@ HAPI_EOS_BASE_ACCOUNT=eosmechatero HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT=producerjson HAPI_EOS_BP_JSON_ON_CHAIN_TABLE=producerjson diff --git a/.env.ultratestnet b/.env.ultratestnet index 7cf5f5ef..a328ffa4 100644 --- a/.env.ultratestnet +++ b/.env.ultratestnet @@ -28,8 +28,9 @@ HAPI_EOS_FAUCET_ACCOUNT=1aa2aa3aa4ai HAPI_EOS_FAUCET_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION= -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.wax b/.env.wax index 82e50da6..1544c12f 100644 --- a/.env.wax +++ b/.env.wax @@ -24,9 +24,10 @@ HAPI_EOS_API_ENDPOINTS=["https://wax.api.eosnation.io","https://wax.edenia.cloud HAPI_EOS_API_CHAIN_ID=1064487b3cd1a897ce03ae5b6a865651747e2e152090f99c1d19d44e01aea5a4 HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... -HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero +HAPI_EOS_MECHANICS_ACCOUNT= HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.env.waxtestnet b/.env.waxtestnet index 7ac40ad7..bc255730 100644 --- a/.env.waxtestnet +++ b/.env.waxtestnet @@ -26,7 +26,8 @@ HAPI_EOS_BASE_ACCOUNT=baseaccount HAPI_EOS_BASE_ACCOUNT_PASSWORD=PW... HAPI_EOS_MECHANICS_ACCOUNT=eosmechatero HAPI_EOS_MECHANICS_PASSWORD=PW... -HAPI_EOS_WALLET_URL=http://localhost:8888 +HAPI_EOS_MECHANICS_CUSTOM_PERMISSION= +HAPI_EOS_WALLET_URL=http://wallet:8888 HAPI_EOS_BP_JSON_ON_CHAIN=false HAPI_EOS_BP_JSON_ON_CHAIN_CONTRACT= HAPI_EOS_BP_JSON_ON_CHAIN_TABLE= diff --git a/.github/workflows/deploy-libre-testnet.yaml b/.github/workflows/deploy-libre-testnet.yaml index ba2bf4d6..e9dd2f93 100644 --- a/.github/workflows/deploy-libre-testnet.yaml +++ b/.github/workflows/deploy-libre-testnet.yaml @@ -88,6 +88,7 @@ jobs: HAPI_EOS_BASE_ACCOUNT_PASSWORD: ${{ secrets.HAPI_EOS_BASE_ACCOUNT_PASSWORD }} HAPI_EOS_MECHANICS_ACCOUNT: ${{ secrets.HAPI_EOS_MECHANICS_ACCOUNT }} HAPI_EOS_MECHANICS_PASSWORD: ${{ secrets.HAPI_EOS_MECHANICS_PASSWORD }} + HAPI_EOS_MECHANICS_CUSTOM_PERMISSION: 'benchmark' HAPI_EOS_FAUCET_ACCOUNT_PASSWORD: ${{ secrets.HAPI_EOS_FAUCET_ACCOUNT_PASSWORD }} GOOGLE_CREDENTIALS_JSON: ${{ secrets.GOOGLE_CREDENTIALS_JSON }} HAPI_EOS_WALLET_URL: http://dashboard-wallet:8888 diff --git a/docker-compose.yaml b/docker-compose.yaml index 069fde45..5cb0b0af 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -41,6 +41,7 @@ services: HAPI_EOS_FAUCET_ACCOUNT_PASSWORD: '${HAPI_EOS_FAUCET_ACCOUNT_PASSWORD}' HAPI_EOS_MECHANICS_ACCOUNT: '${HAPI_EOS_MECHANICS_ACCOUNT}' HAPI_EOS_MECHANICS_PASSWORD: '${HAPI_EOS_MECHANICS_PASSWORD}' + HAPI_EOS_MECHANICS_CUSTOM_PERMISSION: '${HAPI_EOS_MECHANICS_CUSTOM_PERMISSION}' HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION: '${HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION}' HAPI_EOS_WALLET_URL: '${HAPI_EOS_WALLET_URL}' HAPI_EOS_BP_JSON_ON_CHAIN: '${HAPI_EOS_BP_JSON_ON_CHAIN}' diff --git a/hapi/src/config/eos.config.js b/hapi/src/config/eos.config.js index de720fb9..26fc45cf 100644 --- a/hapi/src/config/eos.config.js +++ b/hapi/src/config/eos.config.js @@ -23,6 +23,8 @@ module.exports = { eosmechanics: { account: process.env.HAPI_EOS_MECHANICS_ACCOUNT, password: process.env.HAPI_EOS_MECHANICS_PASSWORD, + customPermission: + process.env.HAPI_EOS_MECHANICS_CUSTOM_PERMISSION || 'active', includeTransaction: process.env.HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION ? JSON.parse(process.env.HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION) : '' diff --git a/hapi/src/services/health-check-history.service.js b/hapi/src/services/health-check-history.service.js index b8985e6c..4225964b 100644 --- a/hapi/src/services/health-check-history.service.js +++ b/hapi/src/services/health-check-history.service.js @@ -36,7 +36,11 @@ const updateEndpointsHealthHistory = async (endpoints, date) => { ` const updates = endpoints.map(endpoint => ({ where: { - _and: [{ value: { _eq: endpoint.value } }, { date: { _eq: date } }] + _and: [ + { producer_id: { _eq: endpoint.producer_id } }, + { value: { _eq: endpoint.value } }, + { date: { _eq: date } } + ] }, _inc: { successful_checks: endpoint.isWorking, diff --git a/hapi/src/services/producer.service.js b/hapi/src/services/producer.service.js index 95ea7687..a7418a09 100644 --- a/hapi/src/services/producer.service.js +++ b/hapi/src/services/producer.service.js @@ -1,7 +1,7 @@ const { StatusCodes } = require('http-status-codes') const { hasuraUtil, sequelizeUtil, producerUtil } = require('../utils') -const { eosConfig } = require('../config') +const { eosConfig, workersConfig } = require('../config') const lacchainService = require('./lacchain.service') const eosioService = require('./eosio.service') @@ -59,6 +59,24 @@ const updateProducers = async (producers = []) => { return insertedRows.insert_producer.returning } +const updateProducersLog = async ({ lastUpdateAt, nextUpdateAt }) => { + const upsertMutation = ` + mutation ($payload: [producers_list_update_log_insert_input!]!) { + insert_producers_list_update_log(objects: $payload, on_conflict: {constraint: producers_list_update_log_pkey, update_columns: [ last_update, next_estimated_update ]}) { + affected_rows + } + } + ` + + await hasuraUtil.request(upsertMutation, { + payload: { + id: 1, + last_update: lastUpdateAt, + next_estimated_update: nextUpdateAt + } + }) +} + const syncProducers = async () => { let producers = [] @@ -73,6 +91,7 @@ const syncProducers = async () => { if (producers?.length) { producers = await updateProducers(producers) + await saveEstimateNextUpdate(new Date()) await syncNodes(producers.slice(0, eosConfig.eosTopLimit)) await syncEndpoints() @@ -82,6 +101,19 @@ const syncProducers = async () => { } } +const saveEstimateNextUpdate = async lastUpdateAt => { + const timeoutGetBPJSONs = 750 + const timeoutGetProducers = eosConfig.apiEndpoints.length * 30 + const timeoutSum = timeoutGetBPJSONs + timeoutGetProducers + const nextUpdateAt = new Date(lastUpdateAt) + + nextUpdateAt.setSeconds( + nextUpdateAt.getSeconds() + workersConfig.syncProducersInterval + timeoutSum + ) + + await updateProducersLog({ lastUpdateAt, nextUpdateAt }) +} + const getProducersSummary = async () => { const [rows] = await sequelizeUtil.query(` SELECT diff --git a/hapi/src/utils/eosmechanics.util.js b/hapi/src/utils/eosmechanics.util.js index 2b55ef38..50037ff6 100644 --- a/hapi/src/utils/eosmechanics.util.js +++ b/hapi/src/utils/eosmechanics.util.js @@ -2,30 +2,18 @@ const { eosConfig } = require('../config') const eosUtil = require('./eos.util') -const cpu = async () => { - const actions = [] - +const transact = async actions => { if (eosConfig.eosmechanics.includeTransaction) { actions.push(eosConfig.eosmechanics.includeTransaction) } - actions.push({ - authorization: [ - { - actor: eosConfig.eosmechanics.account, - permission: 'active' - } - ], - account: eosConfig.eosmechanics.account, - name: 'cpu', - data: {} - }) - const transaction = await eosUtil.transact( actions, eosConfig.eosmechanics.account, eosConfig.eosmechanics.password ) + + await new Promise((resolve) => setTimeout(() => resolve(), 1000)) const block = await eosUtil.getBlock(transaction.processed.block_num) return { @@ -34,18 +22,32 @@ const cpu = async () => { } } -const net = async (input = '') => { +const cpu = async () => { const actions = [] - if (eosConfig.eosmechanics.includeTransaction) { - actions.push(eosConfig.eosmechanics.includeTransaction) - } + actions.push({ + authorization: [ + { + actor: eosConfig.eosmechanics.account, + permission: eosConfig.eosmechanics.customPermission + } + ], + account: eosConfig.eosmechanics.account, + name: 'cpu', + data: {} + }) + + return await transact(actions) +} + +const net = async (input = '') => { + const actions = [] actions.push({ authorization: [ { actor: eosConfig.eosmechanics.account, - permission: 'active' + permission: eosConfig.eosmechanics.customPermission } ], account: eosConfig.eosmechanics.account, @@ -55,32 +57,17 @@ const net = async (input = '') => { } }) - const transaction = await eosUtil.transact( - actions, - eosConfig.eosmechanics.account, - eosConfig.eosmechanics.password - ) - await new Promise(resolve => setTimeout(() => resolve(), 500)) - const block = await eosUtil.getBlock(transaction.processed.block_num) - - return { - transaction, - block - } + return await transact(actions) } const ram = async () => { const actions = [] - if (eosConfig.eosmechanics.includeTransaction) { - actions.push(eosConfig.eosmechanics.includeTransaction) - } - actions.push({ authorization: [ { actor: eosConfig.eosmechanics.account, - permission: 'active' + permission: eosConfig.eosmechanics.customPermission } ], account: eosConfig.eosmechanics.account, @@ -88,18 +75,7 @@ const ram = async () => { data: {} }) - const transaction = await eosUtil.transact( - actions, - eosConfig.eosmechanics.account, - eosConfig.eosmechanics.password - ) - await new Promise(resolve => setTimeout(() => resolve(), 500)) - const block = await eosUtil.getBlock(transaction.processed.block_num) - - return { - transaction, - block - } + return await transact(actions) } module.exports = { diff --git a/hapi/src/workers/producers.worker.js b/hapi/src/workers/producers.worker.js index 3e0f6879..ef72fc04 100644 --- a/hapi/src/workers/producers.worker.js +++ b/hapi/src/workers/producers.worker.js @@ -59,7 +59,10 @@ const start = async () => { settingService.syncEOSPrice, workersConfig.syncExchangeRate ) - run('CPU WORKER', cpuService.worker, workersConfig.cpuWorkerInterval) + + if (eosConfig.eosmechanics.account && eosConfig.eosmechanics.password) { + run('CPU WORKER', cpuService.worker, workersConfig.cpuWorkerInterval) + } if (eosConfig.stateHistoryPluginEndpoint) { run('SYNC STATS INFO', statsService.sync, workersConfig.syncStatsInterval) diff --git a/hasura/metadata/databases/default/tables/public_producers_list_update_log.yaml b/hasura/metadata/databases/default/tables/public_producers_list_update_log.yaml new file mode 100644 index 00000000..ac78df0c --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_producers_list_update_log.yaml @@ -0,0 +1,11 @@ +table: + name: producers_list_update_log + schema: public +select_permissions: + - role: guest + permission: + columns: + - id + - last_update + - next_estimated_update + filter: {} diff --git a/hasura/metadata/databases/default/tables/tables.yaml b/hasura/metadata/databases/default/tables/tables.yaml index 0a6a467d..244cf61c 100644 --- a/hasura/metadata/databases/default/tables/tables.yaml +++ b/hasura/metadata/databases/default/tables/tables.yaml @@ -10,6 +10,7 @@ - "!include public_node.yaml" - "!include public_node_info.yaml" - "!include public_producer.yaml" +- "!include public_producers_list_update_log.yaml" - "!include public_round_history.yaml" - "!include public_schedule_history.yaml" - "!include public_setting.yaml" diff --git a/hasura/migrations/default/1683238474098_create_table_public_producers_list_update_log/down.sql b/hasura/migrations/default/1683238474098_create_table_public_producers_list_update_log/down.sql new file mode 100644 index 00000000..98faf2ae --- /dev/null +++ b/hasura/migrations/default/1683238474098_create_table_public_producers_list_update_log/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."producers_list_update_log"; diff --git a/hasura/migrations/default/1683238474098_create_table_public_producers_list_update_log/up.sql b/hasura/migrations/default/1683238474098_create_table_public_producers_list_update_log/up.sql new file mode 100644 index 00000000..90f07d26 --- /dev/null +++ b/hasura/migrations/default/1683238474098_create_table_public_producers_list_update_log/up.sql @@ -0,0 +1 @@ +CREATE TABLE "public"."producers_list_update_log" ("id" integer NOT NULL DEFAULT 1, "last_update" timestamp with time zone NOT NULL, "next_estimated_update" timestamp with time zone NOT NULL, PRIMARY KEY ("id") , UNIQUE ("id")); diff --git a/kubernetes/configmap-dashboard.yaml b/kubernetes/configmap-dashboard.yaml index 99421d1f..5553fb71 100644 --- a/kubernetes/configmap-dashboard.yaml +++ b/kubernetes/configmap-dashboard.yaml @@ -69,6 +69,7 @@ data: HAPI_EOS_FAUCET_ACCOUNT_PASSWORD: '${HAPI_EOS_FAUCET_ACCOUNT_PASSWORD}' HAPI_EOS_MECHANICS_ACCOUNT: '${HAPI_EOS_MECHANICS_ACCOUNT}' HAPI_EOS_MECHANICS_PASSWORD: '${HAPI_EOS_MECHANICS_PASSWORD}' + HAPI_EOS_MECHANICS_CUSTOM_PERMISSION: '${HAPI_EOS_MECHANICS_CUSTOM_PERMISSION}' HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION: '${HAPI_EOS_MECHANICS_INCLUDE_TRANSACTION}' HAPI_EOS_WALLET_URL: '${HAPI_EOS_WALLET_URL}' HAPI_EOS_BP_JSON_ON_CHAIN: '${HAPI_EOS_BP_JSON_ON_CHAIN}' diff --git a/webapp/src/components/ProducersChart/index.js b/webapp/src/components/ProducersChart/index.js index ddce6c2e..0df0d56f 100644 --- a/webapp/src/components/ProducersChart/index.js +++ b/webapp/src/components/ProducersChart/index.js @@ -59,22 +59,39 @@ const CustomBarLabel = memo( outerRadius - gap, midAngle, ) - const cartesianText = polarToCartesian(cx, cy, outerRadius + 8, midAngle) + const spacing = sm ? 16 : 12 + const cartesianText = polarToCartesian( + cx, + cy, + outerRadius + spacing, + midAngle, + ) const link = generalConfig.eosRateLink ? `${generalConfig.eosRateLink}/block-producers/${payload.owner}` : payload.url + const getNameTextAnchor = (x, cx) => { + if (x + 30 >= cx && x < cx) { + return 'middle' + } else if (x > cx) { + return 'start' + } else { + return 'end' + } + } + const ProducerName = () => { const Content = () => ( cx ? 'start' : 'end'} + textAnchor={getNameTextAnchor(x, cx)} dominantBaseline="central" fill={ fill === theme.palette.primary.dark ? theme.palette.primary.dark : theme.palette.primary.light } + fontSize={sm ? 14 : 12} fontFamily="Roboto, Helvetica, Arial, sans-serif;" fontWeight={fill === theme.palette.primary.dark ? 'bold' : 'normal'} > diff --git a/webapp/src/components/ProducersChart/styles.js b/webapp/src/components/ProducersChart/styles.js index 5058920d..2290e7f1 100644 --- a/webapp/src/components/ProducersChart/styles.js +++ b/webapp/src/components/ProducersChart/styles.js @@ -4,9 +4,9 @@ export default (theme) => ({ padding: theme.spacing(2), borderRadius: theme.spacing(1), boxShadow: - '0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12)' + '0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12)', }, description: { - fontWeight: 'normal' - } + fontWeight: 'normal', + }, }) diff --git a/webapp/src/components/ProducersUpdateLog/index.js b/webapp/src/components/ProducersUpdateLog/index.js new file mode 100644 index 00000000..47cd2506 --- /dev/null +++ b/webapp/src/components/ProducersUpdateLog/index.js @@ -0,0 +1,47 @@ +import React from 'react' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import { useQuery } from '@apollo/client' +import Skeleton from '@mui/material/Skeleton' +import moment from 'moment' + +import { PRODUCERS_UPDATE_LOG_QUERY } from '../../gql' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const ProducersUpdateLog = () => { + const classes = useStyles() + const { t } = useTranslation() + const { loading, data: { updateLogs } = {} } = useQuery( + PRODUCERS_UPDATE_LOG_QUERY, + ) + + if (loading) return + + return ( + <> + {updateLogs && ( +
+ + {t('updatedAt')} + {': '} + + {moment(updateLogs?.at(0)?.last_update)?.format('lll')}{' '} + + + + {t('nextUpdateAt')} + {': '} + + {moment(updateLogs?.at(0)?.next_estimated_update)?.format('lll')} + + +
+ )} + + ) +} + +export default ProducersUpdateLog diff --git a/webapp/src/components/ProducersUpdateLog/styles.js b/webapp/src/components/ProducersUpdateLog/styles.js new file mode 100644 index 00000000..b9f1cac9 --- /dev/null +++ b/webapp/src/components/ProducersUpdateLog/styles.js @@ -0,0 +1,13 @@ +export default (theme) => ({ + updateLogContainer: { + display: 'flex', + flexWrap: 'wrap', + }, + dateText: { + fontWeight: 'bold', + marginRight: theme.spacing(4), + '& span': { + fontWeight: 'normal', + }, + }, +}) diff --git a/webapp/src/gql/producer.gql.js b/webapp/src/gql/producer.gql.js index c295daf3..7d522f64 100644 --- a/webapp/src/gql/producer.gql.js +++ b/webapp/src/gql/producer.gql.js @@ -230,3 +230,10 @@ export const HISTORY_ENDPOINTS_BY_PRODUCER_QUERY = gql`query($id: Int){ date } }` + +export const PRODUCERS_UPDATE_LOG_QUERY = gql`query{ + updateLogs: producers_list_update_log (limit: 1){ + last_update + next_estimated_update + } +}` diff --git a/webapp/src/hooks/customHooks/useEndpointsState.js b/webapp/src/hooks/customHooks/useEndpointsState.js index 03059240..b321f560 100644 --- a/webapp/src/hooks/customHooks/useEndpointsState.js +++ b/webapp/src/hooks/customHooks/useEndpointsState.js @@ -12,10 +12,9 @@ const useEndpointsState = () => { ] = useSearchState({ query: PRODUCERS_QUERY, where: { nodes: { endpoints: { value: { _gt: '' } } } }, - limit: 20 + limit: 20, }) const { data, loading } = useSubscription(ENDPOINTS_SUBSCRIPTION, { variables }) - const [updatedAt, setUpdatedAt] = useState() const [items, setItems] = useState() useEffect(() => { @@ -43,10 +42,6 @@ const useEndpointsState = () => { } }), ) - - if (!data.producers?.[0]?.updated_at) return - - setUpdatedAt(data.producers[0].updated_at) }, [data]) const handleFilter = useCallback(value => { @@ -65,7 +60,7 @@ const useEndpointsState = () => { }, [setPagination]) return [ - { loading, pagination, producers: items, updatedAt, filters }, + { loading, pagination, producers: items, filters }, { handleFilter, handleOnPageChange, handleOnSearch, setPagination }, ] } diff --git a/webapp/src/hooks/customHooks/useHealthCheckHistoryState.js b/webapp/src/hooks/customHooks/useHealthCheckHistoryState.js index 4fc069e8..0e575afc 100644 --- a/webapp/src/hooks/customHooks/useHealthCheckHistoryState.js +++ b/webapp/src/hooks/customHooks/useHealthCheckHistoryState.js @@ -51,19 +51,23 @@ const useHealthCheckState = () => { useEffect(() => { if (!producers?.length) return - setProducersNames( - producers.map(producer => ({ - id: producer.id, - name: producer?.bp_json?.org?.candidate_name, - })), - ) + const formattedProducers = producers.map((producer) => ({ + id: producer.id, + name: + producer?.bp_json?.org?.candidate_name || + producer?.bp_json?.org?.organization_name || + producer?.owner, + })) + + setProducersNames(formattedProducers) const id = location?.state?.producerId const producer = - producers.find(producer => producer.id === id) || producers[0] + formattedProducers.find(producer => producer.id === id) || + formattedProducers[0] - setSelected(id || producers[0]?.id) - setSelectedName(producer?.bp_json?.org?.candidate_name) + setSelected(id || formattedProducers[0]?.id) + setSelectedName(producer?.name) window.history.replaceState({}, document.title) }, [producers, location]) diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json index 3d5a9cb5..a5e0afc5 100644 --- a/webapp/src/language/en.json +++ b/webapp/src/language/en.json @@ -44,7 +44,10 @@ "bugRequest": "Report a bug / Request a feature", "moreInfo": "More Info", "openLink": "Visit Site", - "table": "Table" + "table": "Table", + "noOptions": "No matches", + "updatedAt": "Updated at", + "nextUpdateAt": "Next updated at" }, "routes": { "/>sidebar": "Dashboard", @@ -208,10 +211,16 @@ }, "subtitle3": "Where Does the Data Come From?", "body3": { - "paragraph1": "Antelope Tools provides a detailed and graphic visualization of relevant information of entities running nodes and blockchain infrastructure. We source data on-chain directly from the public blockchain tables and information provided by Block Producers in their bp.json files.", - "paragraph2": "For more information about Antelope Tools, visit our GitHub repo or contact us on our Telegram group. Contact us and join our effort to make EOSIO chains even more transparent and easy to use." + "paragraph1Text1": "Antelope Tools provides a detailed and graphic visualization of relevant information of entities running nodes and blockchain infrastructure. We source data on-chain directly from the public table of producers in the account", + "paragraph1Text2": ", discarding those that aren't active. From the list, we obtain the URL addresses of the BPs to retrieve their data using the", + "paragraph2": "The bp.json contains information about the producer, its nodes, and endpoints. However, it's not queried directly, as there are several networks based on the Antelope protocol, the chains.json object is queried under the producer's website address, thus the correct address of the bp.json is obtained according to the chain_id of the network.", + "paragraph3": "It's important to note that if the chains.json object is not accessible or doesn't contain the chain_id, /bp.json is directly queried. However, this may belong to another network, so only the organizational information of the producer is used and the rest is omitted.", + "paragraph4Text1": "If the registered URL is https://edenia.com/ then it's retrieved first", + "paragraph4Text2": "and the bp.json associated with the id is retrieved. If it does not exist then it's tried with", + "paragraph4Text3": ", but, nodes and endpoints aren't included", + "paragraph5": "For more information about Antelope Tools, visit our GitHub repo or contact us on our Telegram group. Contact us and join our effort to make EOSIO chains even more transparent and easy to use." }, - "bpjsonexample": "Bp.json example" + "standard": "bp.json standard" }, "helpRoute": { "title": "Thank you for using Antelope Tools Blockchain Network Monitor !", @@ -333,7 +342,6 @@ }, "endpointsListRoute": { "title": "Endpoints available by", - "updatedAt": "Updated at", "endpointsResponding": "Only endpoints responding", "showList": "Show List" }, diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json index e2e19b66..5fde0546 100644 --- a/webapp/src/language/es.json +++ b/webapp/src/language/es.json @@ -55,7 +55,10 @@ "bugRequest": "Reportar un problema / Solicitar una característica ", "moreInfo": "Más Información", "openLink": "Visitar Sitio", - "table": "Tabla" + "table": "Tabla", + "noOptions": "Sin coincidencias", + "updatedAt": "Última actualización", + "nextUpdateAt": "Próxima actualización" }, "routes": { "/>sidebar": "Panel", @@ -215,10 +218,16 @@ }, "subtitle3": "¿De dónde se obtienen los datos?", "body3": { - "paragraph1": "Antelope Tools proporciona una visualización detallada y gráfica de la información relevante de las entidades que ejecutan los nodos y la infraestructura de la cadena de bloques. Obtenemos los datos on-chain directamente de las tablas públicas de blockchain y de la información proporcionada por los productores de bloques en sus archivos bp.json.", - "paragraph2": "Para mayor información acerca Antelope Tools, visite nuestro repositorio en GitHub o contáctenos en nuestro grupo de Telegram. Póngase en contacto con nosotros y únase a nuestro esfuerzo por hacer que las blockchains de EOSIO sean aún más transparentes y fáciles de usar." + "paragraph1Text1": "Antelope Tools proporciona una visualización detallada y gráfica de la información relevante de las entidades que ejecutan los nodos y la infraestructura de la cadena de bloques. Obtenemos los datos on-chain directamente de la tabla pública de producers en la cuenta", + "paragraph1Text2": ", descartando aquellos que no están activos. De la lista se obtienen las direcciones url de los BPs para recuperar sus datos mediante el", + "paragraph2": "El bp.json contiene información sobre el productor, sus nodos y endpoints. Sin embargo, no se consulta directamente, ya que existen varias redes basadas en el protocolo de Antelope, en cambio, se consulta el objeto chains.json bajo la dirección del sitio web del productor, de este modo se obtiene la dirección correcta del bp.json según el chain_id de la red.", + "paragraph3": "Es importante destacar que si el objeto chains.json no es accesible o no contiene el chain_id, se consulta directamente /bp.json. Sin embargo, este puede pertenecer a otra red, por lo que solo se utiliza la información organizacional del productor y el resto se omite.", + "paragraph4Text1": "Si se considera que la url registrada es https://edenia.com/ entonces primero se recupera", + "paragraph4Text2": "y se obtiene el bp.json asociado al id. Si no existe se intenta con", + "paragraph4Text3": ", pero, los nodos y endpoints no se incluyen", + "paragraph5": "Para mayor información acerca Antelope Tools, visite nuestro repositorio en GitHub o contáctenos en nuestro grupo de Telegram. Póngase en contacto con nosotros y únase a nuestro esfuerzo por hacer que las blockchains de EOSIO sean aún más transparentes y fáciles de usar." }, - "bpjsonexample": "Ejemplo de bp.json" + "standard": "estándar del bp.json" }, "helpRoute": { "title": "¡Gracias por usar el monitor de red Blockchain de Antelope Tools!", diff --git a/webapp/src/routes/About/index.js b/webapp/src/routes/About/index.js index b5dca9b8..342c0f3a 100644 --- a/webapp/src/routes/About/index.js +++ b/webapp/src/routes/About/index.js @@ -2,9 +2,12 @@ import React from 'react' import Typography from '@mui/material/Typography' import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' +import { Link as RouterLink } from 'react-router-dom' import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' +import { eosConfig } from '../../config' + import Logo from './Logo' import styles from './styles' @@ -18,47 +21,79 @@ const About = () => {
-
-
- - {t('body.paragraph1')} - -
- -
- {t('subtitle1')} - - {t('body1.paragraph1')} - -
- -
- {t('subtitle2')} - - {t('body2.paragraph1')} - -
- -
- {t('subtitle3')} - - {t('body3.paragraph1')} - - {t('bpjsonexample')} - - - - {t('body3.paragraph2')} - -
+
+
+
+ + {t('body.paragraph1')} + + {t('subtitle1')} + + {t('body1.paragraph1')} + + {t('subtitle2')} + + {t('body2.paragraph1')} + + {t('subtitle3')} + {eosConfig.networkName !== 'lacchain' ? ( + <> + + {t('body3.paragraph1Text1')}{' '} + + eosio + + {t('body3.paragraph1Text2')}{' '} + + {t('standard')}. + + -
- + + {t('body3.paragraph2')} + + + {t('body3.paragraph3')} + + + {t('body3.paragraph4Text1')}{' '} + + https://edenia.com/chains.json + {' '} + {t('body3.paragraph4Text2')}{' '} + + https://edenia.com/bp.json + + {eosConfig.networkName !== 'mainnet' && + t('body3.paragraph4Text3')} + . + + + ) : ( + + {t('body3.paragraph1Text1')}{' '} + + eosio + + . + + )} + + {t('body3.paragraph5')} +
diff --git a/webapp/src/routes/About/styles.js b/webapp/src/routes/About/styles.js index e03d0d6b..ee96232e 100644 --- a/webapp/src/routes/About/styles.js +++ b/webapp/src/routes/About/styles.js @@ -13,21 +13,28 @@ export default (theme) => ({ marginBottom: theme.spacing(4), }, }, + logoContainer: { + [theme.breakpoints.down('md')]: { + order: 1, + }, + }, logo: { width: 569, height: 498, + float: 'right', [theme.breakpoints.down('md')]: { - width: '85%', + width: '100%', }, }, cardShadow: { boxShadow: '0px 1px 5px rgba(0, 0, 0, 0.15) !important', }, mainText: { - display: 'flex', - flexDirection: 'row', + width: '100%', + overflow: 'hidden', [theme.breakpoints.down('md')]: { - flexDirection: 'column' + display: 'flex', + flexDirection: 'column', }, - } + }, }) diff --git a/webapp/src/routes/BlockProducers/index.js b/webapp/src/routes/BlockProducers/index.js index 928fee2a..dad0c5ab 100644 --- a/webapp/src/routes/BlockProducers/index.js +++ b/webapp/src/routes/BlockProducers/index.js @@ -9,6 +9,7 @@ import SearchBar from '../../components/SearchBar' import InformationCard from '../../components/InformationCard' import useBlockProducerState from '../../hooks/customHooks/useBlockProducerState' import NoResults from '../../components/NoResults' +import ProducersUpdateLog from 'components/ProducersUpdateLog' import styles from './styles' @@ -52,6 +53,7 @@ const Producers = () => { return ( <> +
{ const classes = useStyles() const { t } = useTranslation('endpointsListRoute') const [ - { loading, pagination, producers, updatedAt, filters }, + { loading, pagination, producers, filters }, { handleFilter, handleOnSearch, handleOnPageChange, setPagination }, ] = useEndpointsState({ useCache: false }) @@ -42,47 +42,45 @@ const EndpointsList = () => { {t('title')} {t('producer')} - {updatedAt && ( + +
+
+
- {t('updatedAt')}: {moment(updatedAt).format('LLL')} + {t('endpointsResponding')} - )} -
-
- - {t('endpointsResponding')} - - { - handleFilter(event.target?.checked) - }} - /> -
-
- + { + handleFilter(event.target?.checked) + }} + /> +
+
+ +
+ + {t('itemsPerPage')} + +
- - {t('itemsPerPage')} - -
{ ) : ( <> - {!!producers?.length ? ( + {!!producers?.length ? ( ) : ( diff --git a/webapp/src/routes/EndpointsList/styles.js b/webapp/src/routes/EndpointsList/styles.js index 4682ce17..70c1a80d 100644 --- a/webapp/src/routes/EndpointsList/styles.js +++ b/webapp/src/routes/EndpointsList/styles.js @@ -5,7 +5,17 @@ export default (theme) => ({ alignItems: 'center', }, dateContainer: { - flex: '40%', + flex: '50%', + display: 'flex', + flexDirection: 'column', + '& div': { + gap: theme.spacing(2), + margin: theme.spacing(2, 0, 2), + }, + }, + controlFormContainer: { + display: 'flex', + flexWrap: 'wrap', }, switchContainer: { display: 'flex', diff --git a/webapp/src/routes/EndpointsStats/index.js b/webapp/src/routes/EndpointsStats/index.js index 9bac286d..d5410c00 100644 --- a/webapp/src/routes/EndpointsStats/index.js +++ b/webapp/src/routes/EndpointsStats/index.js @@ -96,6 +96,7 @@ const EndpointsStats = () => { renderInput={params => ( )} + noOptionsText={t('noOptions')} /> )} {historyData && ( diff --git a/webapp/src/routes/Home/styles.js b/webapp/src/routes/Home/styles.js index f9a55a13..31917a0b 100644 --- a/webapp/src/routes/Home/styles.js +++ b/webapp/src/routes/Home/styles.js @@ -102,6 +102,9 @@ export default (theme) => ({ [theme.breakpoints.down('md')]: { marginBottom: '10px', }, + '& .MuiPaper-root': { + height: '100%', + }, }, cardGrow: { flexGrow: '1', @@ -110,6 +113,9 @@ export default (theme) => ({ flexBasis: 'calc(100%/3)', marginBottom: '10px', }, + '& .MuiPaper-root': { + height: '100%', + }, }, uniquelocations: { flexGrow: '1 !important', diff --git a/webapp/src/routes/Nodes/index.js b/webapp/src/routes/Nodes/index.js index 46f1ae87..8918f3c3 100644 --- a/webapp/src/routes/Nodes/index.js +++ b/webapp/src/routes/Nodes/index.js @@ -11,6 +11,9 @@ const Pagination = lazy(() => import('@mui/material/Pagination')) const SearchBar = lazy(() => import('../../components/SearchBar')) const InformationCard = lazy(() => import('../../components/InformationCard')) const NoResults = lazy(() => import('../../components/NoResults')) +const ProducersUpdateLog = lazy(() => + import('../../components/ProducersUpdateLog'), +) const useStyles = makeStyles(styles) @@ -23,6 +26,7 @@ const Nodes = () => { return ( <> +