mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
In IBD, validate the timestamps of the headers of the pruning point and selected tip (#1829)
* Implement validatePruningPointFutureHeaderTimestamps. * Fix TestIBDWithPruning. * Fix wrong logic. * Add a comment. * Fix a comment. * Fix a variable name. * Add a commment * Fix TestIBDWithPruning. Co-authored-by: Ori Newman <orinewman1@gmail.com>
This commit is contained in:
parent
3dbc42b4f7
commit
77a344cc29
@ -320,6 +320,40 @@ func (flow *handleRelayInvsFlow) processHeader(consensus externalapi.Consensus,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) validatePruningPointFutureHeaderTimestamps() error {
|
||||
headerSelectedTipHash, err := flow.Domain().StagingConsensus().GetHeadersSelectedTip()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headerSelectedTipHeader, err := flow.Domain().StagingConsensus().GetBlockHeader(headerSelectedTipHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headerSelectedTipTimestamp := headerSelectedTipHeader.TimeInMilliseconds()
|
||||
|
||||
currentSelectedTipHash, err := flow.Domain().Consensus().GetHeadersSelectedTip()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentSelectedTipHeader, err := flow.Domain().Consensus().GetBlockHeader(currentSelectedTipHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentSelectedTipTimestamp := currentSelectedTipHeader.TimeInMilliseconds()
|
||||
|
||||
if headerSelectedTipTimestamp < currentSelectedTipTimestamp {
|
||||
return protocolerrors.Errorf(false, "the timestamp of the candidate selected "+
|
||||
"tip is smaller than the current selected tip")
|
||||
}
|
||||
|
||||
minTimestampDifferenceInMilliseconds := (10 * time.Minute).Milliseconds()
|
||||
if headerSelectedTipTimestamp-currentSelectedTipTimestamp < minTimestampDifferenceInMilliseconds {
|
||||
return protocolerrors.Errorf(false, "difference between the timestamps of "+
|
||||
"the current pruning point and the candidate pruning point is too small. Aborting IBD...")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) receiveAndInsertPruningPointUTXOSet(
|
||||
consensus externalapi.Consensus, pruningPointHash *externalapi.DomainHash) (bool, error) {
|
||||
|
||||
|
@ -137,6 +137,11 @@ func (flow *handleRelayInvsFlow) downloadHeadersAndPruningUTXOSet(highHash *exte
|
||||
return protocolerrors.Errorf(true, "the triggering IBD block was not sent")
|
||||
}
|
||||
|
||||
err = flow.validatePruningPointFutureHeaderTimestamps()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Syncing the current pruning point UTXO set")
|
||||
syncedPruningPointUTXOSetSuccessfully, err := flow.syncPruningPointUTXOSet(flow.Domain().StagingConsensus(), proofPruningPoint)
|
||||
if err != nil {
|
||||
|
@ -54,15 +54,15 @@ type Config struct {
|
||||
|
||||
// DefaultConfig returns the default mempool configuration
|
||||
func DefaultConfig(dagParams *dagconfig.Params) *Config {
|
||||
targetBlocksPerSecond := uint64(time.Second / dagParams.TargetTimePerBlock)
|
||||
targetBlocksPerSecond := time.Second.Seconds() / dagParams.TargetTimePerBlock.Seconds()
|
||||
|
||||
return &Config{
|
||||
MaximumTransactionCount: defaultMaximumTransactionCount,
|
||||
TransactionExpireIntervalDAAScore: defaultTransactionExpireIntervalSeconds / targetBlocksPerSecond,
|
||||
TransactionExpireScanIntervalDAAScore: defaultTransactionExpireScanIntervalSeconds / targetBlocksPerSecond,
|
||||
TransactionExpireIntervalDAAScore: uint64(float64(defaultTransactionExpireIntervalSeconds) / targetBlocksPerSecond),
|
||||
TransactionExpireScanIntervalDAAScore: uint64(float64(defaultTransactionExpireScanIntervalSeconds) / targetBlocksPerSecond),
|
||||
TransactionExpireScanIntervalSeconds: defaultTransactionExpireScanIntervalSeconds,
|
||||
OrphanExpireIntervalDAAScore: defaultOrphanExpireIntervalSeconds / targetBlocksPerSecond,
|
||||
OrphanExpireScanIntervalDAAScore: defaultOrphanExpireScanIntervalSeconds / targetBlocksPerSecond,
|
||||
OrphanExpireIntervalDAAScore: uint64(float64(defaultOrphanExpireIntervalSeconds) / targetBlocksPerSecond),
|
||||
OrphanExpireScanIntervalDAAScore: uint64(float64(defaultOrphanExpireScanIntervalSeconds) / targetBlocksPerSecond),
|
||||
MaximumOrphanTransactionMass: defaultMaximumOrphanTransactionMass,
|
||||
MaximumOrphanTransactionCount: defaultMaximumOrphanTransactionCount,
|
||||
AcceptNonStandard: dagParams.RelayNonStdTxs,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"reflect"
|
||||
"sync"
|
||||
@ -116,7 +117,7 @@ func TestIBDWithPruning(t *testing.T) {
|
||||
}
|
||||
|
||||
// This should trigger resolving the syncee virtual
|
||||
syncerTip := mineNextBlock(t, syncer)
|
||||
syncerTip := mineNextBlockWithMockTimestamps(t, syncer)
|
||||
time.Sleep(time.Second)
|
||||
synceeSelectedTip, err := syncee.rpcClient.GetSelectedTipHash()
|
||||
if err != nil {
|
||||
@ -132,6 +133,12 @@ func TestIBDWithPruning(t *testing.T) {
|
||||
|
||||
overrideDAGParams := dagconfig.SimnetParams
|
||||
|
||||
// Increase the target time per block so that we could mine
|
||||
// blocks with timestamps that are spaced far enough apart
|
||||
// to avoid failing the timestamp threshold validation of
|
||||
// ibd-with-headers-proof
|
||||
overrideDAGParams.TargetTimePerBlock = time.Minute
|
||||
|
||||
// This is done to make a pruning depth of 6 blocks
|
||||
overrideDAGParams.FinalityDuration = 2 * overrideDAGParams.TargetTimePerBlock
|
||||
overrideDAGParams.K = 0
|
||||
@ -178,11 +185,11 @@ func TestIBDWithPruning(t *testing.T) {
|
||||
// block.
|
||||
const synceeOnlyBlocks = 2
|
||||
for i := 0; i < synceeOnlyBlocks; i++ {
|
||||
mineNextBlock(t, syncee1)
|
||||
mineNextBlockWithMockTimestamps(t, syncee1)
|
||||
}
|
||||
|
||||
for i := 0; i < numBlocks-1; i++ {
|
||||
mineNextBlock(t, syncer)
|
||||
mineNextBlockWithMockTimestamps(t, syncer)
|
||||
}
|
||||
|
||||
testSync(syncer, syncee1)
|
||||
@ -190,3 +197,38 @@ func TestIBDWithPruning(t *testing.T) {
|
||||
// Test a situation where a node with pruned headers syncs another fresh node.
|
||||
testSync(syncee1, syncee2)
|
||||
}
|
||||
|
||||
var currentMockTimestamp int64 = 0
|
||||
|
||||
// mineNextBlockWithMockTimestamps mines blocks with large timestamp differences
|
||||
// between every two blocks. This is done to avoid the timestamp threshold validation
|
||||
// of ibd-with-headers-proof
|
||||
func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
|
||||
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting block template: %+v", err)
|
||||
}
|
||||
|
||||
block, err := appmessage.RPCBlockToDomainBlock(blockTemplate.Block)
|
||||
if err != nil {
|
||||
t.Fatalf("Error converting block: %s", err)
|
||||
}
|
||||
|
||||
if currentMockTimestamp == 0 {
|
||||
currentMockTimestamp = block.Header.TimeInMilliseconds()
|
||||
} else {
|
||||
currentMockTimestamp += 10_000
|
||||
}
|
||||
mutableHeader := block.Header.ToMutable()
|
||||
mutableHeader.SetTimeInMilliseconds(currentMockTimestamp)
|
||||
block.Header = mutableHeader.ToImmutable()
|
||||
|
||||
solveBlock(block)
|
||||
|
||||
_, err = harness.rpcClient.SubmitBlock(block)
|
||||
if err != nil {
|
||||
t.Fatalf("Error submitting block: %s", err)
|
||||
}
|
||||
|
||||
return block
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user