Speedup / less memory allocations on web hex / shorten / henc calls, fast path difficulty UnmarshalJSON

This commit is contained in:
DataHoarder 2023-07-21 17:43:24 +02:00
parent 2256b460bc
commit d992ce6e18
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
15 changed files with 238 additions and 127 deletions

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/{%s 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/{%s hex(p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}" title="{%s hex(p.YourTipRaw.SideTemplateId(p.Context().Consensus)) %}">{%s shorten(hex(p.YourTipRaw.SideTemplateId(p.Context().Consensus)), 10) %}</a></td>
<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 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/{%s hex(p.OurTip.TemplateId) %}">{%dul p.OurTip.SideHeight %}</a></td>
<td style="width: 10em"><strong>Observer SideChain Id</strong><br/><a href="/share/{%s hex(p.OurTip.TemplateId) %}" title="{%s hex(p.OurTip.TemplateId) %}">{%s shorten(hex(p.OurTip.TemplateId), 10) %}</a></td>
<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 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

@ -1,16 +1,13 @@
package views
import (
"encoding/binary"
hex2 "encoding/hex"
"fmt"
"git.gammaspectra.live/P2Pool/p2pool-observer/index"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
types2 "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/types"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
"log"
"strconv"
"strings"
"time"
@ -51,21 +48,6 @@ func time_elapsed_short[T int64 | uint64 | int | float64](v T) string {
}
}
func shorten(val any, n int) string {
var value string
if s, ok := val.(string); ok {
value = s
} else if h, ok := val.(types.Hash); ok {
value = h.String()
} else if s, ok := val.(fmt.Stringer); ok {
value = s.String()
} else {
value = fmt.Sprintf("%s", value)
}
return utils.Shorten(value, n)
}
func software_info(softwareId types2.SoftwareId, softwareVersion types2.SoftwareVersion) string {
if softwareId == 0 && softwareVersion == 0 {
return "Not present"
@ -161,24 +143,6 @@ func bencstr(val string) string {
}
}
func henc(val any) string {
if h, ok := val.(types.Hash); ok {
return utils.EncodeHexBinaryNumber(h.String())
} else if k, ok := val.(crypto.PrivateKeyBytes); ok {
return utils.EncodeHexBinaryNumber(k.String())
} else if s, ok := val.(string); ok {
return utils.EncodeHexBinaryNumber(s)
} else if h, ok := val.(types.Hash); ok {
return utils.EncodeHexBinaryNumber(h.String())
} else if s, ok := val.(fmt.Stringer); ok {
return utils.EncodeHexBinaryNumber(s.String())
}
//TODO: remove this
log.Panic()
return ""
}
func str(val any) string {
if strVal, ok := val.(fmt.Stringer); ok {
return strVal.String()
@ -241,33 +205,3 @@ func coinbase_extra(b *sidechain.PoolBlock) string {
}
return strings.Join(result, " ")
}
func hex(val any) string {
if s, ok := val.(string); ok {
return s
} else if s, ok := val.(types.Difficulty); ok {
return s.String()
} else if s, ok := val.(crypto.PrivateKey); ok {
return s.String()
} else if s, ok := val.(crypto.PublicKey); ok {
return s.String()
} else if s, ok := val.(crypto.PrivateKeyBytes); ok {
return s.String()
} else if s, ok := val.(crypto.PublicKeyBytes); ok {
return s.String()
} else if s, ok := val.(types.Hash); ok {
return s.String()
} else if s, ok := val.([]byte); ok {
return hex2.EncodeToString(s)
} else if s, ok := val.(uint32); ok {
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], s)
return hex2.EncodeToString(buf[:])
} else if s, ok := val.(uint64); ok {
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], s)
return hex2.EncodeToString(buf[:])
}
return fmt.Sprintf("%s", val)
}

133
cmd/web/views/funcs.qtpl Normal file
View file

@ -0,0 +1,133 @@
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/types" %}
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto" %}
{% import "git.gammaspectra.live/P2Pool/p2pool-observer/utils" %}
{% import "encoding/binary" %}
{% import "fmt" %}
{% import hex2 "encoding/hex" %}
{% stripspace %}
{% func hex(val any) %}
{% code
var hexBuf [types.HashSize*2]byte
%}
{% switch s := val.(type) %}
{% case string %}
{%s s %}
{% case types.Difficulty %}
{% code
hex2.Encode(hexBuf[:types.DifficultySize*2], s.Bytes())
%}
{%z= hexBuf[:types.DifficultySize*2] %}
{% case crypto.PrivateKey %}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
%}
{%z= hexBuf[:] %}
{% case crypto.PublicKey %}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
%}
{%z= hexBuf[:] %}
{% case crypto.PrivateKeyBytes %}
{% code
hex2.Encode(hexBuf[:], s[:])
%}
{%z= hexBuf[:] %}
{% case crypto.PublicKeyBytes %}
{% code
hex2.Encode(hexBuf[:], s[:])
%}
{%z= hexBuf[:] %}
{% case types.Hash %}
{% code
hex2.Encode(hexBuf[:], s[:])
%}
{%z= hexBuf[:] %}
{% case []byte %}
{%s= hex2.EncodeToString(s) %}
{% case uint32 %}
{% code
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], s)
hex2.Encode(hexBuf[:4*2], buf[:])
%}
{%z= hexBuf[:4*2] %}
{% case uint64 %}
{% code
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], s)
hex2.Encode(hexBuf[:8*2], buf[:])
%}
{%z= hexBuf[:8*2] %}
{% default %}
{%v val %}
{% endswitch %}
{% endfunc %}
{% func shorten(val any, n int) %}
{% code
var hexBuf [types.HashSize*2]byte
%}
{% switch s := val.(type) %}
{% case string %}
{%s utils.Shorten(s, n) %}
{% case crypto.PrivateKey %}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{% case crypto.PublicKey %}
{% code
hex2.Encode(hexBuf[:], s.AsSlice())
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{% case crypto.PrivateKeyBytes %}
{% code
hex2.Encode(hexBuf[:], s[:])
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{% case crypto.PublicKeyBytes %}
{% code
hex2.Encode(hexBuf[:], s[:])
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{% case types.Hash %}
{% code
hex2.Encode(hexBuf[:], s[:])
%}
{%z= utils.ShortenSlice(hexBuf[:], n) %}
{% case fmt.Stringer %}
{%s utils.Shorten(s.String(), n) %}
{% default %}
{%s utils.Shorten(fmt.Sprintf("%v", val), n) %}
{% endswitch %}
{% endfunc %}
{% func henc(val any) %}
{% code
var buf [types.HashSize*2+1]byte
%}
{% switch s := val.(type) %}
{% case types.Hash %}
{% code
dst := utils.EncodeSliceBinaryNumber(buf[:], s[:])
%}
{%z= dst[:] %}
{% case crypto.PrivateKeyBytes %}
{% code
dst := utils.EncodeSliceBinaryNumber(buf[:], s[:])
%}
{%z= dst[:] %}
{% case string %}
{%s= utils.EncodeHexBinaryNumber(s) %}
{% case fmt.Stringer %}
{%s= utils.EncodeHexBinaryNumber(s.String()) %}
{% default %}
panic("type not allowed")
{% endswitch %}
{% endfunc %}
{% endstripspace %}

View file

@ -35,9 +35,9 @@ type IndexPage struct {
<th style="width: 15em">Monero Hashrate</th>
</tr>
<tr>
<td title="{%s hex(p.Context().Pool.SideChain.Id) %}"><a href="/share/{%s hex(p.Context().Pool.SideChain.Id) %}">{%dul p.Context().Pool.SideChain.Height %}</a></td>
<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>{%s si_units(diff_hashrate(p.Context().Pool.SideChain.Difficulty, p.Context().Consensus.TargetBlockTime), 2) %}H/s</td>
<td title="{%s 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().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

@ -26,26 +26,26 @@ type ProofPage struct {
<p><strong>Payout Address:</strong> <span class="mono small"><a href="/miner/{%s encodedMinerAddress %}">{%s 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/{%s henc(p.Output.Id) %}">{%s 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.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">{%s hex(p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<p>Verify on Monero CLI: <span class="mono smaller">check_tx_proof {%s hex(p.Output.Id) %} {%s encodedMinerAddress %} {%s hex(p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<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) %} {%s encodedMinerAddress %} {%= hex(p.Raw.Side.CoinbasePrivateKey) %}</span></p>
<p>
<a href="{%s p.Context().GetUrl("localmonero.co") %}/blocks/tx/{%s hex(p.Output.Id) %}?xmraddress={%s encodedMinerAddress %}&txprvkey={%s hex(p.Raw.Side.CoinbasePrivateKey) %}">Verify on LocalMonero</a><br/>
<a href="{%s p.Context().GetUrl("www.exploremonero.com") %}/receipt/{%s hex(p.Output.Id) %}/{%s encodedMinerAddress %}/{%s hex(p.Raw.Side.CoinbasePrivateKey) %}">Verify on Explore Monero</a><br/>
<a href="{%s p.Context().GetUrl("monero.com") %}/payment/{%s hex(p.Output.Id) %}/{%s encodedMinerAddress %}/{%s hex(p.Raw.Side.CoinbasePrivateKey) %}/">Verify on Monero.com</a><br/>
<a href="{%s p.Context().GetUrl("localmonero.co") %}/blocks/tx/{%= hex(p.Output.Id) %}?xmraddress={%s 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) %}/{%s 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) %}/{%s encodedMinerAddress %}/{%= hex(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">{%s hex(address.GetTxProofV2(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}</span></p>
<p><strong>OutProofV1:</strong> <span class="mono smaller">{%s hex(address.GetTxProofV1(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}</span></p>
<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>Verify on Monero GUI <span class="small">(Advanced -> Prove/check -> Check Transaction)</span></p>
</div>
</div>

View file

@ -21,14 +21,14 @@
</tr>
{% for i, b := range foundBlocks %}
<tr>
<th title="{%s hex(b.MainBlock.Id) %}"><a href="/b/{%s benc(b.MainBlock.Height) %}">{%dul b.MainBlock.Height %}</a></th>
<th title="{%= hex(b.MainBlock.Id) %}"><a href="/b/{%s benc(b.MainBlock.Height) %}">{%dul b.MainBlock.Height %}</a></th>
{% if b.UncleOf != types.ZeroHash %}
<th title="{%s hex(b.MainBlock.SideTemplateId) %} is an uncle of height {%dul b.EffectiveHeight %}, {%s hex(b.UncleOf) %}">
<a href="/share/{%s hex(b.MainBlock.SideTemplateId) %}">{%dul b.SideHeight %}*</a>
<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>
{% else %}
<th title="{%s hex(b.MainBlock.SideTemplateId) %}">
<a href="/share/{%s hex(b.MainBlock.SideTemplateId) %}">{%dul b.SideHeight %}</a>
<th title="{%= hex(b.MainBlock.SideTemplateId) %}">
<a href="/share/{%= hex(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>
@ -49,8 +49,8 @@
<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="{%s hex(b.MainBlock.CoinbaseId) %}" class="mono small"><a href="/t/{%s henc(b.MainBlock.CoinbaseId) %}">{%s shorten(hex(b.MainBlock.CoinbaseId), 10) %}</a></td>
<td class="mono smaller">{%s hex(b.MainBlock.CoinbasePrivateKey) %}</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>
</tr>
{% endfor %}
</table>

View file

@ -13,13 +13,13 @@
</tr>
{% for _, p := range payouts %}
<tr>
<th title="{%s hex(p.MainId) %}"><a href="/b/{%s benc(p.MainHeight) %}">{%dul p.MainHeight %}</a></th>
<th title="{%s hex(p.TemplateId) %}"><a href="/share/{%s hex(p.TemplateId) %}">{%dul p.SideHeight %}</a></th>
<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>
<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="{%s hex(p.CoinbaseId) %}" class="mono small"><a href="/t/{%s henc(p.CoinbaseId) %}">{%s shorten(hex(p.CoinbaseId), 10) %}</a></td>
<td><a href="/proof/{%s 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(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>
</tr>
{% endfor %}
</table>

View file

@ -26,9 +26,9 @@
{% if sideBlock.SideHeight == 0 %}
<td colspan="2">Genesis Block</td>
{% elseif sideBlock.IsUncle() %}
<td colspan="2"><a href="/share/{%s hex(sideBlock.UncleOf) %}">&lt;&lt; Parent share</a></td>
<td colspan="2"><a href="/share/{%= hex(sideBlock.UncleOf) %}">&lt;&lt; Parent share</a></td>
{% else %}
<td colspan="2"><a href="/share/{%s hex(sideBlock.ParentTemplateId) %}">&lt;&lt; Previous share</a></td>
<td colspan="2"><a href="/share/{%= hex(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">{%s hex(sideBlock.TemplateId) %}</td>
<td class="mono smaller">{%= hex(sideBlock.TemplateId) %}</td>
{% else %}
<td class="mono smaller">{%s hex(poolBlock.SideTemplateId(ctx.Consensus)) %}</td>
<td class="mono smaller">{%= hex(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) %}">{%s hex(sideBlock.MainId) %}</a></td>
<td class="mono smaller"><a href="/b/{%s benc(sideBlock.MainHeight) %}">{%= hex(sideBlock.MainId) %}</a></td>
{% else %}
<td>{%dul sideBlock.MainHeight %}</td>
<td class="mono smaller">{%s hex(sideBlock.MainId) %}</td>
<td class="mono smaller">{%= hex(sideBlock.MainId) %}</td>
{% endif %}
{% else %}
<td>{%dul poolBlock.Main.Coinbase.GenHeight %}</td>
<td class="mono smaller">{%s hex(poolBlock.MainId()) %}</td>
<td class="mono smaller">{%= hex(poolBlock.MainId()) %}</td>
{% endif %}
</tr>
<tr><td colspan="4">&nbsp;</td></tr>
@ -77,7 +77,7 @@
<tr>
<td title="{%s utc_date(poolBlock.Main.Timestamp) %}">{%s date_diff_short(poolBlock.Main.Timestamp) %}</td>
{% if sideBlock != nil %}
<td class="mono smaller">{%s hex(sideBlock.PowHash) %}</td>
<td class="mono smaller">{%= hex(sideBlock.PowHash) %}</td>
{%= TemplateRowMiner(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 %}
@ -100,12 +100,12 @@
<td>{%s side_block_valuation(poolBlock, ctx.Consensus) %}</td>
{% endif %}
{% if sideBlock != nil && sideBlock.MinedMainAtHeight %}
<td class="mono smaller"><a href="/t/{%s henc(poolBlock.Main.Coinbase.Id()) %}">{%s hex(poolBlock.Main.Coinbase.Id()) %}</a></td>
<td class="mono smaller"><a href="/t/{%= henc(poolBlock.Main.Coinbase.Id()) %}">{%= hex(poolBlock.Main.Coinbase.Id()) %}</a></td>
{% else %}
<td class="mono smaller">{%s hex(poolBlock.Main.Coinbase.Id()) %}</td>
<td class="mono smaller">{%= hex(poolBlock.Main.Coinbase.Id()) %}</td>
{% endif %}
<td class="small">{%s monero_to_xmr(poolBlock.Main.Coinbase.TotalReward) %} XMR</td>
<td class="mono smaller">{%s hex(poolBlock.Side.CoinbasePrivateKey) %}</td>
<td class="mono smaller">{%= hex(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="{%s hex(poolBlock.Main.Nonce) %}">{%dul uint64(poolBlock.Main.Nonce) %}</td>
<td class="mono" title="{%= hex(poolBlock.Main.Nonce) %}">{%dul uint64(poolBlock.Main.Nonce) %}</td>
<td class="mono smaller">{%s str(poolBlock.Side.CumulativeDifficulty) %}</td>
<td class="mono" title="{%s hex(poolBlock.ExtraNonce()) %}">{%dul uint64(poolBlock.ExtraNonce()) %}</td>
<td class="mono" title="{%= hex(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>{%s 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">{%s hex(poolBlock.Side.ExtraBuffer.RandomNumber) %}</span> / <span class="mono" title="SideChain Extra Nonce">{%s hex(poolBlock.Side.ExtraBuffer.SideChainExtraNonce) %}{% endif %}</span></td>
<td>{% if poolBlock.GetPrivateKeySeed() != types.ZeroHash %}<span class="mono smaller">{%s 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(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>
</tr>
</table>
@ -144,7 +144,7 @@
{% endif %}
<ul class="mono">
{% for _, u := range poolBlock.Side.Uncles %}
<li><a href="/share/{%s hex(u) %}">{%s hex(u) %}</a></li>
<li><a href="/share/{%= hex(u) %}">{%= hex(u) %}</a></li>
{% endfor %}
</ul>
{% endif %}
@ -200,7 +200,7 @@
{% for _, t := range poolBlock.Main.Coinbase.Outputs %}
<tr>
<td>{%dul t.Index %}</td>
<td class="mono smaller">{%s hex(t.EphemeralPublicKey) %}</td>
<td class="mono smaller">{%= hex(t.EphemeralPublicKey) %}</td>
{% code var globalOutputIndex uint64 %}
{% if len(coinbaseOutputs) > int(t.Index) %}
{% code globalOutputIndex = coinbaseOutputs[t.Index].GlobalOutputIndex %}
@ -209,12 +209,12 @@
<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/{%s 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(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={%s hex(sweep.Id) %}" class="mono">{%s shorten(hex(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(sweep.Id) %}" class="mono">{%= shorten(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 +229,7 @@
<h2>Included Transactions</h2>
<ul class="mono">
{% for _, t := range poolBlock.Main.Transactions %}
<li><a href="/t/{%s henc(t) %}">{%s hex(t) %}</a></li>
<li><a href="/t/{%= henc(t) %}">{%= hex(t) %}</a></li>
{% endfor %}
</ul>
{% endif %}

View file

@ -7,8 +7,8 @@
{% func TemplateRowMinerWithTag(addr *address.Address, alias string, tag string) %}
{% code encodedMinerAddress := addr.ToBase58() %}
{% if alias != "" %}
<{%s tag %} title="{%s encodedMinerAddress %} ({%s alias %})" class="mono small"><a href="/miner/{%s encodedMinerAddress %}">{%s shorten(alias, 10) %}</a></{%s tag %}>
<{%s tag %} title="{%s encodedMinerAddress %} ({%s alias %})" class="mono small"><a href="/miner/{%s encodedMinerAddress %}">{%= shorten(alias, 10) %}</a></{%s tag %}>
{% else %}
<{%s tag %} title="{%s encodedMinerAddress %}" class="mono small"><a href="/miner/{%s encodedMinerAddress %}">{%s shorten(encodedMinerAddress, 10) %}</a></{%s tag %}>
<{%s tag %} title="{%s encodedMinerAddress %}" class="mono small"><a href="/miner/{%s encodedMinerAddress %}">{%= shorten(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/{%s hex(s.TemplateId) %}">{%dul s.SideHeight %}</a></th>
<td class="mono smaller"><a href="/share/{%s hex(s.TemplateId) %}">{%s shorten(s.TemplateId, 10) %}</a></td>
<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>
{% if s.MinedMainAtHeight %}
<th title="{%s hex(s.MainId) %}"><a href="/b/{%s benc(s.MainHeight) %}">{%dul s.MainHeight %}</a></th>
<th title="{%= hex(s.MainId) %}"><a href="/b/{%s benc(s.MainHeight) %}">{%dul s.MainHeight %}</a></th>
{% else %}
<td title="{%s hex(s.MainId) %}">{%dul s.MainHeight %}</td>
<td title="{%= hex(s.MainId) %}">{%dul s.MainHeight %}</td>
{% endif %}
<td title="{%s utc_date(s.Timestamp) %}">{%s date_diff_short(s.Timestamp) %}</td>
{% if efforts != nil %}

View file

@ -21,10 +21,10 @@
</tr>
{% for _, s := range sweeps %}
<tr>
<td class="mono small"><a href="/transaction-lookup?txid={%s hex(s.Id) %}">{%s shorten(hex(s.Id), 10) %}</a></td>
<td class="mono small"><a href="/transaction-lookup?txid={%= hex(s.Id) %}">{%= shorten(s.Id, 10) %}</a></td>
<td title="{%s utc_date(s.Timestamp) %}">{%s date_diff_short(s.Timestamp) %}</td>
{% if !isMiner %}
<td title="{%s s.Address.ToBase58() %}" class="mono small"><a href="/miner/{%s s.Address.ToBase58() %}">{%s shorten(s.Address.ToBase58(), 10) %}</a></td>
<td title="{%s s.Address.ToBase58() %}" class="mono small"><a href="/miner/{%s s.Address.ToBase58() %}">{%= shorten(s.Address.ToBase58(), 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 %}{%s 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.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/{%s henc(p.TransactionId) %}">{%s hex(p.TransactionId) %}</a></p>
<p><strong>Transaction Id:</strong> <a class="mono small" href="/t/{%= henc(p.TransactionId) %}">{%= hex(p.TransactionId) %}</a></p>
{% code minerAddress := p.Miner.Address.ToBase58() %}
<p><strong>Miner Payout Address:</strong> <a href="/miner/{%s minerAddress %}"><span class="mono small">{%s 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="{%s hex(input.Input.KeyImage) %}">{%s shorten(hex(input.Input.KeyImage), 10) %}</td>
<td class="mono small" title="{%= hex(input.Input.KeyImage) %}">{%= shorten(input.Input.KeyImage, 10) %}</td>
{% endif %}
<td class="small">-</td>
{% code out := p.Result.Outs[totalInputCount] %}
<td title="{%s hex(out.TransactionId) %}" class="mono small"><a href="/t/{%s henc(out.TransactionId) %}">{%s shorten(hex(out.TransactionId), 10) %}</a></td>
<td title="{%= hex(out.TransactionId) %}" class="mono small"><a href="/t/{%= henc(out.TransactionId) %}">{%= shorten(out.TransactionId, 10) %}</a></td>
<td class="small">{%dul input.Input.KeyOffsets[oindex] %}</td>
<td class="small">-</td>
<td class="small">-</td>
@ -142,16 +142,16 @@ 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="{%s hex(input.Input.KeyImage) %}">{%s shorten(hex(input.Input.KeyImage), 10) %}</td>
<td class="mono small" title="{%= hex(input.Input.KeyImage) %}">{%= shorten(input.Input.KeyImage, 10) %}</td>
{% endif %}
<td title="{%s o.Address.ToBase58() %}" class="mono small"><a href="/miner/{%s o.Address.ToBase58() %}">{%s shorten(o.Address.ToBase58(), 10) %}</a></td>
<td title="{%s o.Address.ToBase58() %}" class="mono small"><a href="/miner/{%s o.Address.ToBase58() %}">{%= shorten(o.Address.ToBase58(), 10) %}</a></td>
{% if o.Coinbase != nil %}
<td title="{%s hex(o.Coinbase.Id) %}" class="mono small"><a href="/t/{%s henc(o.Coinbase.Id) %}">{%s shorten(hex(o.Coinbase.Id), 10) %}</a> #{%dul uint64(o.Coinbase.Index) %}</td>
<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 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="{%s hex(o.Sweep.Id) %}" class="mono small"><a href="/transaction-lookup?txid={%s hex(o.Sweep.Id) %}">{%s shorten(hex(o.Sweep.Id), 10) %}</a>
<td title="{%= hex(o.Sweep.Id) %}" class="mono small"><a href="/transaction-lookup?txid={%= hex(o.Sweep.Id) %}">{%= shorten(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

@ -247,6 +247,17 @@ func (d *Difficulty) UnmarshalJSON(b []byte) error {
return err
}
if len(b) == DifficultySize*2+2 {
// fast path
var buf [DifficultySize]byte
if _, err := hex.Decode(buf[:], b[1:len(b)-1]); err != nil {
return err
} else {
*d = DifficultyFromBytes(buf[:])
return nil
}
}
if diff, err := DifficultyFromString(s); err != nil {
return err
} else {

View file

@ -1,6 +1,7 @@
package utils
import (
"bytes"
"encoding/hex"
"github.com/jxskiss/base62"
"math/bits"
@ -49,6 +50,26 @@ func DecodeHexBinaryNumber(i string) string {
return ""
}
func EncodeSliceBinaryNumber(dst, src []byte) []byte {
if len(dst) < 1+(len(src)*2) {
return nil
}
v := encoding.EncodeToBuf(dst[:0], src)
if !bytes.ContainsAny(v, "GHIJKLMNOPQRSTUVWXYZghijklmnopqrstuvwxyz") {
copy(dst[1:], v)
dst[0] = '.'
v = dst[:len(v)]
}
if len(v) >= (len(src) * 2) {
hex.Encode(dst, src)
return dst[:len(src)*2]
}
return v
}
func EncodeHexBinaryNumber(v2 string) string {
b, _ := hex.DecodeString(v2)
v1 := encoding.EncodeToString(b)

View file

@ -7,3 +7,15 @@ func Shorten(value string, n int) string {
return value[:n] + "..." + value[len(value)-n:]
}
}
func ShortenSlice(value []byte, n int) []byte {
if len(value) <= n*2+3 {
return value
} else {
copy(value[n+3:], value[len(value)-n:])
value[n] = '.'
value[n+1] = '.'
value[n+2] = '.'
return value[:n*2+3]
}
}