2022-10-26 16:46:41 +00:00
package sidechain
import (
2023-03-05 14:06:49 +00:00
"errors"
2022-10-26 16:46:41 +00:00
"fmt"
2023-05-16 05:14:58 +00:00
"git.gammaspectra.live/P2Pool/moneroutil"
2022-10-26 16:46:41 +00:00
"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"
2023-05-27 12:43:22 +00:00
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
2022-10-26 16:46:41 +00:00
"strconv"
)
type NetworkType int
const (
NetworkInvalid NetworkType = iota
NetworkMainnet
NetworkTestnet
NetworkStagenet
)
2022-11-03 11:32:07 +00:00
const (
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 ""
}
2023-05-16 05:14:58 +00:00
func ( n NetworkType ) AddressNetwork ( ) ( uint8 , error ) {
switch n {
case NetworkInvalid :
return 0 , errors . New ( "invalid network" )
case NetworkMainnet :
return moneroutil . MainNetwork , nil
case NetworkTestnet :
return moneroutil . TestNetwork , nil
case NetworkStagenet :
2023-05-17 10:17:38 +00:00
return moneroutil . StageNetwork , nil
2023-05-16 05:14:58 +00:00
}
return 0 , errors . New ( "unknown network" )
}
2022-10-26 16:46:41 +00:00
func ( n NetworkType ) MarshalJSON ( ) ( [ ] byte , error ) {
2023-07-22 14:02:00 +00:00
return [ ] byte ( "\"" + n . String ( ) + "\"" ) , nil
2022-10-26 16:46:41 +00:00
}
func ( n * NetworkType ) UnmarshalJSON ( b [ ] byte ) error {
var s string
2023-05-27 12:43:22 +00:00
if err := utils . UnmarshalJSON ( b , & s ) ; err != nil {
2022-10-26 16:46:41 +00:00
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" `
2023-07-25 05:59:41 +00:00
2023-04-16 17:25:24 +00:00
// HardFork optional hardfork information for p2pool
2023-07-25 05:59:41 +00:00
// If empty it will be filled with the default hardfork list to the corresponding NetworkType
2023-04-16 17:25:24 +00:00
HardForks [ ] HardFork ` json:"hard_forks,omitempty" `
2022-10-26 16:46:41 +00:00
2023-04-30 19:49:25 +00:00
hasher randomx . Hasher
2023-07-25 07:05:38 +00:00
Id types . Hash ` json:"id" `
2022-10-26 16:46:41 +00:00
}
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
2023-05-27 12:43:22 +00:00
if err := utils . UnmarshalJSON ( data , & c ) ; err != nil {
2023-03-05 14:06:49 +00:00
return nil , err
}
if ! c . verify ( ) {
return nil , errors . New ( "could not verify" )
}
return & c , nil
}
func ( c * Consensus ) verify ( ) bool {
2023-05-29 08:23:30 +00:00
if c . PoolName == "default" {
//p2pool changed consensus config to use default instead of original value
c . PoolName = ConsensusDefault . PoolName
}
2023-03-05 14:06:49 +00:00
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
2023-06-05 21:41:32 +00:00
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
2023-04-16 17:25:24 +00:00
if len ( c . HardForks ) == 0 {
switch c . NetworkType {
case NetworkMainnet :
c . HardForks = p2poolMainNetHardForks
case NetworkTestnet :
c . HardForks = p2poolTestNetHardForks
case NetworkStagenet :
c . HardForks = p2poolStageNetHardForks
default :
2024-02-26 18:45:13 +00:00
utils . Panicf ( "invalid network type for determining hardfork" )
2023-04-16 17:25:24 +00:00
}
}
2023-03-05 14:06:49 +00:00
return true
2022-10-26 16:46:41 +00:00
}
2023-06-03 09:29:20 +00:00
func ( c * Consensus ) CalculateSideTemplateId ( share * PoolBlock ) ( result types . Hash ) {
2023-06-27 09:36:00 +00:00
return c . CalculateSideTemplateIdPreAllocated ( share , make ( [ ] byte , 0 , max ( share . Main . BufferLength ( ) , share . Side . BufferLength ( ) ) ) )
2023-06-03 09:29:20 +00:00
}
func ( c * Consensus ) CalculateSideTemplateIdPreAllocated ( share * PoolBlock , buf [ ] byte ) ( result types . Hash ) {
h := crypto . GetKeccak256Hasher ( )
defer crypto . PutKeccak256Hasher ( h )
2023-05-18 03:14:03 +00:00
buf , _ = share . Main . SideChainHashingBlob ( buf , true )
2023-06-03 09:29:20 +00:00
_ , _ = h . Write ( buf )
buf , _ = share . Side . AppendBinary ( buf [ : 0 ] , share . ShareVersion ( ) )
_ , _ = h . Write ( buf )
2022-10-26 16:46:41 +00:00
2023-06-05 21:41:32 +00:00
_ , _ = h . Write ( c . Id [ : ] )
2023-06-03 09:29:20 +00:00
crypto . HashFastSum ( h , result [ : ] )
return result
2022-10-26 16:46:41 +00:00
}
2023-06-03 09:29:20 +00:00
func ( c * Consensus ) CalculateSideChainIdFromBlobs ( mainBlob , sideBlob [ ] byte ) ( result types . Hash ) {
h := crypto . GetKeccak256Hasher ( )
defer crypto . PutKeccak256Hasher ( h )
_ , _ = h . Write ( mainBlob )
_ , _ = h . Write ( sideBlob )
2023-06-05 21:41:32 +00:00
_ , _ = h . Write ( c . Id [ : ] )
2023-06-03 09:29:20 +00:00
crypto . HashFastSum ( h , result [ : ] )
return result
2022-10-26 16:46:41 +00:00
}
2023-03-05 14:06:49 +00:00
func ( c * Consensus ) IsDefault ( ) bool {
2023-06-05 21:41:32 +00:00
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 {
2023-06-05 21:41:32 +00:00
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-04-30 19:49:25 +00:00
func ( c * Consensus ) InitHasher ( n int , flags ... randomx . Flag ) error {
if c . hasher != nil {
c . hasher . Close ( )
}
var err error
c . hasher , err = randomx . NewRandomX ( n , flags ... )
if err != nil {
return err
}
return nil
}
func ( c * Consensus ) GetHasher ( ) randomx . Hasher {
if c . hasher == nil {
2023-07-22 15:15:43 +00:00
panic ( "hasher has not been initialized in consensus" )
2023-04-30 19:49:25 +00:00
}
return c . hasher
}
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 )
}
2023-07-10 14:52:19 +00:00
// ApplyUnclePenalty Applies UnclePenalty efficiently
func ( c * Consensus ) ApplyUnclePenalty ( weight types . Difficulty ) ( uncleWeight , unclePenalty types . Difficulty ) {
unclePenalty = weight . Mul64 ( c . UnclePenalty ) . Div64 ( 100 )
uncleWeight = weight . Sub ( unclePenalty )
return
}
2023-06-05 21:41:32 +00:00
var ConsensusDefault = & Consensus { NetworkType : NetworkMainnet , PoolName : "mainnet test 2" , TargetBlockTime : 10 , MinimumDifficulty : 100000 , ChainWindowSize : 2160 , UnclePenalty : 20 , HardForks : p2poolMainNetHardForks , 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 , HardForks : p2poolMainNetHardForks , 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 } }