119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"git.gammaspectra.live/P2Pool/p2pool-observer/index"
|
|
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
|
|
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
|
"golang.org/x/exp/slices"
|
|
"net/url"
|
|
"nhooyr.io/websocket"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type channelEntry struct {
|
|
ApiEndpoint string
|
|
Channel string
|
|
Name string
|
|
PreviousBlocks foundBlocks
|
|
LastWindowMainDifficulty struct {
|
|
Height uint64
|
|
Difficulty uint64
|
|
}
|
|
PoolInfo map[string]any
|
|
Consensus *sidechain.Consensus
|
|
Tip *index.SideBlock
|
|
Window map[types.Hash]*index.SideBlock
|
|
ChainLock sync.RWMutex
|
|
|
|
Ws *websocket.Conn
|
|
}
|
|
|
|
func (c *channelEntry) DesiredPruneDistance() uint64 {
|
|
//prune after a whole day
|
|
/*pruneDistance := (3600 * 24) / c.Consensus.TargetBlockTime
|
|
if pruneDistance < c.Consensus.ChainWindowSize {
|
|
pruneDistance = c.Consensus.ChainWindowSize
|
|
}*/
|
|
|
|
return c.Consensus.ChainWindowSize
|
|
}
|
|
|
|
func (c *channelEntry) SideBlockUnclesByTemplateId(id types.Hash) chan *index.SideBlock {
|
|
result := make(chan *index.SideBlock)
|
|
go func() {
|
|
defer close(result)
|
|
if b := c.SideBlockByTemplateId(id); b != nil && !b.IsUncle() {
|
|
for _, u := range b.Uncles {
|
|
if uncle := c.SideBlockByTemplateId(u.TemplateId); uncle != nil {
|
|
result <- uncle
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
return result
|
|
}
|
|
|
|
func (c *channelEntry) SideBlockByTemplateId(id types.Hash) *index.SideBlock {
|
|
if b, ok := c.Window[id]; ok {
|
|
return b
|
|
} else if b = getTypeFromAPI[index.SideBlock](c.ApiEndpoint, "/api/block_by_id/"+id.String()); b != nil {
|
|
c.Window[b.TemplateId] = b
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *channelEntry) DifficultyFromHeight(height uint64) types.Difficulty {
|
|
if d := getTypeFromAPI[types.Difficulty](c.ApiEndpoint, fmt.Sprintf("/api/main_difficulty_by_height/%d", height)); d != nil {
|
|
return *d
|
|
}
|
|
return types.ZeroDifficulty
|
|
}
|
|
|
|
func (c *channelEntry) openWebSocket() {
|
|
if c.ApiEndpoint == "" {
|
|
c.Ws = nil
|
|
return
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
|
|
u, _ := url.Parse(c.ApiEndpoint)
|
|
if u.Scheme == "https" {
|
|
conn, _, err := websocket.Dial(ctx, fmt.Sprintf("wss://%s/api/events", u.Host), nil)
|
|
if err != nil {
|
|
c.Ws = nil
|
|
return
|
|
}
|
|
c.Ws = conn
|
|
} else {
|
|
conn, _, err := websocket.Dial(ctx, fmt.Sprintf("ws://%s/api/events", u.Host), nil)
|
|
if err != nil {
|
|
c.Ws = nil
|
|
return
|
|
}
|
|
c.Ws = conn
|
|
}
|
|
}
|
|
|
|
func (c *channelEntry) pruneBlocks() {
|
|
pruneDistance := c.DesiredPruneDistance()
|
|
|
|
inChainFromTip := make([]types.Hash, 0, pruneDistance*2)
|
|
|
|
for cur := c.Tip; cur != nil && (c.Tip.EffectiveHeight-cur.EffectiveHeight) <= pruneDistance; cur = c.Window[cur.ParentTemplateId] {
|
|
inChainFromTip = append(inChainFromTip, cur.TemplateId)
|
|
for _, u := range cur.Uncles {
|
|
inChainFromTip = append(inChainFromTip, u.TemplateId)
|
|
}
|
|
}
|
|
|
|
for k := range c.Window {
|
|
if !slices.Contains(inChainFromTip, k) {
|
|
delete(c.Window, k)
|
|
}
|
|
}
|
|
}
|