consensus/cmd/web/views/miner.qtpl

278 lines
13 KiB
Plaintext

{% import "git.gammaspectra.live/P2Pool/p2pool-observer/cmd/index" %}
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain" %}
{% import p2pooltypes "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/types" %}
{% import cmdutils "git.gammaspectra.live/P2Pool/p2pool-observer/cmd/utils" %}
{% code
type MinerPage struct {
// inherit from base page, so its' title is used in error page.
BasePage
Refresh int
Positions struct {
Resolution int
ResolutionWindow int
SeparatorIndex int
Blocks *cmdutils.PositionChart
Uncles *cmdutils.PositionChart
BlocksInWindow *cmdutils.PositionChart
UnclesInWindow *cmdutils.PositionChart
Payouts *cmdutils.PositionChart
}
ExpectedRewardPerWindow uint64
ExpectedRewardPerDay uint64
WindowWeight uint64
Weight uint64
Miner *cmdutils.MinerInfoResult
LastPoolBlock *sidechain.PoolBlock
LastShares []*index.SideBlock
LastSharesEfforts []float64
LastOrphanedShares []*index.SideBlock
LastFound []*index.FoundBlock
LastPayouts []*index.Payout
LastSweeps <-chan *index.MainLikelySweepTransaction
HashrateSubmit bool
HashrateLocal float64
MagnitudeLocal float64
}
%}
{% func (p *MinerPage) Title() %}
{%= p.BasePage.Title() %} - Miner {%z= p.Miner.Address.ToBase58() %}
{% endfunc %}
{% func (p *MinerPage) Content() %}
<div style="text-align: center; font-weight: bold;">
{% if p.Refresh > 0 %}
<a href="/miner/{%z= p.Miner.Address.ToBase58() %}">Autorefresh is ON ({%d p.Refresh %} s)</a>
{% else %}
<a href="/miner/{%z= p.Miner.Address.ToBase58() %}?refresh">Autorefresh is OFF</a>
{% endif %}
</div>
<div style="text-align: center">
{% if p.Miner.LastShareTimestamp == 0 %}
<div style="border: #d1d1d1 1px dashed;">
<h3 style="color:#FF4433">No shares have been reported to this P2Pool network in the past for this miner.</h3>
<p>Finding shares is a random process based on your hashrate vs this P2Pool hashrate. This can take several days for low hashrate miners, and depending on your luck.</p>
<p>Please use the calculator below to find your average share time (with average luck).</p>
<p>You can also verify you are reachable by opening ports with the tool below.</p>
<br/>
<form action="/calculate-share-time" method="get">
<h3>Average Share Time Calculator</h3>
<label for="hashrate">Your Hashrate</label><br/>
<input type="numeric" name="hashrate" id="hashrate" placeholder="100" size="8" class="mono" value=""/>
<select name="magnitude">
<option value="1" selected>H/s</option>
<option value="1000">KH/s</option>
<option value="1000000">MH/s</option>
<option value="1000000000">GH/s</option>
</select>
<br/>
<input type="submit" value="Calculate" style="width: 20em; margin: 20px;"/>
</form>
<form action="/connectivity-check" method="get">
<h3>Connectivity Check</h3>
<div>
<label for="address">IP Address and Port</label><br/>
<input type="text" name="address" id="address" placeholder="5.9.17.234:{%dul uint64(p.Context().Consensus.DefaultPort()) %}" size="20" class="mono" value=""/>
</div>
<br/>
<div style="margin-top: 10px">
<input type="submit" value="Check" style="width: 20em;"/>
</div>
</form>
</div>
<hr/>
{% endif %}
{% if p.LastPoolBlock != nil && p.LastPoolBlock.ShareVersion() < sidechain.ShareVersion_V2 && p.LastPoolBlock.ShareVersionSignaling() != sidechain.ShareVersion_V2 %}
<div style="border: #d1d1d1 1px dashed;">
<h3 style="color:#FF4433" title="Share version {%s p.LastPoolBlock.ShareVersion().String() %}, signaling {%s p.LastPoolBlock.ShareVersionSignaling().String() %}">Recent shares indicate you are running an outdated version of P2Pool</h3>
<p>A new version of <a href="https://github.com/SChernykh/p2pool/releases/tag/v3.3">P2Pool (v3.0+)</a> has been released with several improvements, which requires a consensus change.</p>
<p>P2Pool (not Monero!) has hardforked to new consensus rules on <strong>March 18th, 2023 at 21:00 UTC</strong>. All versions before P2Pool v3.0 are incompatible. P2Pool v3.3+ is recommended.</p>
<p>If you keep using previous versions, you will keep mining as usual, but become almost a solo miner, as incompatible clients will mine on their own.</p>
<p>{% if p.Context().NetServiceAddress == "p2pool.observer" %}After the fork, you can check on <a href="{%s p.Context().GetUrl("old.p2pool.observer") %}/miner/{%z= p.Miner.Address.ToBase58() %}">OLD.P2Pool.Observer</a>.{% elseif p.Context().NetServiceAddress == "mini.p2pool.observer" %}After the fork, you can check on <a href="https://{%s p.Context().GetUrl("old-mini.p2pool.observer") %}/miner/{%z= p.Miner.Address.ToBase58() %}">OLD-MINI.P2Pool.Observer</a>.{% else %}Please check on an observer tracking the old chain.{% endif %}</p>
<p>After upgrading to a supported P2Pool version and mining a share, this message will be dismissed.</p>
<br/>
</div>
<hr/>
{% elseif p.LastPoolBlock != nil && p.LastPoolBlock.ShareVersion() > sidechain.ShareVersion_V1 && p.LastPoolBlock.Side.ExtraBuffer.SoftwareId == p2pooltypes.SoftwareIdP2Pool && p.LastPoolBlock.Side.ExtraBuffer.SoftwareVersion.String() != p.Context().Pool.Versions.P2Pool.ShortVersion().String() %}
<div style="border: #d1d1d1 1px dashed;">
<h3 style="color:#FF4433">Recent shares indicate you are running an older version of P2Pool</h3>
<p><a href="{%s p.Context().Pool.Versions.P2Pool.Link %}">P2Pool {%s p.Context().Pool.Versions.P2Pool.Version %}</a> has been released.</p>
<p>Your most recent share indicates are currently running {%= software_info(p.LastPoolBlock.Side.ExtraBuffer.SoftwareId, p.LastPoolBlock.Side.ExtraBuffer.SoftwareVersion) %}. It is recommended to upgrade.</p>
<p>After upgrading to this P2Pool version and mining a share, this message will be dismissed.</p>
<br/>
</div>
<hr/>
{% endif %}
<p><strong>Payout Address:</strong> <span class="mono small">{%z= p.Miner.Address.ToBase58() %}</span></p>
{% if p.Miner.Alias != "" %}
<p><strong>Miner Alias:</strong> <span class="mono">{%s p.Miner.Alias %}</span></p>
<p><small>Miner Alias is user content and not verified. This value should only be used for vanity purposes.</small></p>
{% endif %}
<p><small><a href="/miner-options/{%z= p.Miner.Address.ToBase58() %}#mineralias">[Change Miner Alias]</a> :: <a href="/miner-options/{%z= p.Miner.Address.ToBase58() %}#webhooks">[Configure WebHook notifications]</a></small></p>
<table class="center" style="max-width: calc(15em + 15em + 15em + 15em + 15em)">
<tr>
<th>Last Share</th>
<th>Current Shares</th>
<th>Estimated Hashrate</th>
<th>Pool Share %</th>
<th>Estimated Window Reward</th>
</tr>
<tr>
<td title="{%s utc_date(p.Miner.LastShareTimestamp) %}">{%s time_elapsed_short(p.Miner.LastShareTimestamp) %}</td>
<td>{%dul p.Positions.BlocksInWindow.Total() %} blocks (+{%dul p.Positions.UnclesInWindow.Total() %} uncles)</td>
{% code windowWeightRatio := float64(p.WindowWeight) / float64(p.Context().Pool.SideChain.Window.Weight.Lo) %}
<td>{%s si_units(windowWeightRatio * float64(diff_hashrate(p.Context().Pool.SideChain.LastBlock.Difficulty, p.Context().Consensus.TargetBlockTime)), 3) %}H/s</td>
<td>{%f.3 windowWeightRatio*100 %}%</td>
<td>{%s monero_to_xmr(p.ExpectedRewardPerWindow) %} XMR</td>
</tr>
<tr><td colspan="5">&nbsp;</td></tr>
<tr>
<th>Estimated Total Shares</th>
<th>Day Shares</th>
<th>Day Hashrate</th>
<th>Day Share %</th>
<th>Estimated Daily Reward</th>
</tr>
<tr>
<td>{% if p.LastPoolBlock != nil %}Around {%dul p.Miner.Shares[1].ShareCount %} blocks (+{%dul p.Miner.Shares[1].UncleCount %} uncles{% if p.Miner.Shares[0].ShareCount > 0 %}, +{%dul p.Miner.Shares[0].ShareCount %} orphans{% endif %}){% else %}No shares reported{% endif %}</td>
<td>{%dul p.Positions.Blocks.Total() %} blocks (+{%dul p.Positions.Uncles.Total() %} uncles)</td>
{% code weightRatio := (float64(p.Weight) / (float64(p.Context().Pool.SideChain.Window.Weight.Mul64(4).Lo) * (float64(p.Context().Pool.SideChain.Consensus.ChainWindowSize) / float64(p.Context().Pool.SideChain.Window.Blocks)))) %}
<td>{%s si_units(weightRatio * float64(diff_hashrate(p.Context().Pool.SideChain.LastBlock.Difficulty, p.Context().Consensus.TargetBlockTime)), 3) %}H/s</td>
<td>{%f.3 weightRatio*100 %}%</td>
<td>{%s monero_to_xmr(p.ExpectedRewardPerDay) %} XMR</td>
</tr>
</table>
</div>
<hr/>
<div style="text-align: center;">
<h2>Share positions</h2>
<p class="small">
Shares appear on the right, and get older towards the left.
<br/>
Number denotes the amount of shares per slice, with the plus (<code>+</code>) character being more than 9, and dot (<code>.</code>) being none.
<br/>
Each slice accounts for {%d p.Positions.Resolution %} P2Pool blocks, or around {%dul (uint64(p.Positions.Resolution) * p.Context().Consensus.TargetBlockTime) / 60 %} minutes.
</p>
<h3>Shares and uncles in PPLNS window</h3>
<p class="small">
Each slice accounts for {%d p.Positions.ResolutionWindow %} P2Pool block heights, or around {%dul (uint64(p.Positions.ResolutionWindow) * p.Context().Consensus.TargetBlockTime) / 60 %} minutes.
<br/>
Shares within the PPLNS window will be weighted towards receiving a payout when any Monero block is found by any P2Pool miner.
</p>
<code class="mono">{%s p.Positions.BlocksInWindow.String() %}</code>
<br/>
<code class="mono">{%s p.Positions.UnclesInWindow.String() %}</code>
<h3>Shares and uncles during last day</h3>
<p class="small">
Each slice accounts for {%d p.Positions.Resolution %} P2Pool block heights, or around {%dul (uint64(p.Positions.Resolution) * p.Context().Consensus.TargetBlockTime) / 60 %} minutes.
<br/>
The pipe (<code>|</code>) character denotes roughly the PPLNS window end.
</p>
<code class="mono">{%s p.Positions.Blocks.StringWithSeparator(p.Positions.SeparatorIndex) %}</code>
<br/>
<code class="mono">{%s p.Positions.Uncles.StringWithSeparator(p.Positions.SeparatorIndex) %}</code>
{% if p.Positions.Payouts.Total() > 0 %}
<h3>Payouts during last day</h3>
<code class="mono">{%s p.Positions.Payouts.StringWithSeparator(p.Positions.SeparatorIndex) %}</code>
{% endif %}
</div>
<br/>
<br/>
<hr/>
<div style="text-align: center">
<h2>Most recent payouts</h2>
{%= TemplatePayoutsSlice(p.Context(), p.LastPayouts) %}
<div class="center"><a href="/payouts/{%z= p.Miner.Address.ToBase58() %}">[show all historical payouts]</a></div>
</div>
<hr/>
<div style="text-align: center">
<h2>Most recent shares</h2>
{% if p.HashrateSubmit || (p.Positions.Blocks.Total() + p.Positions.Uncles.Total()) > 2 %}
{%= TemplateShares(p.Context(), p.LastShares, true, &p.LastSharesEfforts) %}
{% else %}
{%= TemplateShares(p.Context(), p.LastShares, true, nil) %}
{% endif %}
</div>
<hr/>
{% if len(p.LastOrphanedShares) > 0 %}
<div style="text-align: center">
<h2>Most recent orphaned shares</h2>
{%= TemplateShares(p.Context(), p.LastOrphanedShares, true, nil) %}
</div>
<hr/>
{% endif %}
<div style="text-align: center">
<h2>Most recent Monero blocks found</h2>
{%= TemplateFoundBlocks(p.Context(), p.LastFound, true) %}
<div class="center"><a href="/blocks?miner={%z= p.Miner.Address.ToBase58() %}">[show more found blocks]</a></div>
</div>
<hr/>
<div style="text-align: center">
<h2>Most recent likely sweeps</h2>
{%= TemplateSweeps(p.Context(), p.LastSweeps, true) %}
<div class="center"><a href="/sweeps?miner={%z= p.Miner.Address.ToBase58() %}">[show more likely sweeps]</a></div>
</div>
{% if p.Miner.LastShareTimestamp != 0 %}
<hr/>
<div style="text-align: center">
<form action="/calculate-share-time" method="get">
<h3>Effort Calculation</h3>
<p>Local hashrate of each P2Pool miner is not known by the network. A guess is calculated based on daily estimation. If you provide a value here, it will be more accurate for effort calculation.</p>
<p>This data will not be saved.</p>
<label for="hashrate_local">Your Local Hashrate</label><br/>
<input type="numeric" name="hashrate" id="hashrate_local" placeholder="100" size="8" class="mono" value="{% if p.HashrateLocal > 0 %}{%s str(p.HashrateLocal) %}{% endif %}"/>
<select name="magnitude">
<option value="1"{% if p.MagnitudeLocal == 1 %} selected{% endif %}>H/s</option>
<option value="1000"{% if p.MagnitudeLocal == 1000 %} selected{% endif %}>KH/s</option>
<option value="1000000"{% if p.MagnitudeLocal == 1000000 %} selected{% endif %}>MH/s</option>
<option value="1000000000"{% if p.MagnitudeLocal == 1000000000 %} selected{% endif %}>GH/s</option>
</select>
<br/>
<input type="submit" value="Calculate" style="width: 20em; margin: 20px;"/>
</form>
</div>
{% endif %}
{% endfunc %}