2022-10-26 16:46:41 +00:00
package sidechain
import (
"encoding/json"
2023-03-05 14:06:49 +00:00
"errors"
2022-10-26 16:46:41 +00:00
"fmt"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero"
2022-11-07 22:59:52 +00:00
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
2022-10-26 16:46:41 +00:00
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"strconv"
)
type NetworkType int
const (
NetworkInvalid NetworkType = iota
NetworkMainnet
NetworkTestnet
NetworkStagenet
)
2022-11-03 11:32:07 +00:00
const (
PPLNSWindow = 2160
BlockTime = 10
UnclePenalty = 20
UncleBlockDepth = 3
)
type ConsensusProvider interface {
Consensus ( ) * Consensus
}
2022-10-26 16:46:41 +00:00
func ( n NetworkType ) String ( ) string {
switch n {
case NetworkInvalid :
return "invalid"
case NetworkMainnet :
return "mainnet"
case NetworkTestnet :
return "testnet"
case NetworkStagenet :
return "stagenet"
}
return ""
}
func ( n NetworkType ) MarshalJSON ( ) ( [ ] byte , error ) {
return json . Marshal ( n . String ( ) )
}
func ( n * NetworkType ) UnmarshalJSON ( b [ ] byte ) error {
var s string
if err := json . Unmarshal ( b , & s ) ; err != nil {
return err
}
switch s {
case "invalid" :
* n = NetworkInvalid
case "" , "mainnet" : //special case for config.json
* n = NetworkMainnet
case "testnet" :
* n = NetworkTestnet
case "stagenet" :
* n = NetworkStagenet
default :
return fmt . Errorf ( "unknown network type %s" , s )
}
return nil
}
type Consensus struct {
NetworkType NetworkType ` json:"network_type" `
PoolName string ` json:"name" `
PoolPassword string ` json:"password" `
TargetBlockTime uint64 ` json:"block_time" `
MinimumDifficulty uint64 ` json:"min_diff" `
ChainWindowSize uint64 ` json:"pplns_window" `
UnclePenalty uint64 ` json:"uncle_penalty" `
id types . Hash
}
const SmallestMinimumDifficulty = 100000
const LargestMinimumDifficulty = 1000000000
func NewConsensus ( networkType NetworkType , poolName , poolPassword string , targetBlockTime , minimumDifficulty , chainWindowSize , unclePenalty uint64 ) * Consensus {
c := & Consensus {
NetworkType : networkType ,
PoolName : poolName ,
PoolPassword : poolPassword ,
TargetBlockTime : targetBlockTime ,
MinimumDifficulty : minimumDifficulty ,
ChainWindowSize : chainWindowSize ,
UnclePenalty : unclePenalty ,
}
2023-03-05 14:06:49 +00:00
if ! c . verify ( ) {
2022-10-26 16:46:41 +00:00
return nil
}
2023-03-05 14:06:49 +00:00
return c
}
func NewConsensusFromJSON ( data [ ] byte ) ( * Consensus , error ) {
var c Consensus
if err := json . Unmarshal ( data , & c ) ; err != nil {
return nil , err
}
if ! c . verify ( ) {
return nil , errors . New ( "could not verify" )
}
return & c , nil
}
func ( c * Consensus ) verify ( ) bool {
if len ( c . PoolName ) > 128 {
return false
}
2022-10-26 16:46:41 +00:00
if len ( c . PoolPassword ) > 128 {
2023-03-05 14:06:49 +00:00
return false
2022-10-26 16:46:41 +00:00
}
if c . TargetBlockTime < 1 || c . TargetBlockTime > monero . BlockTime {
2023-03-05 14:06:49 +00:00
return false
2022-10-26 16:46:41 +00:00
}
2023-03-07 17:57:06 +00:00
if c . NetworkType == NetworkMainnet && c . MinimumDifficulty < SmallestMinimumDifficulty || c . MinimumDifficulty > LargestMinimumDifficulty {
2023-03-05 14:06:49 +00:00
return false
2022-10-26 16:46:41 +00:00
}
if c . ChainWindowSize < 60 || c . ChainWindowSize > 2160 {
2023-03-05 14:06:49 +00:00
return false
2022-10-26 16:46:41 +00:00
}
if c . UnclePenalty < 1 || c . UnclePenalty > 99 {
2023-03-05 14:06:49 +00:00
return false
2022-10-26 16:46:41 +00:00
}
var emptyHash types . Hash
c . id = c . CalculateId ( )
if c . id == emptyHash {
2023-03-05 14:06:49 +00:00
return false
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
return true
2022-10-26 16:46:41 +00:00
}
2023-03-07 17:57:06 +00:00
func ( c * Consensus ) CalculateSideTemplateId ( share * PoolBlock ) types . Hash {
2022-10-26 16:46:41 +00:00
2023-03-07 17:57:06 +00:00
mainData , _ := share . Main . SideChainHashingBlob ( )
sideData , _ := share . Side . MarshalBinary ( share . ShareVersion ( ) )
2022-10-26 16:46:41 +00:00
2023-03-05 14:06:49 +00:00
return c . CalculateSideChainIdFromBlobs ( mainData , sideData )
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) CalculateSideChainIdFromBlobs ( mainBlob , sideBlob [ ] byte ) types . Hash {
2023-03-07 17:57:06 +00:00
//TODO: handle extra nonce
2023-03-05 14:06:49 +00:00
return crypto . PooledKeccak256 ( mainBlob , sideBlob , c . id [ : ] )
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) Id ( ) types . Hash {
2022-10-26 16:46:41 +00:00
var h types . Hash
2023-03-05 14:06:49 +00:00
if c . id == h {
2022-10-26 16:46:41 +00:00
//this data race is fine
2023-03-05 14:06:49 +00:00
c . id = c . CalculateId ( )
return c . id
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
return c . id
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) IsDefault ( ) bool {
return c . id == ConsensusDefault . id
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) IsMini ( ) bool {
return c . id == ConsensusMini . id
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) DefaultPort ( ) uint16 {
if c . IsMini ( ) {
2022-11-03 11:32:07 +00:00
return 37888
}
return 37889
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) SeedNode ( ) string {
if c . IsMini ( ) {
2022-12-11 13:46:37 +00:00
return "seeds-mini.p2pool.io"
2023-03-05 14:06:49 +00:00
} else if c . IsDefault ( ) {
2022-12-11 13:46:37 +00:00
return "seeds.p2pool.io"
2022-12-04 14:00:05 +00:00
}
return ""
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) CalculateId ( ) types . Hash {
2022-10-26 16:46:41 +00:00
var buf [ ] byte
2023-03-05 14:06:49 +00:00
buf = append ( buf , c . NetworkType . String ( ) ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
2023-03-05 14:06:49 +00:00
buf = append ( buf , c . PoolName ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
2023-03-05 14:06:49 +00:00
buf = append ( buf , c . PoolPassword ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
2023-03-05 14:06:49 +00:00
buf = append ( buf , strconv . FormatUint ( c . TargetBlockTime , 10 ) ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
2023-03-05 14:06:49 +00:00
buf = append ( buf , strconv . FormatUint ( c . MinimumDifficulty , 10 ) ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
2023-03-05 14:06:49 +00:00
buf = append ( buf , strconv . FormatUint ( c . ChainWindowSize , 10 ) ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
2023-03-05 14:06:49 +00:00
buf = append ( buf , strconv . FormatUint ( c . UnclePenalty , 10 ) ... )
2022-10-26 16:46:41 +00:00
buf = append ( buf , 0 )
return randomx . ConsensusHash ( buf )
}
var ConsensusDefault = & Consensus { NetworkType : NetworkMainnet , PoolName : "mainnet test 2" , TargetBlockTime : 10 , MinimumDifficulty : 100000 , ChainWindowSize : 2160 , UnclePenalty : 20 , id : types . Hash { 34 , 175 , 126 , 231 , 181 , 11 , 104 , 146 , 227 , 153 , 218 , 107 , 44 , 108 , 68 , 39 , 178 , 81 , 4 , 212 , 169 , 4 , 142 , 0 , 177 , 110 , 157 , 240 , 68 , 7 , 249 , 24 } }
var ConsensusMini = & Consensus { NetworkType : NetworkMainnet , PoolName : "mini" , TargetBlockTime : 10 , MinimumDifficulty : 100000 , ChainWindowSize : 2160 , UnclePenalty : 20 , id : types . Hash { 57 , 130 , 201 , 26 , 149 , 174 , 199 , 250 , 66 , 80 , 189 , 18 , 108 , 216 , 194 , 220 , 136 , 23 , 63 , 24 , 64 , 113 , 221 , 44 , 219 , 86 , 39 , 163 , 53 , 24 , 126 , 196 } }