consensus/database/miner.go
2022-10-08 20:55:01 +02:00

94 lines
2.2 KiB
Go

package database
import (
"bytes"
"filippo.io/edwards25519"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/address"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/block"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"sync/atomic"
)
type Miner struct {
id uint64
addr string
moneroAddress atomic.Pointer[address.Address]
}
func (m *Miner) Id() uint64 {
return m.id
}
func (m *Miner) Address() string {
return m.addr
}
func (m *Miner) MoneroAddress() *address.Address {
if a := m.moneroAddress.Load(); a != nil {
return a
} else {
a = address.FromBase58(m.addr)
m.moneroAddress.Store(a)
return a
}
}
type addressSortType [types.HashSize * 2]byte
type outputResult struct {
Miner *Miner
Output *block.CoinbaseTransactionOutput
}
func MatchOutputs(c *block.CoinbaseTransaction, miners []*Miner, privateKey types.Hash) (result []outputResult) {
addresses := make(map[addressSortType]*Miner, len(miners))
outputs := c.Outputs
var k addressSortType
for _, m := range miners {
copy(k[:], m.MoneroAddress().SpendPub.Bytes())
copy(k[types.HashSize:], m.MoneroAddress().ViewPub.Bytes())
addresses[k] = m
}
sortedAddresses := maps.Keys(addresses)
slices.SortFunc(sortedAddresses, func(a addressSortType, b addressSortType) bool {
return bytes.Compare(a[:], b[:]) < 0
})
result = make([]outputResult, 0, len(miners))
for _, k = range sortedAddresses {
miner := addresses[k]
pK, _ := edwards25519.NewScalar().SetCanonicalBytes(privateKey[:])
derivation := miner.MoneroAddress().GetDerivationForPrivateKey(pK)
for i, o := range outputs {
if o == nil {
continue
}
sharedData := address.GetDerivationSharedDataForOutputIndex(derivation, uint64(o.Index))
if bytes.Compare(o.EphemeralPublicKey[:], miner.MoneroAddress().GetPublicKeyForSharedData(sharedData).Bytes()) == 0 {
//TODO: maybe clone?
result = append(result, outputResult{
Miner: miner,
Output: o,
})
outputs[i] = nil
outputs = slices.Compact(outputs)
break
}
}
}
slices.SortFunc(result, func(a outputResult, b outputResult) bool {
return a.Output.Index < b.Output.Index
})
return result
}