diff --git a/cmd/web/api.go b/cmd/web/api.go index bc31ba8..6d6d7f4 100644 --- a/cmd/web/api.go +++ b/cmd/web/api.go @@ -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) } diff --git a/cmd/web/views/connectivity-check.qtpl b/cmd/web/views/connectivity-check.qtpl index 6343179..1376503 100644 --- a/cmd/web/views/connectivity-check.qtpl +++ b/cmd/web/views/connectivity-check.qtpl @@ -90,16 +90,16 @@ type ConnectivityCheckPage struct { {% if p.Check.Tip != nil %}   - Peer SideChain Height
{%dul p.YourTipRaw.Side.Height %} - Peer SideChain Id
{%= shorten(p.YourTipRaw.SideTemplateId(p.Context().Consensus), 10) %} + Peer SideChain Height
{%dul p.YourTipRaw.Side.Height %} + Peer SideChain Id
{%= shorten(p.Context(), p.YourTipRaw.SideTemplateId(p.Context().Consensus), 10) %} Peer MainChain Height
{%dul p.YourTipRaw.Main.Coinbase.GenHeight %} Peer Difficulty
{%s si_units(p.YourTipRaw.Side.Difficulty.Lo, 4) %} Peer Cumulative Difficulty
{%s si_units(p.YourTipRaw.Side.CumulativeDifficulty.Lo, 4) %} Peer Timestamp
{%s utc_date(p.YourTipRaw.Main.Timestamp) %} - Observer SideChain Height
{%dul p.OurTip.SideHeight %} - Observer SideChain Id
{%= shorten(p.OurTip.TemplateId, 10) %} + Observer SideChain Height
{%dul p.OurTip.SideHeight %} + Observer SideChain Id
{%= shorten(p.Context(), p.OurTip.TemplateId, 10) %} Observer MainChain Height
{%dul p.OurTip.MainHeight %} Observer Difficulty
{%s si_units(p.OurTip.Difficulty, 4) %} Observer Cumulative Difficulty
{%s si_units(p.OurTip.CumulativeDifficulty.Lo, 4) %} diff --git a/cmd/web/views/context.go b/cmd/web/views/context.go index b14e6de..e82c4a6 100644 --- a/cmd/web/views/context.go +++ b/cmd/web/views/context.go @@ -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 { diff --git a/cmd/web/views/funcs.qtpl b/cmd/web/views/funcs.qtpl index c6dfd2c..5725a41 100644 --- a/cmd/web/views/funcs.qtpl +++ b/cmd/web/views/funcs.qtpl @@ -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 %} diff --git a/cmd/web/views/index.qtpl b/cmd/web/views/index.qtpl index 3e7d269..4f800ac 100644 --- a/cmd/web/views/index.qtpl +++ b/cmd/web/views/index.qtpl @@ -35,9 +35,9 @@ type IndexPage struct { Monero Hashrate - {%dul p.Context().Pool.SideChain.Height %} + {%dul p.Context().Pool.SideChain.Height %} {%s si_units(diff_hashrate(p.Context().Pool.SideChain.Difficulty, p.Context().Consensus.TargetBlockTime), 2) %}H/s - {%dul p.Context().Pool.MainChain.Height %} + {%dul p.Context().Pool.MainChain.Height %} {%s si_units(diff_hashrate(p.Context().Pool.MainChain.Difficulty, uint64(p.Context().Pool.MainChain.BlockTime)), 2) %}H/s   diff --git a/cmd/web/views/miner.qtpl b/cmd/web/views/miner.qtpl index 677030e..f846208 100644 --- a/cmd/web/views/miner.qtpl +++ b/cmd/web/views/miner.qtpl @@ -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 {

Most recent payouts

- {%= TemplatePayouts(p.Context(), p.LastPayouts) %} + {%= TemplatePayoutsSlice(p.Context(), p.LastPayouts) %}
[show all historical payouts]
@@ -216,7 +217,11 @@ type MinerPage struct {

Most recent shares

- {%= 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 %}

diff --git a/cmd/web/views/miners.qtpl b/cmd/web/views/miners.qtpl index 253f089..feb1d33 100644 --- a/cmd/web/views/miners.qtpl +++ b/cmd/web/views/miners.qtpl @@ -81,7 +81,7 @@ type MinersPageMinerEntry struct { {% for i, m := range p.Miners %} {%d i+1 %} - {%= TemplateRowMinerWithTag(m.Address, m.Alias, "th") %} + {%= TemplateRowMinerWithTag(p.Context(), m.Address, m.Alias, "th") %} {%= software_info(m.SoftwareId, m.SoftwareVersion) %} {% code minerRatio := float64(m.Weight.Lo) / float64(p.WindowWeight.Lo) %} {%f.3 minerRatio*100 %}% diff --git a/cmd/web/views/payouts.qtpl b/cmd/web/views/payouts.qtpl index 353ae32..0155003 100644 --- a/cmd/web/views/payouts.qtpl +++ b/cmd/web/views/payouts.qtpl @@ -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 {

Historical miner payouts

Payout Address: {%z= p.Miner.ToBase58() %}

-

Estimated total: {%s monero_to_xmr(p.Total) %} XMR

- {%= TemplatePayouts(p.Context(), p.Payouts) %} + {% code var total uint64 %} + + {%= TemplatePayouts(p.Context(), p.Payouts, &total) %} + +

Estimated total: {%s monero_to_xmr(total) %} XMR

{% endfunc %} \ No newline at end of file diff --git a/cmd/web/views/proof.qtpl b/cmd/web/views/proof.qtpl index 310fdaf..717e805 100644 --- a/cmd/web/views/proof.qtpl +++ b/cmd/web/views/proof.qtpl @@ -26,26 +26,26 @@ type ProofPage struct {

Payout Address: {%z= encodedMinerAddress %}

{% endif %} -

Received {%s monero_to_xmr(p.Output.Value) %} XMR on transaction id {%= hex(p.Output.Id) %} (output index #{%dul uint64(p.Output.Index) %}, global output index #{%dul p.Output.GlobalOutputIndex %}).

+

Received {%s monero_to_xmr(p.Output.Value) %} XMR on transaction id {%= hex(p.Context(), p.Output.Id) %} (output index #{%dul uint64(p.Output.Index) %}, global output index #{%dul p.Output.GlobalOutputIndex %}).

{%dul p.Context().Pool.MainChain.Height - p.Block.MainHeight + 1 %} confirmation(s). Coinbase outputs will unlock after 60 confirmations.

Stealth Address: {%s address.GetEphemeralPublicKey(p.Output.MinerAddress, &p.Raw.Side.CoinbasePrivateKey, uint64(p.Output.Index)).String() %}


Payment Proofs

-

Transaction Private Key: {%= hex(p.Raw.Side.CoinbasePrivateKey) %}

-

Verify on Monero CLI: check_tx_proof {%= hex(p.Output.Id) %} {%z= encodedMinerAddress %} {%= hex(p.Raw.Side.CoinbasePrivateKey) %}

+

Transaction Private Key: {%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}

+

Verify on Monero CLI: check_tx_proof {%= hex(p.Context(), p.Output.Id) %} {%z= encodedMinerAddress %} {%= hex(p.Context(), p.Raw.Side.CoinbasePrivateKey) %}

- Verify on LocalMonero
- Verify on Explore Monero
- Verify on Monero.com
+ Verify on LocalMonero
+ Verify on Explore Monero
+ Verify on Monero.com

-

OutProofV2: {%= hex(address.GetTxProofV2(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}

-

OutProofV1: {%= hex(address.GetTxProofV1(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}

+

OutProofV2: {%= hex(p.Context(), address.GetTxProofV2(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}

+

OutProofV1: {%= hex(p.Context(), address.GetTxProofV1(p.Output.MinerAddress, p.Output.Id, &p.Raw.Side.CoinbasePrivateKey, "")) %}

Verify on Monero GUI (Advanced -> Prove/check -> Check Transaction)

diff --git a/cmd/web/views/share.qtpl b/cmd/web/views/share.qtpl index 7bfd6ac..6a529be 100644 --- a/cmd/web/views/share.qtpl +++ b/cmd/web/views/share.qtpl @@ -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 diff --git a/cmd/web/views/sweeps.qtpl b/cmd/web/views/sweeps.qtpl index fb28711..f3dd60c 100644 --- a/cmd/web/views/sweeps.qtpl +++ b/cmd/web/views/sweeps.qtpl @@ -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 } %} diff --git a/cmd/web/views/tpl_found_blocks.qtpl b/cmd/web/views/tpl_found_blocks.qtpl index 4aa843a..889532c 100644 --- a/cmd/web/views/tpl_found_blocks.qtpl +++ b/cmd/web/views/tpl_found_blocks.qtpl @@ -21,14 +21,14 @@ {% for i, b := range foundBlocks %} - {%dul b.MainBlock.Height %} + {%dul b.MainBlock.Height %} {% if b.UncleOf != types.ZeroHash %} - - {%dul b.SideHeight %}* + + {%dul b.SideHeight %}* {% else %} - - {%dul b.SideHeight %} + + {%dul b.SideHeight %} {% endif %} {%s date_diff_short(b.MainBlock.Timestamp) %} @@ -44,13 +44,13 @@ {% else %} unknown {% endif %} - {%= TemplateRowMiner(b.MinerAddress, b.MinerAlias) %} + {%= TemplateRowMiner(ctx, b.MinerAddress, b.MinerAlias) %} {% endif %} {%dul uint64(b.TransactionCount) %} {%s monero_to_xmr(b.MainBlock.Reward) %} XMR {%dul uint64(b.WindowOutputs) %} - {%= shorten(b.MainBlock.CoinbaseId, 10) %} - {%= hex(b.MainBlock.CoinbasePrivateKey) %} + {%= shorten(ctx, b.MainBlock.CoinbaseId, 10) %} + {%= hex(ctx, b.MainBlock.CoinbasePrivateKey) %} {% endfor %} diff --git a/cmd/web/views/tpl_payouts.qtpl b/cmd/web/views/tpl_payouts.qtpl index 0151780..5f58746 100644 --- a/cmd/web/views/tpl_payouts.qtpl +++ b/cmd/web/views/tpl_payouts.qtpl @@ -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) %} + + + + + + + + + + + {% for p := range payouts %} + {% code *total = *total + p.Reward %} + + + + + + + + + + {% endfor %} +
Monero HeightP2Pool HeightAge [h:m:s]RewardGlobal Output IndexCoinbase TransactionPayout Proof
{%dul p.MainHeight %}{%dul p.SideHeight %}{%s date_diff_short(p.Timestamp) %}{%s monero_to_xmr(p.Reward) %} XMR{%dul p.GlobalOutputIndex %}{%= shorten(ctx, p.CoinbaseId, 10) %}[Payout Proof #{%dul uint64(p.Index) %}]
+{% endfunc %} + +{% func TemplatePayoutsSlice(ctx *GlobalRequestContext, payouts []*index.Payout) %} @@ -13,13 +39,13 @@ {% for _, p := range payouts %} - - + + - - + + {% endfor %}
Monero Height
{%dul p.MainHeight %}{%dul p.SideHeight %}{%dul p.MainHeight %}{%dul p.SideHeight %} {%s date_diff_short(p.Timestamp) %} {%s monero_to_xmr(p.Reward) %} XMR {%dul p.GlobalOutputIndex %}{%= shorten(p.CoinbaseId, 10) %}[Payout Proof #{%dul uint64(p.Index) %}]{%= shorten(ctx, p.CoinbaseId, 10) %}[Payout Proof #{%dul uint64(p.Index) %}]
diff --git a/cmd/web/views/tpl_poolblock.qtpl b/cmd/web/views/tpl_poolblock.qtpl index 005bbdb..00733dd 100644 --- a/cmd/web/views/tpl_poolblock.qtpl +++ b/cmd/web/views/tpl_poolblock.qtpl @@ -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) %}
{% if sideBlock != nil %} {% if sideBlock.MinedMainAtHeight %} @@ -26,9 +26,9 @@ {% if sideBlock.SideHeight == 0 %} Genesis Block {% elseif sideBlock.IsUncle() %} - << Parent share + << Parent share {% else %} - << Previous share + << Previous share {% endif %} {% if sideBlock.IsOrphan() %} Orphans do not have next blocks @@ -49,22 +49,22 @@ {%dul poolBlock.Side.Height %} {% if sideBlock != nil %} - {%= hex(sideBlock.TemplateId) %} + {%= hex(ctx, sideBlock.TemplateId) %} {% else %} - {%= hex(poolBlock.SideTemplateId(ctx.Consensus)) %} + {%= hex(ctx, poolBlock.SideTemplateId(ctx.Consensus)) %} {% endif %} {% if sideBlock != nil %} {% if sideBlock.MinedMainAtHeight %} {%dul sideBlock.MainHeight %} - {%= hex(sideBlock.MainId) %} + {%= hex(ctx, sideBlock.MainId) %} {% else %} {%dul sideBlock.MainHeight %} - {%= hex(sideBlock.MainId) %} + {%= hex(ctx, sideBlock.MainId) %} {% endif %} {% else %} {%dul poolBlock.Main.Coinbase.GenHeight %} - {%= hex(poolBlock.MainId()) %} + {%= hex(ctx, poolBlock.MainId()) %} {% endif %}   @@ -77,12 +77,12 @@ {%s date_diff_short(poolBlock.Main.Timestamp) %} {% if sideBlock != nil %} - {%= hex(sideBlock.PowHash) %} - {%= TemplateRowMiner(sideBlock.MinerAddress, sideBlock.MinerAlias) %} + {%= hex(ctx, sideBlock.PowHash) %} + {%= TemplateRowMiner(ctx, sideBlock.MinerAddress, sideBlock.MinerAlias) %} {%dul sideBlock.Difficulty %} / {%dul sideBlock.PowDifficulty %} {% else %} - - {%= TemplateRowMiner(poolBlock.GetAddress().Reference().ToAddress(ctx.Consensus.NetworkType.AddressNetwork()), "") %} + {%= TemplateRowMiner(ctx, poolBlock.GetAddress().Reference().ToAddress(ctx.Consensus.NetworkType.AddressNetwork()), "") %} {%dul poolBlock.Side.Difficulty.Lo %} {% endif %} @@ -100,12 +100,12 @@ {%= side_block_valuation(poolBlock, ctx.Consensus) %} {% endif %} {% if sideBlock != nil && sideBlock.MinedMainAtHeight %} - {%= hex(poolBlock.Main.Coinbase.Id()) %} + {%= hex(ctx, poolBlock.Main.Coinbase.Id()) %} {% else %} - {%= hex(poolBlock.Main.Coinbase.Id()) %} + {%= hex(ctx, poolBlock.Main.Coinbase.Id()) %} {% endif %} {%s monero_to_xmr(poolBlock.Main.Coinbase.TotalReward) %} XMR - {%= hex(poolBlock.Side.CoinbasePrivateKey) %} + {%= hex(ctx, poolBlock.Side.CoinbasePrivateKey) %}   @@ -115,9 +115,9 @@ Monero Target Difficulty - {%dul uint64(poolBlock.Main.Nonce) %} - {%= hex(poolBlock.Side.CumulativeDifficulty) %} - {%dul uint64(poolBlock.ExtraNonce()) %} + {%dul uint64(poolBlock.Main.Nonce) %} + {%= hex(ctx, poolBlock.Side.CumulativeDifficulty) %} + {%dul uint64(poolBlock.ExtraNonce()) %} {% if sideBlock != nil && sideBlock.MainDifficulty != 0 %}{%dul sideBlock.MainDifficulty %}{% endif %}   @@ -130,8 +130,8 @@ {%= software_info(poolBlock.Side.ExtraBuffer.SoftwareId, poolBlock.Side.ExtraBuffer.SoftwareVersion) %} {%s= poolBlock.ShareVersion().String() %} ({% if poolBlock.ShareVersionSignaling() != sidechain.ShareVersion_None %}signaling {%s= poolBlock.ShareVersionSignaling().String() %} support{% else %}no known signaling{% endif %}) - {% if poolBlock.ShareVersion() > sidechain.ShareVersion_V1 %}{%= hex(poolBlock.Side.ExtraBuffer.RandomNumber) %} / {%= hex(poolBlock.Side.ExtraBuffer.SideChainExtraNonce) %}{% endif %} - {% if poolBlock.GetPrivateKeySeed() != types.ZeroHash %}{%= hex(poolBlock.GetPrivateKeySeed()) %}{% else %}Not Deterministic{% endif %} + {% if poolBlock.ShareVersion() > sidechain.ShareVersion_V1 %}{%= hex(ctx, poolBlock.Side.ExtraBuffer.RandomNumber) %} / {%= hex(ctx, poolBlock.Side.ExtraBuffer.SideChainExtraNonce) %}{% endif %} + {% if poolBlock.GetPrivateKeySeed() != types.ZeroHash %}{%= hex(ctx, poolBlock.GetPrivateKeySeed()) %}{% else %}Not Deterministic{% endif %} @@ -144,15 +144,16 @@ {% endif %} {% endif %} {% if sideBlock != nil && payouts != nil %}

Payouts share was weighted into

+ {% code var total uint64 %} - {%= TemplatePayouts(ctx, payouts) %} + {%= TemplatePayouts(ctx, payouts, &total) %} {% if sideBlock.EffectiveHeight > (ctx.Pool.SideChain.Height - uint64(ctx.Pool.SideChain.WindowSize)) %}

Share is inside the PPLNS window. Any Monero blocks found during this period by any P2Pool miner will provide a direct payout.

{% else %} @@ -200,21 +201,21 @@ {% for _, t := range poolBlock.Main.Coinbase.Outputs %} {%dul t.Index %} - {%= hex(t.EphemeralPublicKey) %} + {%= hex(ctx, t.EphemeralPublicKey) %} {% 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 %} {%s monero_to_xmr(t.Reward) %} XMR {% if sideBlock != nil && sideBlock.MinedMainAtHeight %} {%dul globalOutputIndex %} - [Payout Proof #{%dul t.Index %}] + [Payout Proof #{%dul t.Index %}] {% if sweepsCount > 0 %} {% code outputSweeps := sweeps[t.Index] %} {% if len(outputSweeps) > 0 %} {% code sweep := outputSweeps[0] %} - {%= shorten(sweep.Id, 10) %} {%d sweep.MinerCount %} / {%d sweep.InputCount %} + {%= shorten(ctx, sweep.Id, 10) %} {%d sweep.MinerCount %} / {%d sweep.InputCount %} {% elseif (ctx.Pool.MainChain.Height - sideBlock.MainHeight + 1) < 60 %} Not unlocked {% else %} @@ -229,7 +230,7 @@

Included Transactions

{% endif %} diff --git a/cmd/web/views/tpl_row_miner.qtpl b/cmd/web/views/tpl_row_miner.qtpl index c37756b..7bc62ec 100644 --- a/cmd/web/views/tpl_row_miner.qtpl +++ b/cmd/web/views/tpl_row_miner.qtpl @@ -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">{%= shorten(alias, 10) %} + <{%s tag %} title="{%z= encodedMinerAddress %} ({%s alias %})" class="mono small">{%= shorten(ctx, alias, 10) %} {% else %} - <{%s tag %} title="{%z= encodedMinerAddress %}" class="mono small">{%= shorten(encodedMinerAddress, 10) %} + <{%s tag %} title="{%z= encodedMinerAddress %}" class="mono small">{%= shorten(ctx, encodedMinerAddress, 10) %} {% endif %} {% endfunc %} \ No newline at end of file diff --git a/cmd/web/views/tpl_shares.qtpl b/cmd/web/views/tpl_shares.qtpl index f87aa74..ec9a1b0 100644 --- a/cmd/web/views/tpl_shares.qtpl +++ b/cmd/web/views/tpl_shares.qtpl @@ -19,12 +19,12 @@ {% for i, s := range shares %} - {%dul s.SideHeight %} - {%= shorten(s.TemplateId, 10) %} + {%dul s.SideHeight %} + {%= shorten(ctx, s.TemplateId, 10) %} {% if s.MinedMainAtHeight %} - {%dul s.MainHeight %} + {%dul s.MainHeight %} {% else %} - {%dul s.MainHeight %} + {%dul s.MainHeight %} {% endif %} {%s date_diff_short(s.Timestamp) %} {% if efforts != nil %} @@ -37,7 +37,7 @@ {% endif %} {% endif %} {% if !isMiner %} - {%= TemplateRowMiner(s.MinerAddress, s.MinerAlias) %} + {%= TemplateRowMiner(ctx, s.MinerAddress, s.MinerAlias) %} {% endif %} {%= software_info(s.SoftwareId, s.SoftwareVersion) %} {%s si_units(side_block_weight(s, s.SideHeight, ctx.Consensus.ChainWindowSize, ctx.Consensus), 2) %} diff --git a/cmd/web/views/tpl_sweeps.qtpl b/cmd/web/views/tpl_sweeps.qtpl index 734dd35..298fd00 100644 --- a/cmd/web/views/tpl_sweeps.qtpl +++ b/cmd/web/views/tpl_sweeps.qtpl @@ -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 %} {% else %} @@ -19,15 +19,15 @@ - {% for _, s := range sweeps %} + {% for s := range sweeps %} - + {% if !isMiner %} {% code addr := s.Address.ToBase58() %} - + {% endif %} diff --git a/cmd/web/views/transaction-lookup.qtpl b/cmd/web/views/transaction-lookup.qtpl index 507cf6e..e5f9932 100644 --- a/cmd/web/views/transaction-lookup.qtpl +++ b/cmd/web/views/transaction-lookup.qtpl @@ -55,7 +55,7 @@ type TransactionLookupPage struct {


- +
@@ -75,7 +75,7 @@ type TransactionLookupPage struct {
Unknown Decoys Swept Coinbase Value
{%= shorten(s.Id, 10) %}{%= shorten(ctx, s.Id, 10) %} {%s date_diff_short(s.Timestamp) %}{%= shorten(addr, 10) %}{%= shorten(ctx, addr, 10) %}{%d s.InputDecoyCount %} {%d s.InputCount %} / {%d len(s.GlobalOutputIndices) %}
- + {% endif %} {% code out := p.Result.Outs[totalInputCount] %} - + @@ -142,19 +142,19 @@ type TransactionLookupPage struct { {% else %} - + {% endif %} {% code addr := o.Address.ToBase58() %} - + {% if o.Coinbase != nil %} - + {% elseif o.Sweep != nil %} -
-

Transaction Id: {%= hex(p.TransactionId) %}

+

Transaction Id: {%= hex(p.Context(), p.TransactionId) %}

{% code minerAddress := p.Miner.Address.ToBase58() %}

Miner Payout Address: {%z= minerAddress %}

Likely: {% if p.LikelyMiner %}Yes{% else %}Not likely{% endif %}

@@ -127,11 +127,11 @@ type TransactionLookupPage struct { {% else %}
{%d index %}{%= shorten(input.Input.KeyImage, 10) %}{%= shorten(p.Context(), input.Input.KeyImage, 10) %}-{%= shorten(out.TransactionId, 10) %}{%= shorten(p.Context(), out.TransactionId, 10) %} {%dul input.Input.KeyOffsets[oindex] %} - -
{%d index %}{%= shorten(input.Input.KeyImage, 10) %}{%= shorten(p.Context(), input.Input.KeyImage, 10) %}{%= shorten(addr, 10) %}{%= shorten(p.Context(), addr, 10) %}{%= shorten(o.Coinbase.Id, 10) %} #{%dul uint64(o.Coinbase.Index) %}{%= shorten(p.Context(), o.Coinbase.Id, 10) %} #{%dul uint64(o.Coinbase.Index) %} {%dul o.GlobalOutputIndex %} Coinbase {%s monero_to_xmr(o.Coinbase.Value) %} XMR{%= shorten(o.Sweep.Id, 10) %} + {%= shorten(p.Context(), o.Sweep.Id, 10) %} {% for oindex, goi := range o.Sweep.GlobalOutputIndices %} {% if goi == o.GlobalOutputIndex %} #{%d oindex %}/{%d len(o.Sweep.GlobalOutputIndices) %} diff --git a/cmd/web/web.go b/cmd/web/web.go index 8130168..8778d44 100644 --- a/cmd/web/web.go +++ b/cmd/web/web.go @@ -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,