package main import ( "bytes" "git.gammaspectra.live/P2Pool/p2pool-observer/database" "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool" "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/api" "git.gammaspectra.live/P2Pool/p2pool-observer/types" "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) // MapJSONBlock fills special values for any block func MapJSONBlock(api *api.Api, block database.BlockInterface, extraUncleData, extraCoinbaseData bool) { b := block.GetBlock() b.Lock.Lock() defer b.Lock.Unlock() if extraCoinbaseData { var tx *database.CoinbaseTransaction if b.Main.Found { tx = api.GetDatabase().GetCoinbaseTransaction(b) } if b.Main.Found && tx != nil { b.Coinbase.Payouts = make([]*database.JSONCoinbaseOutput, 0, len(tx.Outputs())) for _, output := range tx.Outputs() { b.Coinbase.Payouts = append(b.Coinbase.Payouts, &database.JSONCoinbaseOutput{ Amount: output.Amount(), Index: output.Index(), Address: api.GetDatabase().GetMiner(output.Miner()).Address(), }) } } else { payoutHint := api.GetBlockWindowPayouts(b) addresses := make(map[[32]byte]*database.JSONCoinbaseOutput, len(payoutHint)) var k [32]byte for minerId, amount := range payoutHint { miner := api.GetDatabase().GetMiner(minerId) copy(k[:], miner.MoneroAddress().SpendPub.Bytes()) copy(k[types.HashSize:], miner.MoneroAddress().ViewPub.Bytes()) addresses[k] = &database.JSONCoinbaseOutput{ Address: miner.Address(), Amount: amount.Lo, } } sortedAddresses := maps.Keys(addresses) slices.SortFunc(sortedAddresses, func(a [32]byte, b [32]byte) bool { return bytes.Compare(a[:], b[:]) < 0 }) b.Coinbase.Payouts = make([]*database.JSONCoinbaseOutput, len(sortedAddresses)) for i, key := range sortedAddresses { addresses[key].Index = uint64(i) b.Coinbase.Payouts[i] = addresses[key] } } } weight := b.Difficulty if uncle, ok := block.(*database.UncleBlock); ok { b.Parent = &database.JSONBlockParent{ Id: uncle.ParentId, Height: uncle.ParentHeight, } weight.Uint128 = weight.Mul64(100 - p2pool.UnclePenalty).Div64(100) } else { for u := range api.GetDatabase().GetUnclesByParentId(b.Id) { uncleWeight := u.Block.Difficulty.Mul64(p2pool.UnclePenalty).Div64(100) weight.Uint128 = weight.Add(uncleWeight) if !extraUncleData { b.Uncles = append(b.Uncles, &database.JSONUncleBlockSimple{ Id: u.Block.Id, Height: u.Block.Height, Weight: uncleWeight.Lo, }) } else { b.Uncles = append(b.Uncles, &database.JSONUncleBlockExtra{ Id: u.Block.Id, Height: u.Block.Height, Difficulty: u.Block.Difficulty, Timestamp: u.Block.Timestamp, Miner: api.GetDatabase().GetMiner(u.Block.MinerId).Address(), PowHash: u.Block.PowHash, Weight: uncleWeight.Lo, }) } } } b.Weight = weight.Lo if b.IsProofHigherThanDifficulty() && !b.Main.Found { b.Main.Orphan = true } b.Address = api.GetDatabase().GetMiner(b.MinerId).Address() }