diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index d99903af4e..bd17714f82 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -53,8 +53,9 @@ type FlowContext struct { onPruningPointUTXOSetOverrideHandler OnPruningPointUTXOSetOverrideHandler onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler - lastRebroadcastTime time.Time - sharedRequestedTransactions *SharedRequestedTransactions + expectedDAAWindowDurationInMilliseconds int64 + lastRebroadcastTime time.Time + sharedRequestedTransactions *SharedRequestedTransactions sharedRequestedBlocks *SharedRequestedBlocks @@ -92,6 +93,8 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage transactionIDsToPropagate: []*externalapi.DomainTransactionID{}, lastTransactionIDPropagationTime: time.Now(), shutdownChan: make(chan struct{}), + expectedDAAWindowDurationInMilliseconds: cfg.NetParams().TargetTimePerBlock.Milliseconds() * + int64(cfg.NetParams().DifficultyAdjustmentWindowSize), } } diff --git a/app/protocol/flowcontext/should_mine.go b/app/protocol/flowcontext/should_mine.go index 9ca7f1a058..f0c01d9472 100644 --- a/app/protocol/flowcontext/should_mine.go +++ b/app/protocol/flowcontext/should_mine.go @@ -2,21 +2,12 @@ package flowcontext import "github.com/kaspanet/kaspad/util/mstime" -const ( - maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 60 * 60 * 1000 // 1 Hour -) - -// ShouldMine returns whether it's ok to use block template from this node -// for mining purposes. -func (f *FlowContext) ShouldMine() (bool, error) { +// IsNearlySynced returns whether this node is considered synced or close to being synced. This info +// is used to determine if it's ok to use a block template from this node for mining purposes. +func (f *FlowContext) IsNearlySynced() (bool, error) { peers := f.Peers() if len(peers) == 0 { - log.Debugf("The node is not connected, so ShouldMine returns false") - return false, nil - } - - if f.IsIBDRunning() { - log.Debugf("IBD is running, so ShouldMine returns false") + log.Debugf("The node is not connected to peers, so IsNearlySynced returns false") return false, nil } @@ -35,13 +26,15 @@ func (f *FlowContext) ShouldMine() (bool, error) { } now := mstime.Now().UnixMilliseconds() - if now-virtualSelectedParentHeader.TimeInMilliseconds() < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { - log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true", + // As a heuristic, we allow the node to mine if he is likely to be within the current DAA window of fully synced nodes. + // Such blocks contribute to security by maintaining the current difficulty despite possibly being slightly out of sync. + if now-virtualSelectedParentHeader.TimeInMilliseconds() < f.expectedDAAWindowDurationInMilliseconds { + log.Debugf("The selected tip timestamp is recent (%d), so IsNearlySynced returns true", virtualSelectedParentHeader.TimeInMilliseconds()) return true, nil } - log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false", + log.Debugf("The selected tip timestamp is old (%d), so IsNearlySynced returns false", virtualSelectedParentHeader.TimeInMilliseconds()) return false, nil } diff --git a/app/protocol/flows/v4/blockrelay/handle_relay_invs.go b/app/protocol/flows/v4/blockrelay/handle_relay_invs.go index 9abf3d7065..74ec9f87a6 100644 --- a/app/protocol/flows/v4/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/v4/blockrelay/handle_relay_invs.go @@ -36,6 +36,7 @@ type RelayInvsContext interface { IsOrphan(blockHash *externalapi.DomainHash) bool IsIBDRunning() bool IsRecoverableError(err error) bool + IsNearlySynced() (bool, error) } type handleRelayInvsFlow struct { @@ -106,10 +107,16 @@ func (flow *handleRelayInvsFlow) start() error { continue } - // Block relay is disabled during IBD + // Block relay is disabled if the node is already during IBD AND considered out of sync if flow.IsIBDRunning() { - log.Debugf("Got block %s while in IBD. continuing...", inv.Hash) - continue + isNearlySynced, err := flow.IsNearlySynced() + if err != nil { + return err + } + if !isNearlySynced { + log.Debugf("Got block %s while in IBD and the node is out of sync. Continuing...", inv.Hash) + continue + } } log.Debugf("Requesting block %s", inv.Hash) diff --git a/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions.go b/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions.go index 74862bafa5..21702986f8 100644 --- a/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions.go +++ b/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions.go @@ -22,7 +22,7 @@ type TransactionsRelayContext interface { SharedRequestedTransactions() *flowcontext.SharedRequestedTransactions OnTransactionAddedToMempool() EnqueueTransactionIDsForPropagation(transactionIDs []*externalapi.DomainTransactionID) error - IsIBDRunning() bool + IsNearlySynced() (bool, error) } type handleRelayedTransactionsFlow struct { @@ -50,7 +50,12 @@ func (flow *handleRelayedTransactionsFlow) start() error { return err } - if flow.IsIBDRunning() { + isNearlySynced, err := flow.IsNearlySynced() + if err != nil { + return err + } + // Transaction relay is disabled if the node is out of sync and thus not mining + if !isNearlySynced { continue } diff --git a/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions_test.go b/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions_test.go index d980456949..09e0d1cc83 100644 --- a/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions_test.go +++ b/app/protocol/flows/v4/transactionrelay/handle_relayed_transactions_test.go @@ -47,8 +47,8 @@ func (m *mocTransactionsRelayContext) EnqueueTransactionIDsForPropagation(transa func (m *mocTransactionsRelayContext) OnTransactionAddedToMempool() { } -func (m *mocTransactionsRelayContext) IsIBDRunning() bool { - return false +func (m *mocTransactionsRelayContext) IsNearlySynced() (bool, error) { + return true, nil } // TestHandleRelayedTransactionsNotFound tests the flow of HandleRelayedTransactions when the peer doesn't diff --git a/app/protocol/flows/v5/blockrelay/handle_relay_invs.go b/app/protocol/flows/v5/blockrelay/handle_relay_invs.go index 9abf3d7065..74ec9f87a6 100644 --- a/app/protocol/flows/v5/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/v5/blockrelay/handle_relay_invs.go @@ -36,6 +36,7 @@ type RelayInvsContext interface { IsOrphan(blockHash *externalapi.DomainHash) bool IsIBDRunning() bool IsRecoverableError(err error) bool + IsNearlySynced() (bool, error) } type handleRelayInvsFlow struct { @@ -106,10 +107,16 @@ func (flow *handleRelayInvsFlow) start() error { continue } - // Block relay is disabled during IBD + // Block relay is disabled if the node is already during IBD AND considered out of sync if flow.IsIBDRunning() { - log.Debugf("Got block %s while in IBD. continuing...", inv.Hash) - continue + isNearlySynced, err := flow.IsNearlySynced() + if err != nil { + return err + } + if !isNearlySynced { + log.Debugf("Got block %s while in IBD and the node is out of sync. Continuing...", inv.Hash) + continue + } } log.Debugf("Requesting block %s", inv.Hash) diff --git a/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions.go b/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions.go index 74862bafa5..21702986f8 100644 --- a/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions.go +++ b/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions.go @@ -22,7 +22,7 @@ type TransactionsRelayContext interface { SharedRequestedTransactions() *flowcontext.SharedRequestedTransactions OnTransactionAddedToMempool() EnqueueTransactionIDsForPropagation(transactionIDs []*externalapi.DomainTransactionID) error - IsIBDRunning() bool + IsNearlySynced() (bool, error) } type handleRelayedTransactionsFlow struct { @@ -50,7 +50,12 @@ func (flow *handleRelayedTransactionsFlow) start() error { return err } - if flow.IsIBDRunning() { + isNearlySynced, err := flow.IsNearlySynced() + if err != nil { + return err + } + // Transaction relay is disabled if the node is out of sync and thus not mining + if !isNearlySynced { continue } diff --git a/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions_test.go b/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions_test.go index 9867ec55dd..5d75be8033 100644 --- a/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions_test.go +++ b/app/protocol/flows/v5/transactionrelay/handle_relayed_transactions_test.go @@ -47,8 +47,8 @@ func (m *mocTransactionsRelayContext) EnqueueTransactionIDsForPropagation(transa func (m *mocTransactionsRelayContext) OnTransactionAddedToMempool() { } -func (m *mocTransactionsRelayContext) IsIBDRunning() bool { - return false +func (m *mocTransactionsRelayContext) IsNearlySynced() (bool, error) { + return true, nil } // TestHandleRelayedTransactionsNotFound tests the flow of HandleRelayedTransactions when the peer doesn't diff --git a/app/protocol/manager.go b/app/protocol/manager.go index 0bdea77a2b..df600cb087 100644 --- a/app/protocol/manager.go +++ b/app/protocol/manager.go @@ -118,7 +118,7 @@ func (m *Manager) SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMemp // ShouldMine returns whether it's ok to use block template from this node // for mining purposes. func (m *Manager) ShouldMine() (bool, error) { - return m.context.ShouldMine() + return m.context.IsNearlySynced() } // IsIBDRunning returns true if IBD is currently marked as running