Skip to content

Fix testnet difficulty bomb edge-case #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package core

import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -573,6 +574,48 @@ func (bc *BlockChain) SetupHvmHeaderNode(config *tbc.Config) {

log.Info(fmt.Sprintf("hVM node initiated, stateId=%x, current EVM tip=%s", stateId[:], currentHash.String()))

tnFix, _ := hex.DecodeString("2decc762c95d7c392b5e852fc861aab2044b5e5748d1696a0cb00de70014d0f4")
// Special case for testnet
if bytes.Equal(stateId[:], tnFix[:]) {
correctPrevStateId, _ := hex.DecodeString("4d1bafde31ffe9d02b81131333340c762a639865361b9429cdf21181e78d8bff")
badBTCBlock, _ := hex.DecodeString("000000000001bdeacca48fd53488d5a8ecf8af7370eb1703623e30e16655f4ae")

var badBlock chainhash.Hash
_ = badBlock.SetBytes(badBTCBlock[:])
badBlockHeader, _, err := bc.tbcHeaderNode.BlockHeaderByHash(context.Background(), badBlock)
if err != nil {
log.Crit("Unable to get bad BTC block", "block", badBTCBlock, "err", err)
}

headersToRemove := make([]*wire.BlockHeader, 1)
headersToRemove[0] = badBlockHeader

msgHeaders := &wire.MsgHeaders{
Headers: headersToRemove,
}

correctHead, _ := hex.DecodeString("0000000000a811c5b42e4a63b9adbaf18686ecbaff8044260bce43a7bdee70d8")

var ch chainhash.Hash
_ = ch.SetBytes(correctHead[:])
prevHeader, _, err := bc.tbcHeaderNode.BlockHeaderByHash(context.Background(), ch)
if err != nil {
log.Crit("Unable to get correct previous block", "block", badBTCBlock, "err", err)
}

// Remove partial hVM state transition and set state back to hVM state at 4d1bafde31ffe9d02b81131333340c762a639865361b9429cdf21181e78d8bff
_, _, err = bc.tbcHeaderNode.RemoveExternalHeaders(context.Background(), msgHeaders, prevHeader, correctPrevStateId)
if err != nil {
log.Crit("Unable to remove external headers", "err", err)
}

// Get updated state ID after fix to continue initialization
stateId, err = bc.tbcHeaderNode.UpstreamStateId(bc.ctx)
if err != nil {
log.Crit("Unable to get upstream state ID from TBC header node", "err", err)
}
}

if bytes.Equal(stateId[:], hVMGenesisUpstreamId[:]) {
// TBC claims to be in its genesis configuration, check to ensure its best header is the hVM genesis header
_, bestHeader, err := bc.tbcHeaderNode.BlockHeaderBest(bc.ctx)
Expand Down
4 changes: 4 additions & 0 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package catalyst

import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"strconv"
Expand Down Expand Up @@ -316,6 +317,8 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
api.forkchoiceLock.Lock()
defer api.forkchoiceLock.Unlock()

log.Info(fmt.Sprintf("Forkchoice update contains %d transactions", len(payloadAttributes.Transactions)))

log.Trace("Engine API request received", "method", "ForkchoiceUpdated", "head", update.HeadBlockHash, "finalized", update.FinalizedBlockHash, "safe", update.SafeBlockHash)
log.Trace(fmt.Sprintf("forkchoiceUpdated, payloadAttributes=%v", payloadAttributes))
log.Info(fmt.Sprintf("Engine API forkchoice updated, head=%s, finalized=%s, safe=%s", update.HeadBlockHash.String(), update.FinalizedBlockHash.String(), update.SafeBlockHash.String()))
Expand Down Expand Up @@ -462,6 +465,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
return engine.STATUS_INVALID, fmt.Errorf("transaction %d is not valid: %v", i, err)
}
transactions = append(transactions, &tx)
log.Info(fmt.Sprintf("Forcibly including transaction %s from source %s with type %d to address %s with data %s", tx.Hash().String(), tx.SourceHash().String(), tx.Type(), tx.To().String(), hex.EncodeToString(tx.Data())))
}
args := &miner.BuildPayloadArgs{
Parent: update.HeadBlockHash,
Expand Down
15 changes: 11 additions & 4 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,12 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
if err != nil {
return &newPayloadResult{err: fmt.Errorf("failed to force-include tx: %s type: %d sender: %s nonce: %d, err: %w", tx.Hash(), tx.Type(), from, tx.Nonce(), err)}
}

log.Info(fmt.Sprintf("Force-included transaction %s", tx.Hash().String()))
}

containsBtcAttrDepTx := false
if !params.noTxs {
if !params.noTxs && len(params.txs) < 2 {
// First, check whether a new Bitcoin Attributes Deposited tx should be included.
// This is a redundant check since GetBitcoinAttributesForNextBlock will return nil with no error if hVM is not enabled/activated.
if miner.backend.BlockChain().IsHvmEnabled() && miner.chainConfig.IsHvm0(params.timestamp) {
Expand Down Expand Up @@ -186,9 +188,14 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
interrupt = new(atomic.Int32)
}

err = miner.fillTransactions(interrupt, work)
if errors.Is(err, errBlockInterruptedByResolve) {
log.Info("Block building got interrupted by payload resolution")
if !containsBtcAttrDepTx {
log.Info("Not including BTC Attributes Deposited transaction, so adding mempool transactions")
err = miner.fillTransactions(interrupt, work)
if errors.Is(err, errBlockInterruptedByResolve) {
log.Info("Block building got interrupted by payload resolution")
}
} else {
log.Info("Block contains BTC Attributes Deposited transaction, not adding mempool transactions")
}
}

Expand Down