Skip to content

Commit 3654521

Browse files
committed
btcd,netsync: add stopatheight flag and logic
When the flag stopatheight is set to something greater than zero, btcd stops immediately after processing the height provided. Also, we won't let the node start if the current height is equal or greater than the provided stopatheight.
1 parent 1966c38 commit 3654521

5 files changed

Lines changed: 60 additions & 1 deletion

File tree

btcd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ func btcdMain(serverChan chan<- *server) error {
265265
// Create server and start it.
266266
server, err := newServer(cfg.Listeners, cfg.AgentBlacklist,
267267
cfg.AgentWhitelist, db, activeNetParams.Params, interrupt)
268+
// Don't start the server if we reached stopHeight
269+
if err == errStopHeightReached {
270+
return nil
271+
}
268272
if err != nil {
269273
// TODO: this logging could do with some beautifying.
270274
btcdLog.Errorf("Unable to start server on %v: %v",

config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ type config struct {
172172
SigNet bool `long:"signet" description:"Use the signet test network"`
173173
SigNetChallenge string `long:"signetchallenge" description:"Connect to a custom signet network defined by this challenge instead of using the global default signet test network -- Can be specified multiple times"`
174174
SigNetSeedNode []string `long:"signetseednode" description:"Specify a seed node for the signet network instead of using the global default signet network seed nodes"`
175+
StopAtHeight int `long:"stopatheight" description:"Stop immediately after the block at the specified height is processed"`
175176
TestNet3 bool `long:"testnet" description:"Use the test network (version 3)"`
176177
TestNet4 bool `long:"testnet4" description:"Use the test network (version 4)"`
177178
TorIsolation bool `long:"torisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."`

netsync/interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type Config struct {
3333
Chain *blockchain.BlockChain
3434
TxMemPool *mempool.TxPool
3535
ChainParams *chaincfg.Params
36+
StopHeight int32
3637

3738
DisableCheckpoints bool
3839
MaxPeers int

netsync/manager.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ package netsync
66

77
import (
88
"math/rand"
9+
"os"
910
"sync"
1011
"sync/atomic"
12+
"syscall"
1113
"time"
1214

1315
"github.com/btcsuite/btcd/blockchain"
@@ -183,6 +185,7 @@ type SyncManager struct {
183185
chain *blockchain.BlockChain
184186
txMemPool *mempool.TxPool
185187
chainParams *chaincfg.Params
188+
stopHeight int32
186189
progressLogger *blockProgressLogger
187190
msgChan chan interface{}
188191
wg sync.WaitGroup
@@ -715,6 +718,11 @@ func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) {
715718
}
716719
}
717720

721+
// Do not start processing the block if we are shutting down
722+
if atomic.LoadInt32(&sm.shutdown) > 0 {
723+
return
724+
}
725+
718726
// Check if the block is eligible for less validation since the headers
719727
// have already been verified to link together and are valid up to the
720728
// next checkpoint.
@@ -826,6 +834,35 @@ func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) {
826834
}
827835
}
828836

837+
// Avoid processing the next block if we are at or after stopHeight
838+
if sm.stopHeight > 0 && heightUpdate >= sm.stopHeight {
839+
shutdown := atomic.LoadInt32(&sm.shutdown)
840+
if shutdown < 1 {
841+
atomic.AddInt32(&sm.shutdown, 1)
842+
}
843+
844+
log.Infof("Reached stop height, stopping.")
845+
846+
// btcd will stop before processing any new block, so let's
847+
// write all the cache coins to disk now
848+
sm.chain.FlushUtxoCache(blockchain.FlushRequired)
849+
850+
// TODO(allocz): if we just call sm.Stop(), we will get stuck in
851+
// a state were the process still runing waiting indefinitely
852+
// for other goroutines to stop, so maybe a global stop function
853+
// would be useful to register from where the stop call came
854+
// from and also notify all goroutines to finish their job as
855+
// soon as possible.
856+
pid := os.Getpid()
857+
proc, err := os.FindProcess(pid)
858+
if err != nil {
859+
log.Errorf("Error finding current process: %v",
860+
err)
861+
return
862+
}
863+
proc.Signal(syscall.SIGTERM)
864+
}
865+
829866
// If we are not in the initial block download mode, it's a good time to
830867
// periodically flush the blockchain cache because we don't expect new
831868
// blocks immediately. After that, there is nothing more to do.
@@ -1628,6 +1665,7 @@ func New(config *Config) (*SyncManager, error) {
16281665
chain: config.Chain,
16291666
txMemPool: config.TxMemPool,
16301667
chainParams: config.ChainParams,
1668+
stopHeight: config.StopHeight,
16311669
rejectedTxns: make(map[chainhash.Hash]struct{}),
16321670
requestedTxns: make(map[chainhash.Hash]struct{}),
16331671
requestedBlocks: make(map[chainhash.Hash]struct{}),

server.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ const (
6060
connectionRetryInterval = time.Second * 5
6161
)
6262

63+
var (
64+
// errStopHeightReached is returned from newServer function when
65+
// best height is greater or equal stopAtHeight value
66+
errStopHeightReached = errors.New("stop height reached")
67+
)
68+
6369
var (
6470
// userAgentName is the user agent name and is used to help identify
6571
// ourselves to other bitcoin peers.
@@ -296,7 +302,7 @@ type serverPeer struct {
296302
addressesMtx sync.RWMutex
297303
knownAddresses lru.Cache
298304
banScore connmgr.DynamicBanScore
299-
quit chan struct{}
305+
quit chan struct{}
300306

301307
// Closed by verAckOnce when OnVerAck fires.
302308
verAckCh chan struct{}
@@ -2995,6 +3001,14 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string,
29953001
if err != nil {
29963002
return nil, err
29973003
}
3004+
if sh := int32(cfg.StopAtHeight); sh > 0 {
3005+
bsh := s.chain.BestSnapshot().Height
3006+
if bsh >= sh {
3007+
btcdLog.Infof("Stopping because stopatheight is "+
3008+
"%d and chainstate best height is %d", sh, bsh)
3009+
return nil, errStopHeightReached
3010+
}
3011+
}
29983012

29993013
// Search for a FeeEstimator state in the database. If none can be found
30003014
// or if it cannot be loaded, create a new one.
@@ -3058,6 +3072,7 @@ func newServer(listenAddrs, agentBlacklist, agentWhitelist []string,
30583072
Chain: s.chain,
30593073
TxMemPool: s.txMemPool,
30603074
ChainParams: s.chainParams,
3075+
StopHeight: int32(cfg.StopAtHeight),
30613076
DisableCheckpoints: cfg.DisableCheckpoints,
30623077
MaxPeers: cfg.MaxPeers,
30633078
FeeEstimator: s.feeEstimator,

0 commit comments

Comments
 (0)