diff --git a/cmd/dcrdata/public/js/controllers/attackcost_controller.js b/cmd/dcrdata/public/js/controllers/attackcost_controller.js index 7c9960ad4..a4d12f68f 100644 --- a/cmd/dcrdata/public/js/controllers/attackcost_controller.js +++ b/cmd/dcrdata/public/js/controllers/attackcost_controller.js @@ -85,10 +85,10 @@ function legendFormatter (data) { const yVals = data.series.reduce((nodes, series) => { if (!series.isVisible) return nodes const precession = series.y >= 1 ? 2 : 6 - return `${nodes} ${series.labelHTML}:  ${digitformat(series.y, precession)}x` + return `${nodes} ${series.labelHTML}: ${digitformat(series.y, precession)}x` }, '
') - html = `${this.getLabels()[0]}: ${digitformat(data.x, 1)}${yVals}` + html = `${this.getLabels()[0]}: ${digitformat(data.x, 0)}${yVals}` } dompurify.sanitize(html) return html @@ -113,13 +113,13 @@ export default class extends Controller { static get targets () { return [ 'actualHashRate', 'attackPercent', 'attackPeriod', 'blockHeight', 'countDevice', 'device', - 'deviceCost', 'deviceDesc', 'deviceName', 'external', 'internal', 'internalHash', 'kwhRate', + 'deviceCost', 'deviceDesc', 'deviceName', 'devicePronoun', 'deviceSuffix', 'external', 'internal', 'internalHash', 'kwhRate', 'kwhRateLabel', 'otherCosts', 'otherCostsValue', 'priceDCR', 'internalAttackText', 'targetHashRate', 'externalAttackText', 'externalAttackPosText', 'additionalDcr', 'newTicketPoolValue', 'internalAttackPosText', 'additionalHashRate', 'newHashRate', 'targetPos', 'targetPow', 'ticketAttackSize', 'ticketPoolAttack', 'ticketPoolSize', - 'ticketPoolSizeLabel', 'ticketPoolValue', 'ticketPrice', 'tickets', 'ticketSizeAttack', 'durationLongDesc', + 'ticketPoolSizeLabel', 'ticketPoolValue', 'ticketPrice', 'tickets', 'ticketSizeAttack', 'durationUnit', 'durationLongDesc', 'total', 'totalDCRPos', 'totalDeviceCost', 'totalElectricity', 'totalExtraCostRate', 'totalKwh', 'totalPos', 'totalPow', - 'graph', 'labels', 'projectedTicketPrice', 'projectedTicketPriceIncrease', 'attackType', 'attackPosPercentAmountLabel', + 'graph', 'labels', 'projectedTicketPrice', 'projectedTicketPriceIncrease', 'projectedTicketPriceSign', 'attackType', 'attackPosPercentAmountLabel', 'dcrPriceLabel', 'totalDCRPosLabel', 'projectedPriceDiv', 'attackNotPossibleWrapperDiv', 'coinSupply', 'totalAttackCostContainer' ] } @@ -155,12 +155,12 @@ export default class extends Controller { if (this.settings.attack_time) this.attackPeriodTarget.value = parseInt(this.settings.attack_time) if (this.settings.target_pow) this.targetPowTarget.value = parseFloat(this.settings.target_pow) if (this.settings.kwh_rate) this.kwhRateTarget.value = parseFloat(this.settings.kwh_rate) - if (this.settings.other_costs) this.otherCostsTarget.value = parseFloat(this.settings.other_cost) + if (this.settings.other_costs) this.otherCostsTarget.value = parseFloat(this.settings.other_costs) if (this.settings.target_pos) this.setAllInputs(this.targetPosTargets, parseFloat(this.settings.target_pos)) if (this.settings.price) this.priceDCRTarget.value = parseFloat(this.settings.price) if (this.settings.device) this.setDevice(this.settings.device) if (this.settings.attack_type) this.attackTypeTarget.value = this.settings.attack_type - if (this.settings.target_pos) this.attackPercentTarget.value = parseInt(this.targetPosTarget.value) / 100 + if (this.settings.target_pos) this.attackPercentTarget.value = parseFloat(this.targetPosTarget.value) / 100 if (this.settings.attack_type !== internalAttackType) { this.settings.attack_type = externalAttackType @@ -208,9 +208,9 @@ export default class extends Controller { const options = { ...nightModeOptions(false), - labels: ['Attackers Tickets', 'Hash Power Multiplier'], + labels: ['Attacker Tickets', 'Hash Power Multiplier'], ylabel: 'Hash Power Multiplier', - xlabel: 'Attackers Tickets', + xlabel: 'Attacker Tickets', axes: { y: { axisLabelWidth: 70 @@ -336,7 +336,7 @@ export default class extends Controller { this.deviceDescTargets.map((n) => { const info = deviceList[n.value] if (!info) return - n.innerHTML = `${info.name}, ${info.hashrate} ${info.units}, ${info.power}w, $${digitformat(info.cost)} per unit` + n.innerHTML = `${info.name} (${info.hashrate} ${info.units}, ${info.power} W, $${digitformat(info.cost)} ea.)` }) } @@ -372,13 +372,13 @@ export default class extends Controller { this.projectedPriceDivTarget.style.display = 'block' this.internalAttackTextTarget.classList.add('d-none') this.internalAttackPosTextTarget.classList.add('d-none') - this.externalAttackTextTarget.classList.remove('d-none') + this.showAll(this.externalAttackTextTargets) this.externalAttackPosTextTarget.classList.remove('d-node') break case internalAttackType: default: this.projectedPriceDivTarget.style.display = 'none' - this.externalAttackTextTarget.classList.add('d-none') + this.hideAll(this.externalAttackTextTargets) this.externalAttackPosTextTarget.classList.add('d-node') this.internalAttackTextTarget.classList.remove('d-none') this.internalAttackPosTextTarget.classList.remove('d-none') @@ -436,13 +436,17 @@ export default class extends Controller { this.setAllValues(this.ticketPoolAttackTargets, digitformat(DCRNeed)) } const projectedTicketPrice = DCRNeed / tpSize - this.projectedTicketPriceIncreaseTarget.innerHTML = digitformat(100 * (projectedTicketPrice - tpPrice) / tpPrice, 2) + this.projectedTicketPriceIncreaseTarget.innerHTML = digitformat(100 * Math.abs(projectedTicketPrice - tpPrice) / tpPrice, 2) + this.projectedTicketPriceSignTarget.innerHTML = projectedTicketPrice > tpPrice ? 'increase' : 'decrease' this.ticketPoolValueTarget.innerHTML = digitformat(hashrate, 3) const totalDCRPos = this.settings.attack_type === externalAttackType ? DCRNeed - tpValue : ticketAttackSize * projectedTicketPrice const totalPos = totalDCRPos * dcrPrice - let timeStr = this.attackPeriodTarget.value - timeStr = this.attackPeriodTarget.value > 1 ? timeStr + ' hours' : timeStr + ' hour' + const timeStr = this.attackPeriodTarget.value + const hourStr = timeStr > 1 ? 'hours' : 'hour' + const timeHourStr = timeStr + ' ' + hourStr + const devicePronounStr = deviceCount > 1 ? 'them' : 'it' + const deviceSuffixStr = deviceCount > 1 ? 's' : '' this.ticketPoolSizeLabelTarget.innerHTML = digitformat(tpSize, 2) this.setAllValues(this.actualHashRateTargets, digitformat(hashrate, 4)) this.priceDCRTarget.value = digitformat(dcrPrice, 2) @@ -450,9 +454,12 @@ export default class extends Controller { this.ticketPriceTarget.innerHTML = digitformat(tpPrice, 4) this.setAllValues(this.targetHashRateTargets, digitformat(this.targetHashRate, 4)) this.setAllValues(this.additionalHashRateTargets, digitformat(this.targetHashRate, 4)) - this.setAllValues(this.durationLongDescTargets, timeStr) + this.durationUnitTarget.innerHTML = hourStr + this.setAllValues(this.durationLongDescTargets, timeHourStr) this.setAllValues(this.countDeviceTargets, digitformat(deviceCount)) - this.setAllValues(this.deviceNameTargets, `${deviceInfo.name}s`) + this.devicePronounTarget.innerHTML = devicePronounStr + this.deviceSuffixTarget.innerHTML = deviceSuffixStr + this.setAllValues(this.deviceNameTargets, `${deviceInfo.name}${deviceSuffixStr}`) this.setAllValues(this.totalDeviceCostTargets, digitformat(totalDeviceCost)) this.setAllValues(this.totalKwhTargets, digitformat(totalKwh, 2)) this.setAllValues(this.totalElectricityTargets, digitformat(totalElectricity, 2)) diff --git a/cmd/dcrdata/public/scss/attackcost.scss b/cmd/dcrdata/public/scss/attackcost.scss index f01f32629..93de51826 100644 --- a/cmd/dcrdata/public/scss/attackcost.scss +++ b/cmd/dcrdata/public/scss/attackcost.scss @@ -13,7 +13,6 @@ input[type=number]::-webkit-inner-spin-button { } .slider { - max-width: 500px; width: 100%; height: calc(1rem + 0.4rem); padding: 0; @@ -145,6 +144,15 @@ input[type=number]::-webkit-inner-spin-button { background-color: #adb5bd; } +.summary { + background-color: #f3f5f6; + bottom: 28px; +} + .b-radius { border-radius: 2px; } + +.min-w-0 { + min-width: 0; +} diff --git a/cmd/dcrdata/public/scss/charts.scss b/cmd/dcrdata/public/scss/charts.scss index 46739b989..e6bc7e146 100644 --- a/cmd/dcrdata/public/scss/charts.scss +++ b/cmd/dcrdata/public/scss/charts.scss @@ -347,9 +347,11 @@ body.darkBG .chartview .dygraph-y2label { } .chart-form-control { + width: -moz-fit-content; width: fit-content; font-size: 0.9rem !important; height: calc(1.5em + 0.5rem + 2px) !important; + line-height: 1; } .chart-control select, @@ -363,14 +365,13 @@ body.darkBG .chartview .dygraph-y2label { .legend-wrapper { position: absolute; - top: -2rem; + top: -2.5rem; left: 100px; right: 20px; } .legend { background: #ececec; - z-index: 10000; padding: 5px 10px 5px 20px; font-size: 14px; } diff --git a/cmd/dcrdata/views/attackcost.tmpl b/cmd/dcrdata/views/attackcost.tmpl index d5f3cd1bd..c9d166026 100644 --- a/cmd/dcrdata/views/attackcost.tmpl +++ b/cmd/dcrdata/views/attackcost.tmpl @@ -29,14 +29,14 @@ Chart
-
+
-
+
- Description + Description
- If an attacker has in their control + If an attacker has in their control 0 and - 0 (HashRate) + 0 hashrate, they will be able to generate blocks at the same average speed as the honest network.
@@ -62,13 +62,13 @@
{{- /* NETWORK PARAMETERS */ -}} -
+
- Current Mainnet Parameters + Current {{.NetName}} Parameters
-
-
+
+
Best Block
@@ -76,19 +76,19 @@
-
+
- Hash Rate + Hashrate
Ph/s
-
-
+
+
- Ticket Pool size + Ticket Pool Size
0
@@ -107,13 +107,13 @@
{{- /* ADJUSTABLE PARAMETERS */ -}} -
+
Adjustable Parameters
-
-
+
+
Attack Time @@ -127,9 +127,10 @@ min="1" max="1000" value="1" + size="4" > - hrs + hour(s)
@@ -146,28 +147,30 @@ min="0.1" value="0.1" max="1000" + size="6" > - USD/kWh + USD/kWh
-
+
- USD-DCR Rate + Exchange Rate
- USD/DCR + USD/DCR
@@ -175,7 +178,7 @@ Attack Type
- - - +
+
+ Mining Device: + +
@@ -215,47 +220,51 @@ type="number" data-target="attackcost.targetPow" data-action="change->attackcost#updateTargetPow" - step="1" - min="1" - max="1000000" + step="0.01" + min="0.01" + max="10000000" + size="11" {{/*autofocus*/}} >% - PoW attack would need 0 - Ph/s. + PoW attack would need 0 + Ph/s. - PoW attack requires adding 0 - Ph/s to the existing 0 - Ph/s network hashrate. New network hashrate will be - 0 - Ph/s. + PoW attack requires adding 0 + Ph/s to the existing 0 + Ph/s network hashrate.
+
+ New network hashrate will be + 0 + Ph/s. +
- In order to aquire a 0 Ph/s + In order to acquire a 0 Ph/s hashrate, it would take 0 - at a cost of $0 - USD to buy them. + at a cost of $0 + USD to buy them.
- Total kWh attack for 0 is + Electricity consumed by 0 + in + 0 is - 0 kWh - + 0 kWh.
- Costs of 0 + Cost of 0 electricity consumption for 0 is $0 - USD - + USD.
To carry out the attack, additional costs for facilities and cooling are estimated at @@ -267,43 +276,47 @@ min="1" max="100" value="5" - >% of the cost of the miners. The additional facility cost is $0. + size="3" + >% of the cost of the miner(s).
- Total PoW attack cost is + The additional facility cost is $0 + USD. +
+
+ Total PoW attack cost: $0 - USD - + USD.
{{- /* POS ATTACK */ -}} -
+
PoS Attack
- A 0 DCR. +
+
+ An internal % PoS attack would need 0 - tickets. - -
-
- Total staked is - 0 DCR + tickets.
@@ -311,48 +324,49 @@ DCR is needed for the attack - ( - 0 DCR + (0 DCR * - 0% - ) + 0%).
+ Total PoS attack cost: $0 + USD - total PoS attack cost - ( - 0 DCR + (0 DCR * - 0 USD/DCR - ) + $0 USD/DCR).
- Current total staked is 0 DCR. + Current total staked is + 0 DCR.
An external % PoS attack would add - 0 DCR + 0 DCR to the total staked.
- New total staked will be 0 DCR. + New total staked will be + 0 DCR.
{{- /* CALCULATED PoS WARNING DISPLAY */ -}}
The projected ticket price is @@ -360,24 +374,24 @@ 0 DCR - (A 0% increase). + (A 0% + change).
+ Total PoS attack cost: $0 + USD - total PoS attack cost - ( - 0 DCR + (0 DCR * - 0 USD/DCR - ) + $0 USD/DCR).
{{- /* CALCULATION SUMMARY */ -}} -
+
Total attack cost: $0