diff --git a/src/web/controls/custom-deploy-ctrl.js b/src/web/controls/custom-deploy-ctrl.js index 3acaed6..b05e0be 100644 --- a/src/web/controls/custom-deploy-ctrl.js +++ b/src/web/controls/custom-deploy-ctrl.js @@ -90,7 +90,7 @@ export const customDeployCtrl = (st, {wallet = [], node, onSendDeploy, onPropose } // Control state - const {selRevAddr, code, phloLimit, status, dataError, proposeStatus, proposeError} + const {selRevAddr, code, phloLimit, status, dataError, proposeStatus, proposeError, fetching} = initSelected(st.view({}), wallet) const tokenName = node.tokenName @@ -99,7 +99,7 @@ export const customDeployCtrl = (st, {wallet = [], node, onSendDeploy, onPropose const labelPhloLimit = `Phlo limit (in tiny ${tokenName} x10^${node.tokenDecimal})` const isWalletEmpty = R.isNil(wallet) || R.isEmpty(wallet) const showPropose = node.network === 'localnet' - const canDeploy = (code || '').trim() !== '' && !!selRevAddr + const canDeploy = (code || '').trim() !== '' && !!selRevAddr && !fetching const phloLimitPreview = showTokenDecimal(phloLimit, node.tokenDecimal) return m('.ctrl.custom-deploy-ctrl', diff --git a/src/web/controls/main-ctrl.js b/src/web/controls/main-ctrl.js index c0a2daa..f11709c 100644 --- a/src/web/controls/main-ctrl.js +++ b/src/web/controls/main-ctrl.js @@ -13,12 +13,16 @@ import { transferCtrl } from './transfer-ctrl' import { customDeployCtrl } from './custom-deploy-ctrl' import { newRevAddress } from '@tgrospic/rnode-grpc-js' +import { makeRNodeWeb } from '../../rnode-web' + /* This will display the test page to select local, testnet, and mainnet validators and make REV transfers and check balance. */ +const {rnodeHttp} = makeRNodeWeb({fetch}) const repoUrl = 'https://github.com/tgrospic/rnode-client-js' +const randomOffset = Math.floor(Math.random() * (2 - 1 + 1)) + 1 //Random number between 1 and 2, for load balancing const mainCtrl = (st, effects) => { const { appCheckBalance, appTransfer, appSendDeploy, appPropose, log, warn } = effects @@ -47,13 +51,14 @@ const mainCtrl = (st, effects) => { .set(account) // State lenses for each control - const selSt = st.o('sel') - const addressSt = st.o('address') - const balanceSt = st.o('balance') - const transferSt = st.o('transfer') - const customDeploySt = st.o('customDeploy') - - const {nets, netsDev, netsTestMain, sel, wallet, devMode} = st.view() + const selSt = st.o('sel') + const addressSt = st.o('address') + const balanceSt = st.o('balance') + const transferSt = st.o('transfer') + const customDeploySt = st.o('customDeploy') + const autoSelectIntervalSt = st.o('autoSelectInterval') + + const {nets, netsDev, netsTestMain, sel, wallet, devMode, autoSelectDisabled} = st.view() const valNodeUrls = getNodeUrls(sel.valNode) const readNodeUrls = getNodeUrls(sel.readNode) @@ -68,6 +73,42 @@ const mainCtrl = (st, effects) => { st.update(s => ({...s, nets, sel, devMode: enabled})) } + const FetchNextValidator = async () => { + const {autoSelectDisabled} = st.view() + if (autoSelectDisabled) { + //Disables transfer/deploy buttons once during toggle + transferSt.update(s => ({...s, fetching: true})) + customDeploySt.update(s => ({...s, fetching: true})) + } + const { nextToPropose } = await rnodeHttp("https://status.rchain.coop", 'validators') + + const net = nets[1] //Select Mainnet + + const next = net.hosts.filter(obj => { + return obj.domain === nextToPropose.host + })[0]; + const nextId = net.hosts.indexOf(next); + + const sel = {valNode: net.hosts[(nextId + randomOffset) % net.hosts.length], readNode: net.readOnlys[0]} + + st.update(s => ({...s, sel})) + transferSt.update(s => ({...s, fetching: false})) + customDeploySt.update(s => ({...s, fetching: false})) + } + + const onAutoSelectToggle = ({disabled}) => { + if (!disabled) { + const interval = setInterval(FetchNextValidator, 5 * 1000) + autoSelectIntervalSt.set({interval: interval}) + FetchNextValidator() //Trigger immediately + } else { + const {interval} = autoSelectIntervalSt.view({}) + clearInterval(interval) + } + + st.update(s => ({...s, autoSelectDisabled: disabled})) + } + // TEMP: Hard Fork 1 info const startMs = new Date('2021-07-18 15:00').getTime() const endMs = new Date('2021-07-25 01:00').getTime() @@ -94,7 +135,7 @@ const mainCtrl = (st, effects) => { // Selector control m('hr'), - selectorCtrl(selSt, {nets, onDevMode}), + selectorCtrl(selSt, {nets, onDevMode, onAutoSelectToggle}), // REV wallet control addressCtrl(addressSt, {wallet, node: valNodeUrls, onAddAccount: onSaveAccount}), @@ -128,6 +169,7 @@ const prepareNets = nets => })) const devMode = false +const autoSelectDisabled = true const netsDev = prepareNets([localNet]) const netsTestMain = prepareNets([testNet, mainNet]) const nets = devMode ? netsDev : netsTestMain @@ -146,6 +188,7 @@ const initialState = { wallet: [], // [{name: 'My REV account', ...newRevAddress()}], // Dev mode (show local networks) devMode, + autoSelectDisabled: autoSelectDisabled } export const startApp = (element, effects) => { diff --git a/src/web/controls/selector-ctrl.js b/src/web/controls/selector-ctrl.js index 15123b7..bd8cf63 100644 --- a/src/web/controls/selector-ctrl.js +++ b/src/web/controls/selector-ctrl.js @@ -3,7 +3,7 @@ import * as R from 'ramda' import m from 'mithril' import { getNodeUrls } from '../../rchain-networks' -export const selectorCtrl = (st, {nets, onDevMode}) => { +export const selectorCtrl = (st, {nets, onDevMode, onAutoSelectToggle}) => { const findValidatorByIndex = index => nets.flatMap(({hosts}) => hosts)[index] @@ -13,6 +13,8 @@ export const selectorCtrl = (st, {nets, onDevMode}) => { const onSelIdx = ev => { const sel = findValidatorByIndex(ev.target.selectedIndex) const read = sel.name === valNode.name ? readNode : findReadOnlyByIndex(0, sel.name) + const isMainnet = sel.name === 'mainnet' + sel.name !== valNode.name ? onAutoSelectToggle({disabled: !isMainnet}) : undefined st.set({valNode: sel, readNode: read}) } @@ -26,6 +28,11 @@ export const selectorCtrl = (st, {nets, onDevMode}) => { onDevMode({enabled: checked}) } + const onAutoSelectInput = ev => { + const checked = ev.target?.checked || false + onAutoSelectToggle({disabled: checked}) + } + const getDdlText = ({name, domain, grpc, https, http}) => { const httpInfo = !!https ? `:${https}` : !!http ? `:${http}` : ' ' const isLocal = name === 'localnet' @@ -36,7 +43,7 @@ export const selectorCtrl = (st, {nets, onDevMode}) => { R.eqBy(({domain, gprc, https, http}) => ({domain, gprc, https, http}), v1, v2) // Control state - const {valNode, readNode, devMode} = st.view({}) + const {valNode, readNode, devMode, autoSelectDisabled} = st.view({}) const isLocal = valNode.name === 'localnet' const isTestnet = valNode.name === 'testnet' @@ -45,6 +52,7 @@ export const selectorCtrl = (st, {nets, onDevMode}) => { const readUrls = getNodeUrls(readNode) // Dev mode tooltip text const devModeText = `Development mode for locally accessible nodes` + const autoSelectText = `Disable automatic selection of validator` return m('.ctrl.selector-ctrl', // Validator selector @@ -66,6 +74,11 @@ export const selectorCtrl = (st, {nets, onDevMode}) => { ), ), + isMainnet && [ + m('label', {title: autoSelectText}, + m('input[type=checkbox]', {checked: autoSelectDisabled, oninput: onAutoSelectInput}), 'Disable Auto Select') + ], + // Validator info m(''), m('span', 'Direct links'), diff --git a/src/web/controls/transfer-ctrl.js b/src/web/controls/transfer-ctrl.js index c76d4b3..d8d4b16 100644 --- a/src/web/controls/transfer-ctrl.js +++ b/src/web/controls/transfer-ctrl.js @@ -47,14 +47,14 @@ export const transferCtrl = (st, {wallet, node, onTransfer, warn}) => { } // Control state - const {account, toAccount, amount, status, error} = initSelected(st.view({}), wallet) + const {account, toAccount, amount, status, error, fetching} = initSelected(st.view({}), wallet) const {tokenName, tokenDecimal} = node const labelSource = `Source ${tokenName} address` const labelDestination = `Destination ${tokenName} address` const labelAmount = `Amount (in tiny ${tokenName} x10^${tokenDecimal})` const isWalletEmpty = R.isNil(wallet) || R.isEmpty(wallet) - const canTransfer = account && toAccount && amount && (account || ethDetected) + const canTransfer = account && toAccount && amount && (account || ethDetected) && !fetching const amountPreview = showTokenDecimal(amount, tokenDecimal) return m('.ctrl.transfer-ctrl',