Skip to content
15 changes: 10 additions & 5 deletions api/service/synchronize/stagedstreamsync/stage_states.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/rs/zerolog"
Expand Down Expand Up @@ -173,7 +174,8 @@ func (stg *StageStates) Exec(ctx context.Context, firstCycle bool, invalidBlockR
return ErrInvalidBlockNumber
}

if stg.configs.bc.HasBlock(block.Hash(), block.NumberU64()) {
blockErr := consensus_engine.ValidateBlockHash(block.Hash())
Comment thread
Frozen marked this conversation as resolved.
Outdated
if blockErr == nil && stg.configs.bc.HasBlock(block.Hash(), block.NumberU64()) {
// At this point, there should be some db discrepancies
if blk := stg.configs.bc.GetBlock(block.Hash(), block.NumberU64()); blk != nil {
if blk.NumberU64() == block.NumberU64() && blk.Hash() == block.Hash() {
Expand All @@ -189,22 +191,25 @@ func (stg *StageStates) Exec(ctx context.Context, firstCycle bool, invalidBlockR
}
}

if err := s.state.UpdateBlockAndStatus(block, stg.configs.bc, false); err != nil {
stg.configs.logger.Warn().Err(err).Uint64("cycle target block", targetHeight).
if blockErr == nil {
blockErr = s.state.UpdateBlockAndStatus(block, stg.configs.bc, false)
}
if blockErr != nil {
stg.configs.logger.Warn().Err(blockErr).Uint64("cycle target block", targetHeight).
Uint64("block number", block.NumberU64()).
Msg(WrapStagedSyncMsg("insert blocks failed in long range"))
s.state.protocol.StreamFailed(streamID, "unverifiable invalid block is received from stream")
invalidBlockHash := block.Hash()
reverter.RevertTo(stg.configs.bc.CurrentBlock().NumberU64(), block.NumberU64(), invalidBlockHash, streamID)
pl["error"] = err.Error()
pl["error"] = blockErr.Error()
longRangeFailInsertedBlockCounterVec.With(pl).Inc()

// Clean up download details for the failed block to prevent memory leaks
if gbm != nil {
gbm.CleanupDetails(i)
}

return err
return blockErr
}

// Mark block as completed after successful insertion
Expand Down
8 changes: 7 additions & 1 deletion cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ func validateHarmonyConfig(config harmonyconfig.HarmonyConfig) error {
return fmt.Errorf("flag --run.offline must have p2p IP be %v", nodeconfig.DefaultLocalListenIP)
}

if !config.Sync.Client && !config.DNSSync.Client {
// Recovery maintenance must be able to open a stopped database without
// starting either downloader. The mainnet validator exception is paired
// with a fail-closed runtime checkpoint/sync guard in cmd/harmony.
recoveryValidator := config.Network.NetworkType == nodeconfig.Mainnet &&
config.General.NodeType == NodeTypeValidator
if !config.Sync.Client && !config.DNSSync.Client &&
!config.General.IsOffline && !recoveryValidator {
// There is no module up for sync
return errors.New("either --sync.client or --sync.legacy.client shall be enabled")
}
Expand Down
27 changes: 27 additions & 0 deletions cmd/config/recovery_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package config

import (
"testing"

nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/stretchr/testify/require"
)

func TestRecoveryConfigAllowsNoSyncClientOnlyInNarrowCases(t *testing.T) {
offline := GetDefaultHmyConfigCopy(nodeconfig.Mainnet)
offline.General.IsOffline = true
offline.P2P.IP = nodeconfig.DefaultLocalListenIP
offline.Sync.Client = false
offline.DNSSync.Client = false
require.NoError(t, validateHarmonyConfig(offline))

recoveryValidator := GetDefaultHmyConfigCopy(nodeconfig.Mainnet)
recoveryValidator.Sync.Client = false
recoveryValidator.DNSSync.Client = false
require.NoError(t, validateHarmonyConfig(recoveryValidator))

testnet := GetDefaultHmyConfigCopy(nodeconfig.Testnet)
testnet.Sync.Client = false
testnet.DNSSync.Client = false
require.Error(t, validateHarmonyConfig(testnet))
}
Loading