Web/api streaming optimizations
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2023-07-23 19:07:32 +02:00
parent b7b1344eea
commit 0b8823cdf3
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
19 changed files with 175 additions and 199 deletions

View file

@ -70,7 +70,7 @@ func getSliceFromAPI[T any](method string, cacheTime ...int) []T {
})
}
func getStreamFromAPI[T any](method string, cacheTime ...int) chan T {
func getStreamFromAPI[T any](method string) <-chan T {
result := make(chan T, 1)
go func() {
@ -86,10 +86,26 @@ func getStreamFromAPI[T any](method string, cacheTime ...int) chan T {
defer io.ReadAll(response.Body)
if response.StatusCode == http.StatusOK {
var err error
// Read opening
var b [1]byte
for {
if _, err = response.Body.Read(b[:]); err != nil {
return
}
if b[0] == '[' {
break
} else if b[0] != ' ' && b[0] != 0xa {
return
}
}
decoder := utils.NewJSONDecoder(response.Body)
for decoder.More() {
var item T
if decoder.Decode(&item) != nil {
if err := decoder.Decode(&item); err != nil {
return
} else {
result <- item
@ -102,7 +118,7 @@ func getStreamFromAPI[T any](method string, cacheTime ...int) chan T {
return result
}
func getSideBlocksStreamFromAPI(method string) chan *index.SideBlock {
func getSideBlocksStreamFromAPI(method string) <-chan *index.SideBlock {
return getStreamFromAPI[*index.SideBlock](method)
}

View file

@ -90,16 +90,16 @@ type ConnectivityCheckPage struct {
{% if p.Check.Tip != nil %}
<tr><th colspan="6">&nbsp;</th></tr>
<tr style="line-height: 1.5;">
<td style="width: 10em"><strong>Peer SideChain Height</strong><br/><a href="/share/{%= hex(p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}">{%dul p.YourTipRaw.Side.Height %}</a></td>
<td style="width: 10em"><strong>Peer SideChain Id</strong><br/><a href="/share/{%= hex(p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}" title="{%= hex(p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}">{%= shorten(p.YourTipRaw.SideTemplateId(p.Context().Consensus), 10) %}</a></td>
<td style="width: 10em"><strong>Peer SideChain Height</strong><br/><a href="/share/{%= hex(p.Context(), p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}">{%dul p.YourTipRaw.Side.Height %}</a></td>
<td style="width: 10em"><strong>Peer SideChain Id</strong><br/><a href="/share/{%= hex(p.Context(), p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}" title="{%= hex(p.Context(), p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}">{%= shorten(p.Context(), p.YourTipRaw.SideTemplateId(p.Context().Consensus), 10) %}</a></td>
<td style="width: 10em"><strong>Peer MainChain Height</strong><br/>{%dul p.YourTipRaw.Main.Coinbase.GenHeight %}</td>
<td style="width: 10em"><strong>Peer Difficulty</strong><br/>{%s si_units(p.YourTipRaw.Side.Difficulty.Lo, 4) %}</td>
<td style="width: 10em"><strong>Peer Cumulative Difficulty</strong><br/>{%s si_units(p.YourTipRaw.Side.CumulativeDifficulty.Lo, 4) %}</td>
<td style="width: 10em"><strong>Peer Timestamp</strong><br/>{%s utc_date(p.YourTipRaw.Main.Timestamp) %}</td>
</tr>
<tr style="line-height: 1.5;">
<td style="width: 10em"><strong>Observer SideChain Height</strong><br/><a href="/share/{%= hex(p.OurTip.TemplateId) %}">{%dul p.OurTip.SideHeight %}</a></td>
<td style="width: 10em"><strong>Observer SideChain Id</strong><br/><a href="/share/{%= hex(p.OurTip.TemplateId) %}" title="{%= hex(p.OurTip.TemplateId) %}">{%= shorten(p.OurTip.TemplateId, 10) %}</a></td>
<td style="width: 10em"><strong>Observer SideChain Height</strong><br/><a href="/share/{%= hex(p.Context(), p.OurTip.TemplateId) %}">{%dul p.OurTip.SideHeight %}</a></td>
<td style="width: 10em"><strong>Observer SideChain Id</strong><br/><a href="/share/{%= hex(p.Context(), p.OurTip.TemplateId) %}" title="{%= hex(p.Context(), p.OurTip.TemplateId) %}">{%= shorten(p.Context(), p.OurTip.TemplateId, 10) %}</a></td>
<td style="width: 10em"><strong>Observer MainChain Height</strong><br/>{%dul p.OurTip.MainHeight %}</td>
<td style="width: 10em"><strong>Observer Difficulty</strong><br/>{%s si_units(p.OurTip.Difficulty, 4) %}</td>
<td style="width: 10em"><strong>Observer Cumulative Difficulty</strong><br/>{%s si_units(p.OurTip.CumulativeDifficulty.Lo, 4) %}</td>

View file

@ -3,6 +3,7 @@ package views
import (
cmdutils "git.gammaspectra.live/P2Pool/p2pool-observer/cmd/utils"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
)
type GlobalRequestContext struct {
@ -23,6 +24,7 @@ type GlobalRequestContext struct {
Link string
}
}
HexBuffer [types.HashSize * 2]byte
}
func (ctx *GlobalRequestContext) GetUrl(host string) string {

View file

@ -7,162 +7,99 @@
{% import "encoding/binary" %}
{% import "fmt" %}
{% import "sync" %}
{% import "slices" %}
{% import hex2 "encoding/hex" %}
{% stripspace %}
{% code
var hexBufPool sync.Pool
func init() {
hexBufPool.New = func() any {
return make([]byte, types.HashSize*2)
}
}
%}
{% func hex(val any) %}
{% func hex(ctx *GlobalRequestContext, val any) %}
{% switch s := val.(type) %}
{% case string %}
{%s s %}
{% case types.Difficulty %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:types.DifficultySize*2], s.Bytes())
hex2.Encode(ctx.HexBuffer[:types.DifficultySize*2], s.Bytes())
%}
{%z= hexBuf[:types.DifficultySize*2] %}
{%z= ctx.HexBuffer[:types.DifficultySize*2] %}
{% case crypto.PrivateKeyBytes %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s[:])
hex2.Encode(ctx.HexBuffer[:], s[:])
%}
{%z= hexBuf[:] %}
{%z= ctx.HexBuffer[:] %}
{% case crypto.PublicKeyBytes %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s[:])
hex2.Encode(ctx.HexBuffer[:], s[:])
%}
{%z= hexBuf[:] %}
{%z= ctx.HexBuffer[:] %}
{% case crypto.PrivateKey %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
hex2.Encode(ctx.HexBuffer[:], s.AsSlice())
%}
{%z= hexBuf[:] %}
{%z= ctx.HexBuffer[:] %}
{% case crypto.PublicKey %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
hex2.Encode(ctx.HexBuffer[:], s.AsSlice())
%}
{%z= hexBuf[:] %}
{%z= ctx.HexBuffer[:] %}
{% case types.Hash %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s[:])
hex2.Encode(ctx.HexBuffer[:], s[:])
%}
{%z= hexBuf[:] %}
{%z= ctx.HexBuffer[:] %}
{% case []byte %}
{%s= hex2.EncodeToString(s) %}
{% case uint32 %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], s)
hex2.Encode(hexBuf[:4*2], buf[:])
hex2.Encode(ctx.HexBuffer[:4*2], buf[:])
%}
{%z= hexBuf[:4*2] %}
{%z= ctx.HexBuffer[:4*2] %}
{% case uint64 %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], s)
hex2.Encode(hexBuf[:8*2], buf[:])
hex2.Encode(ctx.HexBuffer[:8*2], buf[:])
%}
{%z= hexBuf[:8*2] %}
{%z= ctx.HexBuffer[:8*2] %}
{% default %}
{%v val %}
{% endswitch %}
{% endfunc %}
{% func shorten(val any, n int) %}
{% func shorten(ctx *GlobalRequestContext, val any, n int) %}
{% switch s := val.(type) %}
{% case string %}
{%s utils.Shorten(s, n) %}
{% case []byte %}
{%z= utils.ShortenSlice(slices.Clone(s), n) %}
{% case crypto.PrivateKeyBytes %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s[:])
hex2.Encode(ctx.HexBuffer[:], s[:])
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{%z= utils.ShortenSlice(ctx.HexBuffer[:], n) %}
{% case crypto.PublicKeyBytes %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s[:])
hex2.Encode(ctx.HexBuffer[:], s[:])
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{%z= utils.ShortenSlice(ctx.HexBuffer[:], n) %}
{% case crypto.PrivateKey %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
hex2.Encode(ctx.HexBuffer[:], s.AsSlice())
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{%z= utils.ShortenSlice(ctx.HexBuffer[:], n) %}
{% case crypto.PublicKey %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
hex2.Encode(ctx.HexBuffer[:], s.AsSlice())
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{%z= utils.ShortenSlice(ctx.HexBuffer[:], n) %}
{% case types.Hash %}
{% code
hexBuf := hexBufPool.Get().([]byte)
defer hexBufPool.Put(hexBuf)
%}
{% code
hex2.Encode(hexBuf[:], s[:])
hex2.Encode(ctx.HexBuffer[:], s[:])
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{%z= utils.ShortenSlice(ctx.HexBuffer[:], n) %}
{% case fmt.Stringer %}
{%s utils.Shorten(s.String(), n) %}
{% default %}

View file

@ -35,9 +35,9 @@ type IndexPage struct {
<th style="width: 15em">Monero Hashrate</th>
</tr>
<tr>
<td title="{%= hex(p.Context().Pool.SideChain.Id) %}"><a href="/share/{%= hex(p.Context().Pool.SideChain.Id) %}">{%dul p.Context().Pool.SideChain.Height %}</a></td>
<td title="{%= hex(p.Context(), p.Context().Pool.SideChain.Id) %}"><a href="/share/{%= hex(p.Context(), p.Context().Pool.SideChain.Id) %}">{%dul p.Context().Pool.SideChain.Height %}</a></td>
<td>{%s si_units(diff_hashrate(p.Context().Pool.SideChain.Difficulty, p.Context().Consensus.TargetBlockTime), 2) %}H/s</td>
<td title="{%= hex(p.Context().Pool.MainChain.Id) %}"><a href="/b/{%s benc(p.Context().Pool.MainChain.Height) %}">{%dul p.Context().Pool.MainChain.Height %}</a></td>
<td title="{%= hex(p.Context(), p.Context().Pool.MainChain.Id) %}"><a href="/b/{%s benc(p.Context().Pool.MainChain.Height) %}">{%dul p.Context().Pool.MainChain.Height %}</a></td>
<td>{%s si_units(diff_hashrate(p.Context().Pool.MainChain.Difficulty, uint64(p.Context().Pool.MainChain.BlockTime)), 2) %}H/s</td>
</tr>
<tr><th colspan="4">&nbsp;</th></tr>

View file

@ -30,8 +30,9 @@ type MinerPage struct {
LastOrphanedShares []*index.SideBlock
LastFound []*index.FoundBlock
LastPayouts []*index.Payout
LastSweeps []*index.MainLikelySweepTransaction
LastSweeps <-chan *index.MainLikelySweepTransaction
HashrateSubmit bool
HashrateLocal float64
MagnitudeLocal float64
}
@ -208,7 +209,7 @@ type MinerPage struct {
<div style="text-align: center">
<h2>Most recent payouts</h2>
{%= TemplatePayouts(p.Context(), p.LastPayouts) %}
{%= TemplatePayoutsSlice(p.Context(), p.LastPayouts) %}
<div class="center"><a href="/payouts/{%z= p.Miner.Address.ToBase58() %}">[show all historical payouts]</a></div>
</div>
@ -216,7 +217,11 @@ type MinerPage struct {
<div style="text-align: center">
<h2>Most recent shares</h2>
{%= TemplateShares(p.Context(), p.LastShares, true, &p.LastSharesEfforts) %}
{% 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/>

View file

@ -81,7 +81,7 @@ type MinersPageMinerEntry struct {
{% for i, m := range p.Miners %}
<tr style="padding-bottom: 10px; border-bottom: solid #aaa 1px">
<td style="vertical-align: middle">{%d i+1 %}</td>
{%= TemplateRowMinerWithTag(m.Address, m.Alias, "th") %}
{%= TemplateRowMinerWithTag(p.Context(), m.Address, m.Alias, "th") %}
<td style="vertical-align: middle">{%= software_info(m.SoftwareId, m.SoftwareVersion) %}</td>
{% code minerRatio := float64(m.Weight.Lo) / float64(p.WindowWeight.Lo) %}
<td style="vertical-align: middle">{%f.3 minerRatio*100 %}%</td>

View file

@ -6,9 +6,8 @@ type PayoutsPage struct {
// inherit from base page, so its' title is used in error page.
BasePage
Refresh int
Total uint64
Miner *address.Address
Payouts []*index.Payout
Payouts <-chan *index.Payout
}
%}
@ -30,9 +29,12 @@ type PayoutsPage struct {
<div style="text-align: center">
<h2>Historical miner payouts</h2>
<p><strong>Payout Address:</strong> <a href="/miner/{%z= p.Miner.ToBase58() %}"><span class="mono small">{%z= p.Miner.ToBase58() %}</span></a></p>
<p><strong>Estimated total:</strong> {%s monero_to_xmr(p.Total) %} XMR</p>
{%= TemplatePayouts(p.Context(), p.Payouts) %}
{% code var total uint64 %}
{%= TemplatePayouts(p.Context(), p.Payouts, &total) %}
<p><strong>Estimated total:</strong> {%s monero_to_xmr(total) %} XMR</p>
</div>
{% endfunc %}

View file

@ -26,26 +26,26 @@ type ProofPage struct {
<p><strong>Payout Address:</strong> <span class="mono small"><a href="/miner/{%z= encodedMinerAddress %}">{%z= encodedMinerAddress %}</a></span></p>
{% endif %}
<p>Received <strong>{%s monero_to_xmr(p.Output.Value) %} XMR</strong> on transaction id <a class="mono small" href="/t/{%= henc(p.Output.Id) %}">{%= hex(p.Output.Id) %}</a> (output index #{%dul uint64(p.Output.Index) %}, global output index #{%dul p.Output.GlobalOutputIndex %}).</p>
<p>Received <strong>{%s monero_to_xmr(p.Output.Value) %} XMR</strong> on transaction id <a class="mono small" href="/t/{%= henc(p.Output.Id) %}">{%= hex(p.Context(), p.Output.Id) %}</a> (output index #{%dul uint64(p.Output.Index) %}, global output index #{%dul p.Output.GlobalOutputIndex %}).</p>
<p><strong>{%dul p.Context().Pool.MainChain.Height - p.Block.MainHeight + 1 %} confirmation(s)</strong>. Coinbase outputs will unlock after 60 confirmations.</p>
<p><strong>Stealth Address:</strong> <span class="mono small">{%s address.GetEphemeralPublicKey(p.Output.MinerAddress, &p.Raw.Side.CoinbasePrivateKey, uint64(p.Output.Index)).String() %}</span></p>
<hr/>
<h3>Payment Proofs</h3>
<div style="border: #aaaaaa 1px dashed; margin-bottom: 20px">
<p><strong>Transaction Private Key:</strong> <span class="mono small">{%= hex(p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<p>Verify on Monero CLI: <span class="mono smaller">check_tx_proof {%= hex(p.Output.Id) %} {%z= encodedMinerAddress %} {%= hex(p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<p><strong>Transaction Private Key:</strong> <span class="mono small">{%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<p>Verify on Monero CLI: <span class="mono smaller">check_tx_proof {%= hex(p.Context(), p.Output.Id) %} {%z= encodedMinerAddress %} {%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<p>
<a href="{%s p.Context().GetUrl("localmonero.co") %}/blocks/tx/{%= hex(p.Output.Id) %}?xmraddress={%z= encodedMinerAddress %}&txprvkey={%= hex(p.Raw.Side.CoinbasePrivateKey) %}">Verify on LocalMonero</a><br/>
<a href="{%s p.Context().GetUrl("www.exploremonero.com") %}/receipt/{%= hex(p.Output.Id) %}/{%z= encodedMinerAddress %}/{%= hex(p.Raw.Side.CoinbasePrivateKey) %}">Verify on Explore Monero</a><br/>
<a href="{%s p.Context().GetUrl("monero.com") %}/payment/{%= hex(p.Output.Id) %}/{%z= encodedMinerAddress %}/{%= hex(p.Raw.Side.CoinbasePrivateKey) %}/">Verify on Monero.com</a><br/>
<a href="{%s p.Context().GetUrl("localmonero.co") %}/blocks/tx/{%= hex(p.Context(), p.Output.Id) %}?xmraddress={%z= encodedMinerAddress %}&txprvkey={%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}">Verify on LocalMonero</a><br/>
<a href="{%s p.Context().GetUrl("www.exploremonero.com") %}/receipt/{%= hex(p.Context(), p.Output.Id) %}/{%z= encodedMinerAddress %}/{%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}">Verify on Explore Monero</a><br/>
<a href="{%s p.Context().GetUrl("monero.com") %}/payment/{%= hex(p.Context(), p.Output.Id) %}/{%z= encodedMinerAddress %}/{%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}/">Verify on Monero.com</a><br/>
</p>
</div>
<div style="border: #aaaaaa 1px dashed">
<p><strong>OutProofV2:</strong> <span class="mono smaller">{%= hex(address.GetTxProofV2(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}</span></p>
<p><strong>OutProofV1:</strong> <span class="mono smaller">{%= hex(address.GetTxProofV1(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}</span></p>
<p><strong>OutProofV2:</strong> <span class="mono smaller">{%= hex(p.Context(), address.GetTxProofV2(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}</span></p>
<p><strong>OutProofV1:</strong> <span class="mono smaller">{%= hex(p.Context(), address.GetTxProofV1(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}</span></p>
<p>Verify on Monero GUI <span class="small">(Advanced -> Prove/check -> Check Transaction)</span></p>
</div>
</div>

View file

@ -8,7 +8,7 @@ type SharePage struct {
Block *index.SideBlock
PoolBlock *sidechain.PoolBlock
Payouts []*index.Payout
Payouts <-chan *index.Payout
CoinbaseOutputs index.MainCoinbaseOutputs
SweepsCount int
Sweeps [][]*index.MainLikelySweepTransaction

View file

@ -6,7 +6,7 @@ type SweepsPage struct {
// inherit from base page, so its' title is used in error page.
BasePage
Refresh int
Sweeps []*index.MainLikelySweepTransaction
Sweeps <-chan *index.MainLikelySweepTransaction
Miner *address.Address
}
%}

View file

@ -21,14 +21,14 @@
</tr>
{% for i, b := range foundBlocks %}
<tr>
<th title="{%= hex(b.MainBlock.Id) %}"><a href="/b/{%s benc(b.MainBlock.Height) %}">{%dul b.MainBlock.Height %}</a></th>
<th title="{%= hex(ctx, b.MainBlock.Id) %}"><a href="/b/{%s benc(b.MainBlock.Height) %}">{%dul b.MainBlock.Height %}</a></th>
{% if b.UncleOf != types.ZeroHash %}
<th title="{%= hex(b.MainBlock.SideTemplateId) %} is an uncle of height {%dul b.EffectiveHeight %}, {%= hex(b.UncleOf) %}">
<a href="/share/{%= hex(b.MainBlock.SideTemplateId) %}">{%dul b.SideHeight %}*</a>
<th title="{%= hex(ctx, b.MainBlock.SideTemplateId) %} is an uncle of height {%dul b.EffectiveHeight %}, {%= hex(ctx, b.UncleOf) %}">
<a href="/share/{%= hex(ctx, b.MainBlock.SideTemplateId) %}">{%dul b.SideHeight %}*</a>
</th>
{% else %}
<th title="{%= hex(b.MainBlock.SideTemplateId) %}">
<a href="/share/{%= hex(b.MainBlock.SideTemplateId) %}">{%dul b.SideHeight %}</a>
<th title="{%= hex(ctx, b.MainBlock.SideTemplateId) %}">
<a href="/share/{%= hex(ctx, b.MainBlock.SideTemplateId) %}">{%dul b.SideHeight %}</a>
</th>
{% endif %}
<td title="{%s utc_date(b.MainBlock.Timestamp) %}">{%s date_diff_short(b.MainBlock.Timestamp) %}</td>
@ -44,13 +44,13 @@
{% else %}
<td>unknown</td>
{% endif %}
{%= TemplateRowMiner(b.MinerAddress, b.MinerAlias) %}
{%= TemplateRowMiner(ctx, b.MinerAddress, b.MinerAlias) %}
{% endif %}
<td>{%dul uint64(b.TransactionCount) %}</td>
<th class="small">{%s monero_to_xmr(b.MainBlock.Reward) %} XMR</th>
<td>{%dul uint64(b.WindowOutputs) %}</td>
<td title="{%= hex(b.MainBlock.CoinbaseId) %}" class="mono small"><a href="/t/{%= henc(b.MainBlock.CoinbaseId) %}">{%= shorten(b.MainBlock.CoinbaseId, 10) %}</a></td>
<td class="mono smaller">{%= hex(b.MainBlock.CoinbasePrivateKey) %}</td>
<td title="{%= hex(ctx, b.MainBlock.CoinbaseId) %}" class="mono small"><a href="/t/{%= henc(b.MainBlock.CoinbaseId) %}">{%= shorten(ctx, b.MainBlock.CoinbaseId, 10) %}</a></td>
<td class="mono smaller">{%= hex(ctx, b.MainBlock.CoinbasePrivateKey) %}</td>
</tr>
{% endfor %}
</table>

View file

@ -1,6 +1,32 @@
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/cmd/index" %}
{% func TemplatePayouts(ctx *GlobalRequestContext, payouts []*index.Payout) %}
{% func TemplatePayouts(ctx *GlobalRequestContext, payouts <-chan *index.Payout, total *uint64) %}
<table class="center datatable" style="max-width: calc(8em + 8em + 8em + 10em + 10em + 7em + 12em + 10em)">
<tr>
<th style="width: 8em;">Monero Height</th>
<th style="width: 8em;">P2Pool Height</th>
<th style="width: 8em;">Age <small>[h:m:s]</small></th>
<th style="width: 10em;">Reward</th>
<th style="width: 10em;">Global Output Index</th>
<th style="width: 12em;">Coinbase Transaction</th>
<th style="width: 10em;">Payout Proof</th>
</tr>
{% for p := range payouts %}
{% code *total = *total + p.Reward %}
<tr>
<th title="{%= hex(ctx, p.MainId) %}"><a href="/b/{%s benc(p.MainHeight) %}">{%dul p.MainHeight %}</a></th>
<th title="{%= hex(ctx, p.TemplateId) %}"><a href="/share/{%= hex(ctx, p.TemplateId) %}">{%dul p.SideHeight %}</a></th>
<td title="{%s utc_date(p.Timestamp) %}">{%s date_diff_short(p.Timestamp) %}</td>
<td>{%s monero_to_xmr(p.Reward) %} XMR</td>
<td>{%dul p.GlobalOutputIndex %}</td>
<td title="{%= hex(ctx, p.CoinbaseId) %}" class="mono small"><a href="/t/{%= henc(p.CoinbaseId) %}">{%= shorten(ctx, p.CoinbaseId, 10) %}</a></td>
<td><a href="/proof/{%= hex(ctx, p.MainId) %}/{%dul uint64(p.Index) %}" title="Prove you have a matching output for your address on this transaction">[Payout Proof #{%dul uint64(p.Index) %}]</a></td>
</tr>
{% endfor %}
</table>
{% endfunc %}
{% func TemplatePayoutsSlice(ctx *GlobalRequestContext, payouts []*index.Payout) %}
<table class="center datatable" style="max-width: calc(8em + 8em + 8em + 10em + 10em + 7em + 12em + 10em)">
<tr>
<th style="width: 8em;">Monero Height</th>
@ -13,13 +39,13 @@
</tr>
{% for _, p := range payouts %}
<tr>
<th title="{%= hex(p.MainId) %}"><a href="/b/{%s benc(p.MainHeight) %}">{%dul p.MainHeight %}</a></th>
<th title="{%= hex(p.TemplateId) %}"><a href="/share/{%= hex(p.TemplateId) %}">{%dul p.SideHeight %}</a></th>
<th title="{%= hex(ctx, p.MainId) %}"><a href="/b/{%s benc(p.MainHeight) %}">{%dul p.MainHeight %}</a></th>
<th title="{%= hex(ctx, p.TemplateId) %}"><a href="/share/{%= hex(ctx, p.TemplateId) %}">{%dul p.SideHeight %}</a></th>
<td title="{%s utc_date(p.Timestamp) %}">{%s date_diff_short(p.Timestamp) %}</td>
<td>{%s monero_to_xmr(p.Reward) %} XMR</td>
<td>{%dul p.GlobalOutputIndex %}</td>
<td title="{%= hex(p.CoinbaseId) %}" class="mono small"><a href="/t/{%= henc(p.CoinbaseId) %}">{%= shorten(p.CoinbaseId, 10) %}</a></td>
<td><a href="/proof/{%= hex(p.MainId) %}/{%dul uint64(p.Index) %}" title="Prove you have a matching output for your address on this transaction">[Payout Proof #{%dul uint64(p.Index) %}]</a></td>
<td title="{%= hex(ctx, p.CoinbaseId) %}" class="mono small"><a href="/t/{%= henc(p.CoinbaseId) %}">{%= shorten(ctx, p.CoinbaseId, 10) %}</a></td>
<td><a href="/proof/{%= hex(ctx, p.MainId) %}/{%dul uint64(p.Index) %}" title="Prove you have a matching output for your address on this transaction">[Payout Proof #{%dul uint64(p.Index) %}]</a></td>
</tr>
{% endfor %}
</table>

View file

@ -6,7 +6,7 @@
{%= TemplatePoolBlockWithSideBlock(ctx, poolBlock, header, false, nil, nil, nil, 0, nil) %}
{% endfunc %}
{% func TemplatePoolBlockWithSideBlock(ctx *GlobalRequestContext, poolBlock *sidechain.PoolBlock, header string, navigation bool, sideBlock *index.SideBlock, payouts []*index.Payout, coinbaseOutputs index.MainCoinbaseOutputs, sweepsCount int, sweeps [][]*index.MainLikelySweepTransaction) %}
{% func TemplatePoolBlockWithSideBlock(ctx *GlobalRequestContext, poolBlock *sidechain.PoolBlock, header string, navigation bool, sideBlock *index.SideBlock, payouts <-chan *index.Payout, coinbaseOutputs index.MainCoinbaseOutputs, sweepsCount int, sweeps [][]*index.MainLikelySweepTransaction) %}
<div class="center" style="text-align: center">
{% if sideBlock != nil %}
{% if sideBlock.MinedMainAtHeight %}
@ -26,9 +26,9 @@
{% if sideBlock.SideHeight == 0 %}
<td colspan="2">Genesis Block</td>
{% elseif sideBlock.IsUncle() %}
<td colspan="2"><a href="/share/{%= hex(sideBlock.UncleOf) %}">&lt;&lt; Parent share</a></td>
<td colspan="2"><a href="/share/{%= hex(ctx, sideBlock.UncleOf) %}">&lt;&lt; Parent share</a></td>
{% else %}
<td colspan="2"><a href="/share/{%= hex(sideBlock.ParentTemplateId) %}">&lt;&lt; Previous share</a></td>
<td colspan="2"><a href="/share/{%= hex(ctx, sideBlock.ParentTemplateId) %}">&lt;&lt; Previous share</a></td>
{% endif %}
{% if sideBlock.IsOrphan() %}
<td colspan="2">Orphans do not have next blocks</td>
@ -49,22 +49,22 @@
<tr>
<td>{%dul poolBlock.Side.Height %}</td>
{% if sideBlock != nil %}
<td class="mono smaller">{%= hex(sideBlock.TemplateId) %}</td>
<td class="mono smaller">{%= hex(ctx, sideBlock.TemplateId) %}</td>
{% else %}
<td class="mono smaller">{%= hex(poolBlock.SideTemplateId(ctx.Consensus)) %}</td>
<td class="mono smaller">{%= hex(ctx, poolBlock.SideTemplateId(ctx.Consensus)) %}</td>
{% endif %}
{% if sideBlock != nil %}
{% if sideBlock.MinedMainAtHeight %}
<td><a href="/b/{%s benc(sideBlock.MainHeight) %}">{%dul sideBlock.MainHeight %}</a></td>
<td class="mono smaller"><a href="/b/{%s benc(sideBlock.MainHeight) %}">{%= hex(sideBlock.MainId) %}</a></td>
<td class="mono smaller"><a href="/b/{%s benc(sideBlock.MainHeight) %}">{%= hex(ctx, sideBlock.MainId) %}</a></td>
{% else %}
<td>{%dul sideBlock.MainHeight %}</td>
<td class="mono smaller">{%= hex(sideBlock.MainId) %}</td>
<td class="mono smaller">{%= hex(ctx, sideBlock.MainId) %}</td>
{% endif %}
{% else %}
<td>{%dul poolBlock.Main.Coinbase.GenHeight %}</td>
<td class="mono smaller">{%= hex(poolBlock.MainId()) %}</td>
<td class="mono smaller">{%= hex(ctx, poolBlock.MainId()) %}</td>
{% endif %}
</tr>
<tr><td colspan="4">&nbsp;</td></tr>
@ -77,12 +77,12 @@
<tr>
<td title="{%s utc_date(poolBlock.Main.Timestamp) %}">{%s date_diff_short(poolBlock.Main.Timestamp) %}</td>
{% if sideBlock != nil %}
<td class="mono smaller">{%= hex(sideBlock.PowHash) %}</td>
{%= TemplateRowMiner(sideBlock.MinerAddress, sideBlock.MinerAlias) %}
<td class="mono smaller">{%= hex(ctx, sideBlock.PowHash) %}</td>
{%= TemplateRowMiner(ctx, sideBlock.MinerAddress, sideBlock.MinerAlias) %}
<td><span class="mono">{%dul sideBlock.Difficulty %}</span> / <span class="mono" title="Proof of Work Difficulty">{%dul sideBlock.PowDifficulty %}</span></td>
{% else %}
<td class="mono smaller">-</td>
{%= TemplateRowMiner(poolBlock.GetAddress().Reference().ToAddress(ctx.Consensus.NetworkType.AddressNetwork()), "") %}
{%= TemplateRowMiner(ctx, poolBlock.GetAddress().Reference().ToAddress(ctx.Consensus.NetworkType.AddressNetwork()), "") %}
<td><span class="mono">{%dul poolBlock.Side.Difficulty.Lo %}</span></td>
{% endif %}
</tr>
@ -100,12 +100,12 @@
<td>{%= side_block_valuation(poolBlock, ctx.Consensus) %}</td>
{% endif %}
{% if sideBlock != nil && sideBlock.MinedMainAtHeight %}
<td class="mono smaller"><a href="/t/{%= henc(poolBlock.Main.Coinbase.Id()) %}">{%= hex(poolBlock.Main.Coinbase.Id()) %}</a></td>
<td class="mono smaller"><a href="/t/{%= henc(poolBlock.Main.Coinbase.Id()) %}">{%= hex(ctx, poolBlock.Main.Coinbase.Id()) %}</a></td>
{% else %}
<td class="mono smaller">{%= hex(poolBlock.Main.Coinbase.Id()) %}</td>
<td class="mono smaller">{%= hex(ctx, poolBlock.Main.Coinbase.Id()) %}</td>
{% endif %}
<td class="small">{%s monero_to_xmr(poolBlock.Main.Coinbase.TotalReward) %} XMR</td>
<td class="mono smaller">{%= hex(poolBlock.Side.CoinbasePrivateKey) %}</td>
<td class="mono smaller">{%= hex(ctx, poolBlock.Side.CoinbasePrivateKey) %}</td>
</tr>
<tr><td colspan="4">&nbsp;</td></tr>
<tr>
@ -115,9 +115,9 @@
<th>Monero Target Difficulty</th>
</tr>
<tr>
<td class="mono" title="{%= hex(poolBlock.Main.Nonce) %}">{%dul uint64(poolBlock.Main.Nonce) %}</td>
<td class="mono smaller">{%= hex(poolBlock.Side.CumulativeDifficulty) %}</td>
<td class="mono" title="{%= hex(poolBlock.ExtraNonce()) %}">{%dul uint64(poolBlock.ExtraNonce()) %}</td>
<td class="mono" title="{%= hex(ctx, poolBlock.Main.Nonce) %}">{%dul uint64(poolBlock.Main.Nonce) %}</td>
<td class="mono smaller">{%= hex(ctx, poolBlock.Side.CumulativeDifficulty) %}</td>
<td class="mono" title="{%= hex(ctx, poolBlock.ExtraNonce()) %}">{%dul uint64(poolBlock.ExtraNonce()) %}</td>
<td class="mono">{% if sideBlock != nil && sideBlock.MainDifficulty != 0 %}{%dul sideBlock.MainDifficulty %}{% endif %}</td>
</tr>
<tr><td colspan="4">&nbsp;</td></tr>
@ -130,8 +130,8 @@
<tr>
<td>{%= software_info(poolBlock.Side.ExtraBuffer.SoftwareId, poolBlock.Side.ExtraBuffer.SoftwareVersion) %}</td>
<td>{%s= poolBlock.ShareVersion().String() %} <span class="small">({% if poolBlock.ShareVersionSignaling() != sidechain.ShareVersion_None %}signaling {%s= poolBlock.ShareVersionSignaling().String() %} support{% else %}no known signaling{% endif %})</span></td>
<td class="small">{% if poolBlock.ShareVersion() > sidechain.ShareVersion_V1 %}<span class="mono" title="Random Number">{%= hex(poolBlock.Side.ExtraBuffer.RandomNumber) %}</span> / <span class="mono" title="SideChain Extra Nonce">{%= hex(poolBlock.Side.ExtraBuffer.SideChainExtraNonce) %}{% endif %}</span></td>
<td>{% if poolBlock.GetPrivateKeySeed() != types.ZeroHash %}<span class="mono smaller">{%= hex(poolBlock.GetPrivateKeySeed()) %}</span>{% else %}Not Deterministic{% endif %}</td>
<td class="small">{% if poolBlock.ShareVersion() > sidechain.ShareVersion_V1 %}<span class="mono" title="Random Number">{%= hex(ctx, poolBlock.Side.ExtraBuffer.RandomNumber) %}</span> / <span class="mono" title="SideChain Extra Nonce">{%= hex(ctx, poolBlock.Side.ExtraBuffer.SideChainExtraNonce) %}{% endif %}</span></td>
<td>{% if poolBlock.GetPrivateKeySeed() != types.ZeroHash %}<span class="mono smaller">{%= hex(ctx, poolBlock.GetPrivateKeySeed()) %}</span>{% else %}Not Deterministic{% endif %}</td>
</tr>
</table>
@ -144,15 +144,16 @@
{% endif %}
<ul class="mono">
{% for _, u := range poolBlock.Side.Uncles %}
<li><a href="/share/{%= hex(u) %}">{%= hex(u) %}</a></li>
<li><a href="/share/{%= hex(ctx, u) %}">{%= hex(ctx, u) %}</a></li>
{% endfor %}
</ul>
{% endif %}
{% if sideBlock != nil && payouts != nil %}
<h2>Payouts share was weighted into</h2>
{% code var total uint64 %}
{%= TemplatePayouts(ctx, payouts) %}
{%= TemplatePayouts(ctx, payouts, &total) %}
{% if sideBlock.EffectiveHeight > (ctx.Pool.SideChain.Height - uint64(ctx.Pool.SideChain.WindowSize)) %}
<div class="center"><h3>Share is inside the PPLNS window. Any Monero blocks found during this period by any P2Pool miner will provide a direct payout.</h3></div>
{% else %}
@ -200,21 +201,21 @@
{% for _, t := range poolBlock.Main.Coinbase.Outputs %}
<tr>
<td>{%dul t.Index %}</td>
<td class="mono smaller">{%= hex(t.EphemeralPublicKey) %}</td>
<td class="mono smaller">{%= hex(ctx, t.EphemeralPublicKey) %}</td>
{% code var globalOutputIndex uint64 %}
{% if len(coinbaseOutputs) > int(t.Index) %}
{% code globalOutputIndex = coinbaseOutputs[t.Index].GlobalOutputIndex %}
{%= TemplateRowMiner(coinbaseOutputs[t.Index].MinerAddress, coinbaseOutputs[t.Index].MinerAlias) %}
{%= TemplateRowMiner(ctx, coinbaseOutputs[t.Index].MinerAddress, coinbaseOutputs[t.Index].MinerAlias) %}
{% endif %}
<td class="small" title="{%f.3 (float64(t.Reward) / float64(poolBlock.Main.Coinbase.TotalReward)) * 100 %}%">{%s monero_to_xmr(t.Reward) %} XMR</td>
{% if sideBlock != nil && sideBlock.MinedMainAtHeight %}
<td class="small">{%dul globalOutputIndex %}</td>
<td class="small"><a href="/proof/{%= hex(sideBlock.MainId) %}/{%dul t.Index %}" title="Prove you have a matching output for this address on this transaction">[Payout Proof #{%dul t.Index %}]</a></td>
<td class="small"><a href="/proof/{%= hex(ctx, sideBlock.MainId) %}/{%dul t.Index %}" title="Prove you have a matching output for this address on this transaction">[Payout Proof #{%dul t.Index %}]</a></td>
{% if sweepsCount > 0 %}
{% code outputSweeps := sweeps[t.Index] %}
{% if len(outputSweeps) > 0 %}
{% code sweep := outputSweeps[0] %}
<td class="smaller" title="{%s utc_date(sweep.Timestamp) %}"><a href="/transaction-lookup?txid={%= hex(sweep.Id) %}" class="mono">{%= shorten(sweep.Id, 10) %} {%d sweep.MinerCount %} / {%d sweep.InputCount %}</a></td>
<td class="smaller" title="{%s utc_date(sweep.Timestamp) %}"><a href="/transaction-lookup?txid={%= hex(ctx, sweep.Id) %}" class="mono">{%= shorten(ctx, sweep.Id, 10) %} {%d sweep.MinerCount %} / {%d sweep.InputCount %}</a></td>
{% elseif (ctx.Pool.MainChain.Height - sideBlock.MainHeight + 1) < 60 %}
<td class="small">Not unlocked</td>
{% else %}
@ -229,7 +230,7 @@
<h2>Included Transactions</h2>
<ul class="mono">
{% for _, t := range poolBlock.Main.Transactions %}
<li><a href="/t/{%= henc(t) %}">{%= hex(t) %}</a></li>
<li><a href="/t/{%= henc(t) %}">{%= hex(ctx, t) %}</a></li>
{% endfor %}
</ul>
{% endif %}

View file

@ -1,14 +1,14 @@
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/monero/address" %}
{% func TemplateRowMiner(addr *address.Address, alias string) %}
{%= TemplateRowMinerWithTag(addr, alias, "td") %}
{% func TemplateRowMiner(ctx *GlobalRequestContext, addr *address.Address, alias string) %}
{%= TemplateRowMinerWithTag(ctx, addr, alias, "td") %}
{% endfunc %}
{% func TemplateRowMinerWithTag(addr *address.Address, alias string, tag string) %}
{% func TemplateRowMinerWithTag(ctx *GlobalRequestContext, addr *address.Address, alias string, tag string) %}
{% code encodedMinerAddress := addr.ToBase58() %}
{% if alias != "" %}
<{%s tag %} title="{%z= encodedMinerAddress %} ({%s alias %})" class="mono small"><a href="/miner/{%z= encodedMinerAddress %}">{%= shorten(alias, 10) %}</a></{%s tag %}>
<{%s tag %} title="{%z= encodedMinerAddress %} ({%s alias %})" class="mono small"><a href="/miner/{%z= encodedMinerAddress %}">{%= shorten(ctx, alias, 10) %}</a></{%s tag %}>
{% else %}
<{%s tag %} title="{%z= encodedMinerAddress %}" class="mono small"><a href="/miner/{%z= encodedMinerAddress %}">{%= shorten(encodedMinerAddress, 10) %}</a></{%s tag %}>
<{%s tag %} title="{%z= encodedMinerAddress %}" class="mono small"><a href="/miner/{%z= encodedMinerAddress %}">{%= shorten(ctx, encodedMinerAddress, 10) %}</a></{%s tag %}>
{% endif %}
{% endfunc %}

View file

@ -19,12 +19,12 @@
</tr>
{% for i, s := range shares %}
<tr{% if s.MinedMainAtHeight %} class="hl-found"{% endif %}>
<th><a href="/share/{%= hex(s.TemplateId) %}">{%dul s.SideHeight %}</a></th>
<td class="mono smaller"><a href="/share/{%= hex(s.TemplateId) %}">{%= shorten(s.TemplateId, 10) %}</a></td>
<th><a href="/share/{%= hex(ctx, s.TemplateId) %}">{%dul s.SideHeight %}</a></th>
<td class="mono smaller"><a href="/share/{%= hex(ctx, s.TemplateId) %}">{%= shorten(ctx, s.TemplateId, 10) %}</a></td>
{% if s.MinedMainAtHeight %}
<th title="{%= hex(s.MainId) %}"><a href="/b/{%s benc(s.MainHeight) %}">{%dul s.MainHeight %}</a></th>
<th title="{%= hex(ctx, s.MainId) %}"><a href="/b/{%s benc(s.MainHeight) %}">{%dul s.MainHeight %}</a></th>
{% else %}
<td title="{%= hex(s.MainId) %}">{%dul s.MainHeight %}</td>
<td title="{%= hex(ctx, s.MainId) %}">{%dul s.MainHeight %}</td>
{% endif %}
<td title="{%s utc_date(s.Timestamp) %}">{%s date_diff_short(s.Timestamp) %}</td>
{% if efforts != nil %}
@ -37,7 +37,7 @@
{% endif %}
{% endif %}
{% if !isMiner %}
{%= TemplateRowMiner(s.MinerAddress, s.MinerAlias) %}
{%= TemplateRowMiner(ctx, s.MinerAddress, s.MinerAlias) %}
{% endif %}
<td>{%= software_info(s.SoftwareId, s.SoftwareVersion) %}</td>
<td title="{%dul side_block_weight(s, s.SideHeight, ctx.Consensus.ChainWindowSize, ctx.Consensus) %}">{%s si_units(side_block_weight(s, s.SideHeight, ctx.Consensus.ChainWindowSize, ctx.Consensus), 2) %}</td>

View file

@ -1,6 +1,6 @@
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/cmd/index" %}
{% func TemplateSweeps(ctx *GlobalRequestContext, sweeps []*index.MainLikelySweepTransaction, isMiner bool) %}
{% func TemplateSweeps(ctx *GlobalRequestContext, sweeps <-chan *index.MainLikelySweepTransaction, isMiner bool) %}
{% if isMiner %}
<table class="center datatable" style="max-width: calc(12em + 10em + 10em + 8em + 10em + 10em + 10em + 12em)">
{% else %}
@ -19,15 +19,15 @@
<th style="width: 10em;" title="The number and ratio of decoy inputs not owned by miners on this sweep">Unknown Decoys</th>
<th style="width: 10em;" title="The value known from Coinbase sources">Swept Coinbase Value</th>
</tr>
{% for _, s := range sweeps %}
{% for s := range sweeps %}
<tr>
<td class="mono small"><a href="/transaction-lookup?txid={%= hex(s.Id) %}">{%= shorten(s.Id, 10) %}</a></td>
<td class="mono small"><a href="/transaction-lookup?txid={%= hex(ctx, s.Id) %}">{%= shorten(ctx, s.Id, 10) %}</a></td>
<td title="{%s utc_date(s.Timestamp) %}">{%s date_diff_short(s.Timestamp) %}</td>
{% if !isMiner %}
{% code
addr := s.Address.ToBase58()
%}
<td title="{%z= addr %}" class="mono small"><a href="/miner/{%z= addr %}">{%= shorten(addr, 10) %}</a></td>
<td title="{%z= addr %}" class="mono small"><a href="/miner/{%z= addr %}">{%= shorten(ctx, addr, 10) %}</a></td>
{% endif %}
<td>{%d s.InputDecoyCount %}</td>
<td>{%d s.InputCount %} / {%d len(s.GlobalOutputIndices) %}</td>

View file

@ -55,7 +55,7 @@ type TransactionLookupPage struct {
</p>
<div>
<label for="txid">Transaction Id</label><br/>
<input type="text" name="txid" id="txid" placeholder="e1c88cd5fb5538edfcb4814c286cb0af02b7800f50a86e50626014124aec2f1e" size="64" maxlength="64" class="mono" value="{% if p.TransactionId != types.ZeroHash %}{%= hex(p.TransactionId) %}{% endif %}"/>
<input type="text" name="txid" id="txid" placeholder="e1c88cd5fb5538edfcb4814c286cb0af02b7800f50a86e50626014124aec2f1e" size="64" maxlength="64" class="mono" value="{% if p.TransactionId != types.ZeroHash %}{%= hex(p.Context(), p.TransactionId) %}{% endif %}"/>
</div>
<div style="margin-top: 10px">
<input type="submit" value="Lookup" style="width: 20em;"/>
@ -75,7 +75,7 @@ type TransactionLookupPage struct {
<table class="center" style="max-width: calc(8em + 15em + 15em + 15em + 15em + 15em + 15em);">
<tr>
<td colspan="7">
<p><strong>Transaction Id:</strong> <a class="mono small" href="/t/{%= henc(p.TransactionId) %}">{%= hex(p.TransactionId) %}</a></p>
<p><strong>Transaction Id:</strong> <a class="mono small" href="/t/{%= henc(p.TransactionId) %}">{%= hex(p.Context(), p.TransactionId) %}</a></p>
{% code minerAddress := p.Miner.Address.ToBase58() %}
<p><strong>Miner Payout Address:</strong> <a href="/miner/{%z= minerAddress %}"><span class="mono small">{%z= minerAddress %}</span></a></p>
<p><strong>Likely:</strong> {% if p.LikelyMiner %}Yes{% else %}Not likely{% endif %}</p>
@ -127,11 +127,11 @@ type TransactionLookupPage struct {
{% else %}
<tr>
<td>{%d index %}</td>
<td class="mono small" title="{%= hex(input.Input.KeyImage) %}">{%= shorten(input.Input.KeyImage, 10) %}</td>
<td class="mono small" title="{%= hex(p.Context(), input.Input.KeyImage) %}">{%= shorten(p.Context(), input.Input.KeyImage, 10) %}</td>
{% endif %}
<td class="small">-</td>
{% code out := p.Result.Outs[totalInputCount] %}
<td title="{%= hex(out.TransactionId) %}" class="mono small"><a href="/t/{%= henc(out.TransactionId) %}">{%= shorten(out.TransactionId, 10) %}</a></td>
<td title="{%= hex(p.Context(), out.TransactionId) %}" class="mono small"><a href="/t/{%= henc(out.TransactionId) %}">{%= shorten(p.Context(), out.TransactionId, 10) %}</a></td>
<td class="small">{%dul input.Input.KeyOffsets[oindex] %}</td>
<td class="small">-</td>
<td class="small">-</td>
@ -142,19 +142,19 @@ type TransactionLookupPage struct {
{% else %}
<tr {% if o.Address.Compare(p.Miner.Address) == 0 %} class="hl-found"{% endif %}>
<td>{%d index %}</td>
<td class="mono small" title="{%= hex(input.Input.KeyImage) %}">{%= shorten(input.Input.KeyImage, 10) %}</td>
<td class="mono small" title="{%= hex(p.Context(), input.Input.KeyImage) %}">{%= shorten(p.Context(), input.Input.KeyImage, 10) %}</td>
{% endif %}
{% code
addr := o.Address.ToBase58()
%}
<td title="{%z= addr %}" class="mono small"><a href="/miner/{%z= addr %}">{%= shorten(addr, 10) %}</a></td>
<td title="{%z= addr %}" class="mono small"><a href="/miner/{%z= addr %}">{%= shorten(p.Context(), addr, 10) %}</a></td>
{% if o.Coinbase != nil %}
<td title="{%= hex(o.Coinbase.Id) %}" class="mono small"><a href="/t/{%= henc(o.Coinbase.Id) %}">{%= shorten(o.Coinbase.Id, 10) %}</a> #{%dul uint64(o.Coinbase.Index) %}</td>
<td title="{%= hex(p.Context(), o.Coinbase.Id) %}" class="mono small"><a href="/t/{%= henc(o.Coinbase.Id) %}">{%= shorten(p.Context(), o.Coinbase.Id, 10) %}</a> #{%dul uint64(o.Coinbase.Index) %}</td>
<td class="small">{%dul o.GlobalOutputIndex %}</td>
<td class="small" title="This input was seen as an output to a mined Monero block via P2Pool">Coinbase</td>
<td class="small mono">{%s monero_to_xmr(o.Coinbase.Value) %} XMR</td>
{% elseif o.Sweep != nil %}
<td title="{%= hex(o.Sweep.Id) %}" class="mono small"><a href="/transaction-lookup?txid={%= hex(o.Sweep.Id) %}">{%= shorten(o.Sweep.Id, 10) %}</a>
<td title="{%= hex(p.Context(), o.Sweep.Id) %}" class="mono small"><a href="/transaction-lookup?txid={%= hex(p.Context(), o.Sweep.Id) %}">{%= shorten(p.Context(), o.Sweep.Id, 10) %}</a>
{% for oindex, goi := range o.Sweep.GlobalOutputIndices %}
{% if goi == o.GlobalOutputIndex %}
#{%d oindex %}/{%d len(o.Sweep.GlobalOutputIndices) %}

View file

@ -585,13 +585,13 @@ func main() {
if miner != nil {
renderPage(request, writer, &views.SweepsPage{
Refresh: refresh,
Sweeps: getSliceFromAPI[*index.MainLikelySweepTransaction](fmt.Sprintf("sweeps/%d?limit=100", miner.Id)),
Sweeps: getStreamFromAPI[*index.MainLikelySweepTransaction](fmt.Sprintf("sweeps/%d?limit=100", miner.Id)),
Miner: miner.Address,
}, poolInfo)
} else {
renderPage(request, writer, &views.SweepsPage{
Refresh: refresh,
Sweeps: getSliceFromAPI[*index.MainLikelySweepTransaction]("sweeps?limit=100", 30),
Sweeps: getStreamFromAPI[*index.MainLikelySweepTransaction]("sweeps?limit=100"),
Miner: nil,
}, poolInfo)
}
@ -759,7 +759,7 @@ func main() {
raw = b
}
payouts := getSliceFromAPI[*index.Payout](fmt.Sprintf("block_by_id/%s/payouts", block.MainId))
payouts := getStreamFromAPI[*index.Payout](fmt.Sprintf("block_by_id/%s/payouts", block.MainId))
sweepsCount := 0
@ -858,7 +858,7 @@ func main() {
var lastFound []*index.FoundBlock
var payouts []*index.Payout
var sweeps []*index.MainLikelySweepTransaction
var sweeps <-chan *index.MainLikelySweepTransaction
var raw *sidechain.PoolBlock
@ -891,11 +891,7 @@ func main() {
defer wg.Done()
lastFound = getSliceFromAPI[*index.FoundBlock](fmt.Sprintf("found_blocks?limit=10&miner=%d", miner.Id))
}()
wg.Add(1)
go func() {
defer wg.Done()
sweeps = getSliceFromAPI[*index.MainLikelySweepTransaction](fmt.Sprintf("sweeps/%d?limit=5", miner.Id))
}()
sweeps = getStreamFromAPI[*index.MainLikelySweepTransaction](fmt.Sprintf("sweeps/%d?limit=5", miner.Id))
wg.Add(1)
go func() {
defer wg.Done()
@ -1026,6 +1022,7 @@ func main() {
if hashRate > 0 && magnitude > 0 {
dailyHashRate = uint64(hashRate * magnitude)
}
minerPage.HashrateSubmit = true
}
minerPage.HashrateLocal = hashRate
@ -1117,18 +1114,8 @@ func main() {
return
}
payouts := getSliceFromAPI[*index.Payout](fmt.Sprintf("payouts/%d?search_limit=0", miner.Id))
if len(payouts) == 0 {
renderPage(request, writer, views.NewErrorPage(http.StatusNotFound, "Address Not Found", "You need to have mined at least one share in the past, and a main block found during that period. Come back later :)"))
return
}
payouts := getStreamFromAPI[*index.Payout](fmt.Sprintf("payouts/%d?search_limit=0", miner.Id))
renderPage(request, writer, &views.PayoutsPage{
Total: func() (result uint64) {
for _, p := range payouts {
result += p.Reward
}
return
}(),
Miner: miner.Address,
Payouts: payouts,
Refresh: refresh,