Check miner data on client block response and block broadcast
This commit is contained in:
parent
968b07ae0b
commit
d59a78c25d
|
@ -2,6 +2,7 @@ package mainchain
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
mainblock "git.gammaspectra.live/P2Pool/p2pool-observer/monero/block"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/client"
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/transaction"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
|
||||
p2pooltypes "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/types"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
|
||||
"golang.org/x/exp/slices"
|
||||
|
@ -31,7 +33,7 @@ type MainChain struct {
|
|||
mainchainByHash map[types.Hash]*sidechain.ChainMain
|
||||
|
||||
tip atomic.Pointer[sidechain.ChainMain]
|
||||
tipMinerData atomic.Pointer[MinerData]
|
||||
tipMinerData atomic.Pointer[p2pooltypes.MinerData]
|
||||
|
||||
medianTimestamp atomic.Uint64
|
||||
}
|
||||
|
@ -64,15 +66,94 @@ func (c *MainChain) Listen() error {
|
|||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-s.ErrC:
|
||||
return ctx.Err()
|
||||
case err := <-s.ErrC:
|
||||
//TODO: retry connection
|
||||
return err
|
||||
case fullChainMain := <-s.FullChainMainC:
|
||||
log.Print(fullChainMain)
|
||||
if len(fullChainMain.MinerTx.Inputs) < 1 {
|
||||
continue
|
||||
}
|
||||
d := &sidechain.ChainMain{
|
||||
Difficulty: types.ZeroDifficulty,
|
||||
Height: fullChainMain.MinerTx.Inputs[0].Gen.Height,
|
||||
Timestamp: uint64(fullChainMain.Timestamp),
|
||||
Reward: 0,
|
||||
Id: types.ZeroHash,
|
||||
}
|
||||
for _, o := range fullChainMain.MinerTx.Outputs {
|
||||
d.Reward += o.Amount
|
||||
}
|
||||
|
||||
outputs := make(transaction.Outputs, 0, len(fullChainMain.MinerTx.Outputs))
|
||||
var totalReward uint64
|
||||
for i, o := range fullChainMain.MinerTx.Outputs {
|
||||
if o.ToKey != nil {
|
||||
outputs = append(outputs, transaction.Output{
|
||||
Index: uint64(i),
|
||||
Reward: o.Amount,
|
||||
Type: transaction.TxOutToKey,
|
||||
EphemeralPublicKey: o.ToKey.Key,
|
||||
ViewTag: 0,
|
||||
})
|
||||
} else if o.ToTaggedKey != nil {
|
||||
tk, _ := hex.DecodeString(o.ToTaggedKey.ViewTag)
|
||||
outputs = append(outputs, transaction.Output{
|
||||
Index: uint64(i),
|
||||
Reward: o.Amount,
|
||||
Type: transaction.TxOutToTaggedKey,
|
||||
EphemeralPublicKey: o.ToTaggedKey.Key,
|
||||
ViewTag: tk[0],
|
||||
})
|
||||
} else {
|
||||
//error
|
||||
break
|
||||
}
|
||||
totalReward += o.Amount
|
||||
}
|
||||
|
||||
if len(outputs) != len(fullChainMain.MinerTx.Outputs) {
|
||||
continue
|
||||
}
|
||||
|
||||
extraDataRaw, _ := hex.DecodeString(fullChainMain.MinerTx.Extra)
|
||||
extraTags := transaction.ExtraTags{}
|
||||
if err = extraTags.UnmarshalBinary(extraDataRaw); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
blockData := &mainblock.Block{
|
||||
MajorVersion: uint8(fullChainMain.MajorVersion),
|
||||
MinorVersion: uint8(fullChainMain.MinorVersion),
|
||||
Timestamp: uint64(fullChainMain.Timestamp),
|
||||
PreviousId: fullChainMain.PrevID,
|
||||
Nonce: uint32(fullChainMain.Nonce),
|
||||
Coinbase: &transaction.CoinbaseTransaction{
|
||||
Version: uint8(fullChainMain.MinerTx.Version),
|
||||
UnlockTime: uint64(fullChainMain.MinerTx.UnlockTime),
|
||||
InputCount: uint8(len(fullChainMain.MinerTx.Inputs)),
|
||||
InputType: transaction.TxInGen,
|
||||
GenHeight: fullChainMain.MinerTx.Inputs[0].Gen.Height,
|
||||
Outputs: outputs,
|
||||
OutputsBlobSize: 0,
|
||||
TotalReward: totalReward,
|
||||
Extra: extraTags,
|
||||
ExtraBaseRCT: 0,
|
||||
},
|
||||
Transactions: fullChainMain.TxHashes,
|
||||
TransactionParentIndices: nil,
|
||||
}
|
||||
c.HandleMainBlock(blockData)
|
||||
case fullMinerData := <-s.FullMinerDataC:
|
||||
log.Print(fullMinerData)
|
||||
c.HandleMinerData(&p2pooltypes.MinerData{
|
||||
MajorVersion: fullMinerData.MajorVersion,
|
||||
Height: fullMinerData.Height,
|
||||
PrevId: fullMinerData.PrevId,
|
||||
SeedHash: fullMinerData.SeedHash,
|
||||
Difficulty: fullMinerData.Difficulty,
|
||||
MedianWeight: fullMinerData.MedianWeight,
|
||||
AlreadyGeneratedCoins: fullMinerData.AlreadyGeneratedCoins,
|
||||
MedianTimestamp: fullMinerData.MedianTimestamp,
|
||||
TimeReceived: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -249,6 +330,10 @@ func (c *MainChain) GetChainMainTip() *sidechain.ChainMain {
|
|||
return c.tip.Load()
|
||||
}
|
||||
|
||||
func (c *MainChain) GetMinerDataTip() *p2pooltypes.MinerData {
|
||||
return c.tipMinerData.Load()
|
||||
}
|
||||
|
||||
func (c *MainChain) updateTip() {
|
||||
if minerData := c.tipMinerData.Load(); minerData != nil {
|
||||
if d := c.GetChainMainByHash(minerData.PrevId); d != nil {
|
||||
|
@ -336,7 +421,7 @@ func (c *MainChain) DownloadBlockHeaders(currentHeight uint64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *MainChain) HandleMinerData(minerData *MinerData) {
|
||||
func (c *MainChain) HandleMinerData(minerData *p2pooltypes.MinerData) {
|
||||
var missingHeights []uint64
|
||||
func() {
|
||||
c.lock.Lock()
|
||||
|
@ -364,10 +449,6 @@ func (c *MainChain) HandleMinerData(minerData *MinerData) {
|
|||
} else {
|
||||
existingPrevMainData.Id = prevMainData.Id
|
||||
|
||||
// timestamp and reward is unknown here
|
||||
existingPrevMainData.Timestamp = 0
|
||||
existingPrevMainData.Reward = 0
|
||||
|
||||
prevMainData = existingPrevMainData
|
||||
}
|
||||
|
||||
|
@ -429,16 +510,3 @@ func (c *MainChain) getBlockHeader(height uint64) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
type MinerData struct {
|
||||
MajorVersion uint8
|
||||
Height uint64
|
||||
PrevId types.Hash
|
||||
SeedHash types.Hash
|
||||
Difficulty types.Difficulty
|
||||
MedianWeight uint64
|
||||
AlreadyGeneratedCoins uint64
|
||||
MedianTimestamp uint64
|
||||
//TxBacklog any
|
||||
TimeReceived time.Time
|
||||
}
|
||||
|
|
|
@ -394,14 +394,22 @@ func (c *Client) OnConnection() {
|
|||
isChainTipBlockRequest := false
|
||||
if c.chainTipBlockRequest.Swap(false) {
|
||||
isChainTipBlockRequest = true
|
||||
//peerHeight := block.Main.Coinbase.GenHeight
|
||||
//ourHeight :=
|
||||
if expectedBlockId == types.ZeroHash {
|
||||
peerHeight := block.Main.Coinbase.GenHeight
|
||||
ourHeight := c.Owner.MainChain().GetMinerDataTip().Height
|
||||
|
||||
if (peerHeight + 2) < ourHeight {
|
||||
c.Ban(DefaultBanTime, fmt.Errorf("mining on top of a stale block (mainchain peer height %d, expected >= %d)", peerHeight, ourHeight))
|
||||
return
|
||||
}
|
||||
}
|
||||
//TODO: stale block
|
||||
|
||||
log.Printf("[P2PClient] Peer %s tip is at id = %s, height = %d, main height = %d", c.AddressPort.String(), types.HashFromBytes(block.CoinbaseExtra(sidechain.SideTemplateId)), block.Side.Height, block.Main.Coinbase.GenHeight)
|
||||
|
||||
if expectedBlockId != types.ZeroHash {
|
||||
c.Ban(DefaultBanTime, fmt.Errorf("expected block id = %s, got %s", expectedBlockId, types.ZeroHash.String()))
|
||||
return
|
||||
}
|
||||
|
||||
c.SendPeerListRequest()
|
||||
|
@ -469,7 +477,32 @@ func (c *Client) OnConnection() {
|
|||
//TODO: ban here, but sort blocks properly, maybe a queue to re-try?
|
||||
return
|
||||
} else {
|
||||
//TODO: investigate different monero block mining
|
||||
ourMinerData := c.Owner.MainChain().GetMinerDataTip()
|
||||
|
||||
if block.Main.PreviousId != ourMinerData.PrevId {
|
||||
// This peer is mining on top of a different Monero block, investigate it
|
||||
|
||||
peerHeight := block.Main.Coinbase.GenHeight
|
||||
ourHeight := ourMinerData.Height
|
||||
|
||||
if peerHeight < ourHeight {
|
||||
if (ourHeight - peerHeight) < 5 {
|
||||
elapsedTime := time.Now().Sub(ourMinerData.TimeReceived)
|
||||
if (ourHeight-peerHeight) > 1 || elapsedTime > (time.Second*10) {
|
||||
log.Printf("[P2PClient] Peer %s broadcasted a stale block (%d ms late, mainchain height %d, expected >= %d), ignoring it", c.AddressPort.String(), elapsedTime.Milliseconds(), peerHeight, ourHeight)
|
||||
}
|
||||
} else {
|
||||
c.Ban(DefaultBanTime, fmt.Errorf("broadcasted an unreasonably stale block (mainchain height %d, expected >= %d)", peerHeight, ourHeight))
|
||||
return
|
||||
}
|
||||
} else if peerHeight > ourHeight {
|
||||
if peerHeight >= (ourHeight + 2) {
|
||||
log.Printf("[P2PClient] Peer %s is ahead on mainchain (mainchain height %d, your height %d). Is monerod stuck or lagging?", c.AddressPort.String(), peerHeight, ourHeight)
|
||||
}
|
||||
} else {
|
||||
log.Printf("[P2PClient] Peer %s is mining on an alternative mainchain tip (mainchain height %d, previous_id = %s)", c.AddressPort.String(), peerHeight, block.Main.PreviousId)
|
||||
}
|
||||
}
|
||||
|
||||
block.WantBroadcast.Store(true)
|
||||
if missingBlocks, err = c.Owner.SideChain().AddPoolBlockExternal(block); err != nil {
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/mainchain"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
|
||||
p2pooltypes "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/types"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
|
||||
"golang.org/x/exp/slices"
|
||||
"log"
|
||||
|
@ -18,8 +20,16 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
type P2PoolInterface interface {
|
||||
sidechain.ConsensusProvider
|
||||
SideChain() *sidechain.SideChain
|
||||
MainChain() *mainchain.MainChain
|
||||
GetChainMainTip() *sidechain.ChainMain
|
||||
GetMinerDataTip() *p2pooltypes.MinerData
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
sidechain *sidechain.SideChain
|
||||
p2pool P2PoolInterface
|
||||
|
||||
peerId uint64
|
||||
versionInformation PeerVersionInformation
|
||||
|
@ -47,7 +57,7 @@ type Server struct {
|
|||
ctx context.Context
|
||||
}
|
||||
|
||||
func NewServer(sidechain *sidechain.SideChain, listenAddress string, externalListenPort uint16, maxOutgoingPeers, maxIncomingPeers uint32, ctx context.Context) (*Server, error) {
|
||||
func NewServer(p2pool P2PoolInterface, listenAddress string, externalListenPort uint16, maxOutgoingPeers, maxIncomingPeers uint32, ctx context.Context) (*Server, error) {
|
||||
peerId := make([]byte, int(unsafe.Sizeof(uint64(0))))
|
||||
_, err := rand.Read(peerId)
|
||||
if err != nil {
|
||||
|
@ -60,7 +70,7 @@ func NewServer(sidechain *sidechain.SideChain, listenAddress string, externalLis
|
|||
}
|
||||
|
||||
s := &Server{
|
||||
sidechain: sidechain,
|
||||
p2pool: p2pool,
|
||||
listenAddress: addrPort,
|
||||
externalListenPort: externalListenPort,
|
||||
peerId: binary.LittleEndian.Uint64(peerId),
|
||||
|
@ -316,7 +326,11 @@ func (s *Server) PeerId() uint64 {
|
|||
}
|
||||
|
||||
func (s *Server) SideChain() *sidechain.SideChain {
|
||||
return s.sidechain
|
||||
return s.p2pool.SideChain()
|
||||
}
|
||||
|
||||
func (s *Server) MainChain() *mainchain.MainChain {
|
||||
return s.p2pool.MainChain()
|
||||
}
|
||||
|
||||
func (s *Server) updateClients() {
|
||||
|
@ -384,5 +398,5 @@ func (s *Server) Broadcast(block *sidechain.PoolBlock) {
|
|||
}
|
||||
|
||||
func (s *Server) Consensus() *sidechain.Consensus {
|
||||
return s.sidechain.Consensus()
|
||||
return s.p2pool.Consensus()
|
||||
}
|
||||
|
|
144
p2pool/p2pool.go
144
p2pool/p2pool.go
|
@ -3,7 +3,6 @@ package p2pool
|
|||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/block"
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/mainchain"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/p2p"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
|
||||
p2pooltypes "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/types"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
"log"
|
||||
"strconv"
|
||||
|
@ -95,7 +95,7 @@ func NewP2Pool(consensus *sidechain.Consensus, settings map[string]string) (*P2P
|
|||
externalListenPort, _ = strconv.ParseUint(externalPort, 10, 0)
|
||||
}
|
||||
|
||||
if pool.server, err = p2p.NewServer(pool.sidechain, listenAddress, uint16(externalListenPort), uint32(maxOutgoingPeers), uint32(maxIncomingPeers), pool.ctx); err != nil {
|
||||
if pool.server, err = p2p.NewServer(pool, listenAddress, uint16(externalListenPort), uint32(maxOutgoingPeers), uint32(maxIncomingPeers), pool.ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -114,8 +114,13 @@ func (p *P2Pool) GetChainMainTip() *sidechain.ChainMain {
|
|||
return p.mainchain.GetChainMainTip()
|
||||
}
|
||||
|
||||
func (p *P2Pool) GetMinerDataTip() *p2pooltypes.MinerData {
|
||||
return p.mainchain.GetMinerDataTip()
|
||||
}
|
||||
|
||||
// GetMinimalBlockHeaderByHeight Only Id / Height / Timestamp are assured
|
||||
func (p *P2Pool) GetMinimalBlockHeaderByHeight(height uint64) *block.Header {
|
||||
lowerThanTip := height <= p.mainchain.GetChainMainTip().Height
|
||||
if chainMain := p.mainchain.GetChainMainByHeight(height); chainMain != nil && chainMain.Id != types.ZeroHash {
|
||||
return &block.Header{
|
||||
Timestamp: chainMain.Timestamp,
|
||||
|
@ -124,7 +129,7 @@ func (p *P2Pool) GetMinimalBlockHeaderByHeight(height uint64) *block.Header {
|
|||
Difficulty: chainMain.Difficulty,
|
||||
Id: chainMain.Id,
|
||||
}
|
||||
} else {
|
||||
} else if lowerThanTip {
|
||||
if header, err := p.ClientRPC().GetBlockHeaderByHeight(height, p.ctx); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
|
@ -146,11 +151,14 @@ func (p *P2Pool) GetMinimalBlockHeaderByHeight(height uint64) *block.Header {
|
|||
return blockHeader
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (p *P2Pool) GetDifficultyByHeight(height uint64) types.Difficulty {
|
||||
lowerThanTip := height <= p.mainchain.GetChainMainTip().Height
|
||||
if chainMain := p.mainchain.GetChainMainByHeight(height); chainMain != nil && chainMain.Difficulty != types.ZeroDifficulty {
|
||||
return chainMain.Difficulty
|
||||
} else {
|
||||
} else if lowerThanTip {
|
||||
//TODO cache
|
||||
if header, err := p.ClientRPC().GetBlockHeaderByHeight(height, p.ctx); err != nil {
|
||||
return types.ZeroDifficulty
|
||||
|
@ -173,6 +181,8 @@ func (p *P2Pool) GetDifficultyByHeight(height uint64) types.Difficulty {
|
|||
return blockHeader.Difficulty
|
||||
}
|
||||
}
|
||||
|
||||
return types.ZeroDifficulty
|
||||
}
|
||||
|
||||
// GetMinimalBlockHeaderByHash Only Id / Height / Timestamp are assured
|
||||
|
@ -221,6 +231,14 @@ func (p *P2Pool) Context() context.Context {
|
|||
return p.ctx
|
||||
}
|
||||
|
||||
func (p *P2Pool) SideChain() *sidechain.SideChain {
|
||||
return p.sidechain
|
||||
}
|
||||
|
||||
func (p *P2Pool) MainChain() *mainchain.MainChain {
|
||||
return p.mainchain
|
||||
}
|
||||
|
||||
func (p *P2Pool) Server() *p2p.Server {
|
||||
return p.server
|
||||
}
|
||||
|
@ -241,106 +259,11 @@ func (p *P2Pool) Run() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
if zmqStream, err := p.ClientZMQ().Listen(p.ctx); err != nil {
|
||||
return err
|
||||
} else {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-zmqStream.ErrC:
|
||||
p.Close()
|
||||
return
|
||||
case fullChainMain := <-zmqStream.FullChainMainC:
|
||||
if len(fullChainMain.MinerTx.Inputs) < 1 {
|
||||
continue
|
||||
}
|
||||
d := &sidechain.ChainMain{
|
||||
Difficulty: types.ZeroDifficulty,
|
||||
Height: fullChainMain.MinerTx.Inputs[0].Gen.Height,
|
||||
Timestamp: uint64(fullChainMain.Timestamp),
|
||||
Reward: 0,
|
||||
Id: types.ZeroHash,
|
||||
}
|
||||
for _, o := range fullChainMain.MinerTx.Outputs {
|
||||
d.Reward += o.Amount
|
||||
}
|
||||
|
||||
outputs := make(transaction.Outputs, 0, len(fullChainMain.MinerTx.Outputs))
|
||||
var totalReward uint64
|
||||
for i, o := range fullChainMain.MinerTx.Outputs {
|
||||
if o.ToKey != nil {
|
||||
outputs = append(outputs, transaction.Output{
|
||||
Index: uint64(i),
|
||||
Reward: o.Amount,
|
||||
Type: transaction.TxOutToKey,
|
||||
EphemeralPublicKey: o.ToKey.Key,
|
||||
ViewTag: 0,
|
||||
})
|
||||
} else if o.ToTaggedKey != nil {
|
||||
tk, _ := hex.DecodeString(o.ToTaggedKey.ViewTag)
|
||||
outputs = append(outputs, transaction.Output{
|
||||
Index: uint64(i),
|
||||
Reward: o.Amount,
|
||||
Type: transaction.TxOutToTaggedKey,
|
||||
EphemeralPublicKey: o.ToTaggedKey.Key,
|
||||
ViewTag: tk[0],
|
||||
})
|
||||
} else {
|
||||
//error
|
||||
break
|
||||
}
|
||||
totalReward += o.Amount
|
||||
}
|
||||
|
||||
if len(outputs) != len(fullChainMain.MinerTx.Outputs) {
|
||||
continue
|
||||
}
|
||||
|
||||
extraDataRaw, _ := hex.DecodeString(fullChainMain.MinerTx.Extra)
|
||||
extraTags := transaction.ExtraTags{}
|
||||
if err = extraTags.UnmarshalBinary(extraDataRaw); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
blockData := &block.Block{
|
||||
MajorVersion: uint8(fullChainMain.MajorVersion),
|
||||
MinorVersion: uint8(fullChainMain.MinorVersion),
|
||||
Timestamp: uint64(fullChainMain.Timestamp),
|
||||
PreviousId: fullChainMain.PrevID,
|
||||
Nonce: uint32(fullChainMain.Nonce),
|
||||
Coinbase: &transaction.CoinbaseTransaction{
|
||||
Version: uint8(fullChainMain.MinerTx.Version),
|
||||
UnlockTime: uint64(fullChainMain.MinerTx.UnlockTime),
|
||||
InputCount: uint8(len(fullChainMain.MinerTx.Inputs)),
|
||||
InputType: transaction.TxInGen,
|
||||
GenHeight: fullChainMain.MinerTx.Inputs[0].Gen.Height,
|
||||
Outputs: outputs,
|
||||
OutputsBlobSize: 0,
|
||||
TotalReward: totalReward,
|
||||
Extra: extraTags,
|
||||
ExtraBaseRCT: 0,
|
||||
},
|
||||
Transactions: fullChainMain.TxHashes,
|
||||
TransactionParentIndices: nil,
|
||||
}
|
||||
p.mainchain.HandleMainBlock(blockData)
|
||||
case fullMinerData := <-zmqStream.FullMinerDataC:
|
||||
p.mainchain.HandleMinerData(&mainchain.MinerData{
|
||||
MajorVersion: fullMinerData.MajorVersion,
|
||||
Height: fullMinerData.Height,
|
||||
PrevId: fullMinerData.PrevId,
|
||||
SeedHash: fullMinerData.SeedHash,
|
||||
Difficulty: fullMinerData.Difficulty,
|
||||
MedianWeight: fullMinerData.MedianWeight,
|
||||
AlreadyGeneratedCoins: fullMinerData.AlreadyGeneratedCoins,
|
||||
MedianTimestamp: fullMinerData.MedianTimestamp,
|
||||
TimeReceived: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
go func() {
|
||||
if p.mainchain.Listen() != nil {
|
||||
p.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
p.started.Store(true)
|
||||
|
||||
|
@ -405,7 +328,7 @@ func (p *P2Pool) getMinerData() error {
|
|||
prevId, _ := types.HashFromString(minerData.PrevId)
|
||||
seedHash, _ := types.HashFromString(minerData.SeedHash)
|
||||
diff, _ := types.DifficultyFromString(minerData.Difficulty)
|
||||
p.mainchain.HandleMinerData(&mainchain.MinerData{
|
||||
p.mainchain.HandleMinerData(&p2pooltypes.MinerData{
|
||||
MajorVersion: minerData.MajorVersion,
|
||||
Height: minerData.Height,
|
||||
PrevId: prevId,
|
||||
|
@ -463,5 +386,16 @@ func (p *P2Pool) Started() bool {
|
|||
}
|
||||
|
||||
func (p *P2Pool) Broadcast(block *sidechain.PoolBlock) {
|
||||
minerData := p.GetMinerDataTip()
|
||||
if (block.Main.Coinbase.GenHeight)+2 < minerData.Height {
|
||||
log.Printf("[P2Pool] Trying to broadcast a stale block %s (mainchain height %d, current height is %d)", block.SideTemplateId(p.consensus), block.Main.Coinbase.GenHeight, minerData.Height)
|
||||
return
|
||||
}
|
||||
|
||||
if block.Main.Coinbase.GenHeight > (minerData.Height + 2) {
|
||||
log.Printf("[P2Pool] Trying to broadcast a block %s ahead on mainchain (mainchain height %d, current height is %d)", block.SideTemplateId(p.consensus), block.Main.Coinbase.GenHeight, minerData.Height)
|
||||
return
|
||||
}
|
||||
|
||||
p.server.Broadcast(block)
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ import (
|
|||
const BlockSaveEpochSize = 32
|
||||
|
||||
const (
|
||||
BlockSaveOptionTemplate = 1 << 0
|
||||
//BlockSaveOptionDeterministicPrivateKey = 1 << 1
|
||||
BlockSaveOptionDeterministicBlobs = 1 << 2
|
||||
BlockSaveOptionUncles = 1 << 3
|
||||
BlockSaveOptionTemplate = 1 << 0
|
||||
BlockSaveOptionDeterministicPrivateKeySeed = 1 << 1
|
||||
BlockSaveOptionDeterministicBlobs = 1 << 2
|
||||
BlockSaveOptionUncles = 1 << 3
|
||||
|
||||
BlockSaveFieldSizeInBits = 8
|
||||
|
||||
|
@ -60,9 +60,6 @@ func (c *SideChain) saveBlock(block *PoolBlock) {
|
|||
c.sidechainLock.RLock()
|
||||
defer c.sidechainLock.RUnlock()
|
||||
|
||||
//only store keys when not deterministic
|
||||
//isDeterministicPrivateKey := c.isPoolBlockTransactionKeyIsDeterministic(block)
|
||||
|
||||
calculatedOutputs := c.calculateOutputs(block)
|
||||
calcBlob, _ := calculatedOutputs.MarshalBinary()
|
||||
blockBlob, _ := block.Main.Coinbase.Outputs.MarshalBinary()
|
||||
|
@ -76,13 +73,26 @@ func (c *SideChain) saveBlock(block *PoolBlock) {
|
|||
|
||||
parent := c.getParent(block)
|
||||
|
||||
//only store keys when not deterministic
|
||||
isDeterministicPrivateKeySeed := parent != nil && c.isPoolBlockTransactionKeyIsDeterministic(block)
|
||||
|
||||
if isDeterministicPrivateKeySeed && block.ShareVersion() > ShareVersion_V1 {
|
||||
expectedSeed := parent.Side.CoinbasePrivateKeySeed
|
||||
if parent.Main.PreviousId != block.Main.PreviousId {
|
||||
expectedSeed = parent.CalculateTransactionPrivateKeySeed()
|
||||
}
|
||||
if block.Side.CoinbasePrivateKeySeed != expectedSeed {
|
||||
isDeterministicPrivateKeySeed = false
|
||||
}
|
||||
}
|
||||
|
||||
blob := make([]byte, 0, 4096*2)
|
||||
|
||||
var blockFlags uint64
|
||||
|
||||
/*if isDeterministicPrivateKey {
|
||||
blockFlags |= BlockSaveOptionDeterministicPrivateKey
|
||||
}*/
|
||||
if isDeterministicPrivateKeySeed {
|
||||
blockFlags |= BlockSaveOptionDeterministicPrivateKeySeed
|
||||
}
|
||||
|
||||
if !storeBlob {
|
||||
blockFlags |= BlockSaveOptionDeterministicBlobs
|
||||
|
@ -163,8 +173,8 @@ func (c *SideChain) saveBlock(block *PoolBlock) {
|
|||
blob = binary.AppendUvarint(blob, minerAddressOffset)
|
||||
}
|
||||
|
||||
// private key, if needed
|
||||
if true /*(blockFlags & BlockSaveOptionDeterministicPrivateKey) == 0*/ {
|
||||
// private key seed, if needed
|
||||
if (blockFlags&BlockSaveOptionDeterministicPrivateKeySeed) == 0 || (block.ShareVersion() > ShareVersion_V1 && (blockFlags&BlockSaveOptionTemplate) != 0) {
|
||||
blob = append(blob, block.Side.CoinbasePrivateKeySeed[:]...)
|
||||
//public may be needed on invalid - TODO check
|
||||
//blob = append(blob, block.CoinbaseExtra(SideCoinbasePublicKey)...)
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/transaction"
|
||||
p2pooltypes "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/types"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
|
||||
"golang.org/x/exp/slices"
|
||||
|
@ -42,6 +43,7 @@ type P2PoolInterface interface {
|
|||
UpdateBlockFound(data *ChainMain, block *PoolBlock)
|
||||
SubmitBlock(block *mainblock.Block)
|
||||
GetChainMainTip() *ChainMain
|
||||
GetMinerDataTip() *p2pooltypes.MinerData
|
||||
}
|
||||
|
||||
type ChainMain struct {
|
||||
|
|
19
p2pool/types/minerdata.go
Normal file
19
p2pool/types/minerdata.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MinerData struct {
|
||||
MajorVersion uint8
|
||||
Height uint64
|
||||
PrevId types.Hash
|
||||
SeedHash types.Hash
|
||||
Difficulty types.Difficulty
|
||||
MedianWeight uint64
|
||||
AlreadyGeneratedCoins uint64
|
||||
MedianTimestamp uint64
|
||||
//TxBacklog any
|
||||
TimeReceived time.Time
|
||||
}
|
Loading…
Reference in a new issue