diff --git a/p2pool/api/p2poolapi.go b/p2pool/api/p2poolapi.go index 3bfdbf7..ab55662 100644 --- a/p2pool/api/p2poolapi.go +++ b/p2pool/api/p2poolapi.go @@ -54,7 +54,7 @@ func (p *P2PoolApi) WaitSync() (err error) { time.Sleep(time.Second * 5) } utils.Logf("API", "SYNCHRONIZED (height %d, id %s, blocks %d)", status.Height, status.Id, status.Blocks) - utils.Logf("API", "Consensus id = %s\n", p.Consensus().Id) + utils.Logf("API", "Consensus id = %s / %s\n", p.Consensus().Id, p.Consensus().MergeMiningId) return nil } @@ -77,7 +77,7 @@ func (p *P2PoolApi) WaitSyncStart() (err error) { if status.Synchronized { utils.Logf("API", "SYNCHRONIZED (height %d, id %s, blocks %d)", status.Height, status.Id, status.Blocks) } - utils.Logf("API", "Consensus id = %s\n", p.Consensus().Id) + utils.Logf("API", "Consensus id = %s / %s\n", p.Consensus().Id, p.Consensus().MergeMiningId) return nil } diff --git a/p2pool/p2p/client.go b/p2pool/p2p/client.go index 85df88b..035dbbd 100644 --- a/p2pool/p2p/client.go +++ b/p2pool/p2p/client.go @@ -404,6 +404,7 @@ func (c *Client) OnConnection() { } if c.IsIncomingConnection { + //TODO: consensus MergeMiningId if hash, ok := CalculateChallengeHash(c.handshakeChallenge, c.Owner.Consensus().Id, solution); !ok { //not enough PoW c.Ban(DefaultBanTime, fmt.Errorf("not enough PoW on HANDSHAKE_SOLUTION, challenge = %s, solution = %d, calculated hash = %s, expected hash = %s", fasthex.EncodeToString(c.handshakeChallenge[:]), solution, hash.String(), challengeHash.String())) @@ -414,6 +415,7 @@ func (c *Client) OnConnection() { return } } else { + //TODO: consensus MergeMiningId if hash, _ := CalculateChallengeHash(c.handshakeChallenge, c.Owner.Consensus().Id, solution); hash != challengeHash { //wrong hash c.Ban(DefaultBanTime, fmt.Errorf("wrong hash HANDSHAKE_SOLUTION, challenge = %s, solution = %d, calculated hash = %s, expected hash = %s", fasthex.EncodeToString(c.handshakeChallenge[:]), solution, hash.String(), challengeHash.String())) @@ -885,6 +887,7 @@ func (c *Client) sendHandshakeSolution(challenge HandshakeChallenge) { stop.Store(true) } + //TODO: consensus MergeMiningId if solution, hash, ok := FindChallengeSolution(challenge, c.Owner.Consensus().Id, stop); ok || c.IsIncomingConnection { var buf [HandshakeChallengeSize + types.HashSize]byte diff --git a/p2pool/sidechain/consensus.go b/p2pool/sidechain/consensus.go index 8b2da54..2d084da 100644 --- a/p2pool/sidechain/consensus.go +++ b/p2pool/sidechain/consensus.go @@ -99,9 +99,11 @@ type Consensus struct { hasher randomx.Hasher Id types.Hash `json:"id"` + + MergeMiningId types.Hash `json:"mm_id"` } -const SmallestMinimumDifficulty = 100000 +const SmallestMinimumDifficulty = 1000 const LargestMinimumDifficulty = 1000000000 func NewConsensus(networkType NetworkType, poolName, poolPassword string, targetBlockTime, minimumDifficulty, chainWindowSize, unclePenalty uint64) *Consensus { @@ -166,10 +168,14 @@ func (c *Consensus) verify() bool { } var emptyHash types.Hash - c.Id = c.CalculateId() + c.Id = c.CalculateId(false) if c.Id == emptyHash { return false } + c.MergeMiningId = c.CalculateId(true) + if c.MergeMiningId == emptyHash { + return false + } if len(c.HardForks) == 0 { switch c.NetworkType { @@ -200,19 +206,27 @@ func (c *Consensus) CalculateSideTemplateIdPreAllocated(share *PoolBlock, buf [] buf, _ = share.Side.AppendBinary(buf[:0], share.ShareVersion()) _, _ = h.Write(buf) - _, _ = h.Write(c.Id[:]) + if share.ShareVersion() > ShareVersion_V2 { + _, _ = h.Write(c.MergeMiningId[:]) + } else { + _, _ = h.Write(c.Id[:]) + } crypto.HashFastSum(h, result[:]) return result } -func (c *Consensus) CalculateSideChainIdFromBlobs(mainBlob, sideBlob []byte) (result types.Hash) { +func (c *Consensus) CalculateSideChainIdFromBlobs(mainBlob, sideBlob []byte, isMergeMining bool) (result types.Hash) { h := crypto.GetKeccak256Hasher() defer crypto.PutKeccak256Hasher(h) _, _ = h.Write(mainBlob) _, _ = h.Write(sideBlob) - _, _ = h.Write(c.Id[:]) + if isMergeMining { + _, _ = h.Write(c.MergeMiningId[:]) + } else { + _, _ = h.Write(c.Id[:]) + } crypto.HashFastSum(h, result[:]) return result } @@ -267,8 +281,11 @@ func (c *Consensus) GetHasher() randomx.Hasher { return c.hasher } -func (c *Consensus) CalculateId() types.Hash { +func (c *Consensus) CalculateId(mergeMining bool) types.Hash { var buf []byte + if mergeMining { + buf = append(buf, 'm', 'm', 0) + } buf = append(buf, c.NetworkType.String()...) buf = append(buf, 0) buf = append(buf, c.PoolName...) @@ -294,5 +311,26 @@ func (c *Consensus) ApplyUnclePenalty(weight types.Difficulty) (uncleWeight, unc return } -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}} +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}, + MergeMiningId: types.Hash{107, 177, 178, 129, 71, 2, 66, 207, 56, 145, 102, 187, 105, 128, 102, 27, 68, 29, 81, 92, 114, 214, 215, 125, 158, 40, 117, 207, 32, 182, 142, 101}, +} + +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}, + MergeMiningId: types.Hash{215, 23, 207, 132, 167, 193, 162, 243, 66, 3, 228, 99, 238, 140, 39, 46, 112, 158, 200, 37, 62, 100, 138, 59, 183, 233, 136, 91, 198, 34, 19, 39}, +} diff --git a/p2pool/sidechain/consensus_test.go b/p2pool/sidechain/consensus_test.go index e71d0c2..760a258 100644 --- a/p2pool/sidechain/consensus_test.go +++ b/p2pool/sidechain/consensus_test.go @@ -6,15 +6,24 @@ import ( ) func TestDefaultConsensusId(t *testing.T) { - id := ConsensusMini.CalculateId() + id := ConsensusMini.CalculateId(false) if id != ConsensusMini.Id { t.Fatalf("wrong mini sidechain id, expected %s, got %s", ConsensusMini.Id.String(), id.String()) } + id = ConsensusMini.CalculateId(true) + if id != ConsensusMini.MergeMiningId { + t.Fatalf("wrong mini merge mining sidechain id, expected %s, got %s", ConsensusMini.MergeMiningId.String(), id.String()) + } - id = ConsensusDefault.CalculateId() + id = ConsensusDefault.CalculateId(false) if id != ConsensusDefault.Id { t.Fatalf("wrong default sidechain id, expected %s, got %s", ConsensusDefault.Id.String(), id.String()) } + + id = ConsensusDefault.CalculateId(true) + if id != ConsensusDefault.MergeMiningId { + t.Fatalf("wrong default merge mining sidechain id, expected %s, got %s", ConsensusDefault.MergeMiningId.String(), id.String()) + } } func TestOverlyLongConsensus(t *testing.T) { diff --git a/p2pool/sidechain/sidechain.go b/p2pool/sidechain/sidechain.go index 5265669..b52f841 100644 --- a/p2pool/sidechain/sidechain.go +++ b/p2pool/sidechain/sidechain.go @@ -315,7 +315,7 @@ func (c *SideChain) AddPoolBlockExternal(block *PoolBlock) (missingBlocks []type //verify template id against merkle proof mmTag := block.MergeMiningTag() - auxiliarySlot := merge_mining.GetAuxiliarySlot(c.Consensus().Id, mmTag.Nonce, mmTag.NumberAuxiliaryChains) + auxiliarySlot := merge_mining.GetAuxiliarySlot(c.Consensus().MergeMiningId, mmTag.Nonce, mmTag.NumberAuxiliaryChains) if !block.Side.MerkleProof.Verify(templateId, int(auxiliarySlot), int(mmTag.NumberAuxiliaryChains), mmTag.RootHash) { return nil, fmt.Errorf("could not verify template id %s merkle proof against merkle tree root hash %s (number of chains = %d, nonce = %d, auxiliary slot = %d)", templateId, mmTag.RootHash, mmTag.NumberAuxiliaryChains, mmTag.Nonce, auxiliarySlot), true @@ -606,7 +606,8 @@ func (c *SideChain) verifyBlock(block *PoolBlock) (verification error, invalid e len(block.Side.Uncles) != 0 || block.Side.Difficulty.Cmp64(c.Consensus().MinimumDifficulty) != 0 || block.Side.CumulativeDifficulty.Cmp64(c.Consensus().MinimumDifficulty) != 0 || - (block.ShareVersion() > ShareVersion_V1 && block.Side.CoinbasePrivateKeySeed != c.Consensus().Id) { + (block.ShareVersion() > ShareVersion_V1 && block.ShareVersion() < ShareVersion_V3 && block.Side.CoinbasePrivateKeySeed != c.Consensus().Id) || + (block.ShareVersion() > ShareVersion_V2 && block.Side.CoinbasePrivateKeySeed != c.Consensus().MergeMiningId) { return nil, errors.New("genesis block has invalid parameters") } //this does not verify coinbase outputs, but that's fine diff --git a/p2pool/stratum/server.go b/p2pool/stratum/server.go index dbc436c..90c4f5a 100644 --- a/p2pool/stratum/server.go +++ b/p2pool/stratum/server.go @@ -218,7 +218,11 @@ func (s *Server) fillNewTemplateData(currentDifficulty types.Difficulty) error { s.newTemplateData.Uncles = s.sidechain.GetPossibleUncles(s.tip, s.newTemplateData.SideHeight) } else { s.newTemplateData.PreviousTemplateId = types.ZeroHash - s.newTemplateData.TransactionPrivateKeySeed = s.sidechain.Consensus().Id + if s.newTemplateData.ShareVersion > sidechain.ShareVersion_V2 { + s.newTemplateData.TransactionPrivateKeySeed = s.sidechain.Consensus().MergeMiningId + } else { + s.newTemplateData.TransactionPrivateKeySeed = s.sidechain.Consensus().Id + } s.newTemplateData.Difficulty = types.DifficultyFrom64(s.sidechain.Consensus().MinimumDifficulty) s.newTemplateData.CumulativeDifficulty = types.DifficultyFrom64(s.sidechain.Consensus().MinimumDifficulty) } diff --git a/p2pool/stratum/template.go b/p2pool/stratum/template.go index 4d6eae6..f99cbeb 100644 --- a/p2pool/stratum/template.go +++ b/p2pool/stratum/template.go @@ -106,7 +106,11 @@ func (tpl *Template) TemplateId(hasher *sha3.HasherState, preAllocatedBuffer []b buf := tpl.Blob(preAllocatedBuffer, 0, 0, sideRandomNumber, sideExtraNonce, types.ZeroHash) _, _ = hasher.Write(buf) - _, _ = hasher.Write(consensus.Id[:]) + if tpl.ShareVersion(consensus) > sidechain.ShareVersion_V2 { + _, _ = hasher.Write(consensus.MergeMiningId[:]) + } else { + _, _ = hasher.Write(consensus.Id[:]) + } crypto.HashFastSum(hasher, (*result)[:]) hasher.Reset() } @@ -116,6 +120,10 @@ func (tpl *Template) Timestamp() uint64 { return t } +func (tpl *Template) ShareVersion(consensus *sidechain.Consensus) sidechain.ShareVersion { + return sidechain.P2PoolShareVersion(consensus, tpl.Timestamp()) +} + func (tpl *Template) CoinbaseBufferLength() int { return tpl.TransactionsOffset - tpl.CoinbaseOffset }