Skip to content

Commit c4da54c

Browse files
authored
support flag to control size of block index cache (#1453)
* support flag to control size of block index cache * fix calls to NewBlockchain to include block index size * update run.go to use DefaultBlockIndexSize
1 parent ca1497c commit c4da54c

File tree

11 files changed

+79
-28
lines changed

11 files changed

+79
-28
lines changed

cmd/config.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ type Config struct {
4949
DisableEncoderMigrations bool
5050
HypersyncMaxQueueSize uint32
5151

52+
// Block Index Size
53+
BlockIndexSize int
54+
5255
// PoS Validator
5356
PosValidatorSeed string
5457

@@ -140,6 +143,18 @@ func LoadConfig() *Config {
140143
config.DisableEncoderMigrations = viper.GetBool("disable-encoder-migrations")
141144
config.HypersyncMaxQueueSize = viper.GetUint32("hypersync-max-queue-size")
142145

146+
// Block Index Size
147+
config.BlockIndexSize = viper.GetInt("block-index-size")
148+
if config.BlockIndexSize <= 0 {
149+
glog.Fatal("Block index size must be greater than 0")
150+
}
151+
if config.BlockIndexSize < lib.MinBlockIndexSize {
152+
glog.Fatalf("Block index size must be greater than %d", lib.MinBlockIndexSize)
153+
}
154+
if config.BlockIndexSize > lib.MaxBlockIndexSize {
155+
glog.Fatalf("Block index size must be less than %d", lib.MaxBlockIndexSize)
156+
}
157+
143158
// PoS Validator
144159
config.PosValidatorSeed = viper.GetString("pos-validator-seed")
145160

@@ -270,6 +285,8 @@ func (config *Config) Print() {
270285
glog.Infof("MaxSyncBlockHeight: %v", config.MaxSyncBlockHeight)
271286
}
272287

288+
glog.Infof("BlockIndexSize: %v", config.BlockIndexSize)
289+
273290
if len(config.ConnectIPs) > 0 {
274291
glog.Infof("Connect IPs: %s", config.ConnectIPs)
275292
}

cmd/node.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ func (node *Node) Start(exitChannels ...*chan struct{}) {
245245
node.Config.TransactionValidationRefreshIntervalMillis,
246246
node.Config.StateSyncerMempoolTxnSyncLimit,
247247
node.Config.CheckpointSyncingProviders,
248+
node.Config.BlockIndexSize,
248249
)
249250
if err != nil {
250251
// shouldRestart can be true if, on the previous run, we did not finish flushing all ancestral

cmd/run.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ func SetupRunFlags(cmd *cobra.Command) {
8686
is true.
8787
- hypersync: Will sync by downloading historical state, and will NOT
8888
download historical blocks. Can only be set if HyperSync is true.`)
89+
// Block Index Size
90+
cmd.PersistentFlags().Uint64("block-index-size", lib.DefaultBlockIndexSize, "The number of blocks to keep in memory in the block "+
91+
"index. Setting this to a lower number will reduce memory usage, but will require the node to go to disk "+
92+
"more when fetching block nodes more often.")
8993

9094
// PoS Validator
9195
cmd.PersistentFlags().String("pos-validator-seed", "", "A BIP39 seed phrase or seed hex used to generate the "+

lib/blockchain.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -553,24 +553,32 @@ type BlockIndex struct {
553553
blockIndexByHash *collections.LruCache[BlockHash, *BlockNode]
554554
tip *BlockNode
555555
headerTip *BlockNode
556+
size int
556557
}
557558

558559
// NewBlockIndex creates a new BlockIndex with the provided snapshot and tip node.
559-
func NewBlockIndex(db *badger.DB, snapshot *Snapshot, tipNode *BlockNode) *BlockIndex {
560-
blockIndexByHash, _ := collections.NewLruCache[BlockHash, *BlockNode](MaxBlockIndexNodes) // TODO: parameterize this?
560+
func NewBlockIndex(db *badger.DB, snapshot *Snapshot, tipNode *BlockNode, blockIndexSize int) (*BlockIndex, error) {
561+
blockIndexByHash, err := collections.NewLruCache[BlockHash, *BlockNode](blockIndexSize)
562+
if err != nil {
563+
return nil, errors.Wrapf(err, "NewBlockIndex: Problem creating LRU cache")
564+
}
561565
return &BlockIndex{
562566
db: db,
563567
snapshot: snapshot,
564568
blockIndexByHash: blockIndexByHash,
565569
tip: tipNode,
566570
headerTip: tipNode,
567-
}
571+
size: blockIndexSize,
572+
}, nil
568573
}
569574

570575
// setBlockIndexFromMap is a helper function only used in tests. It constructs the
571576
// block index from the provided map of block hashes to block nodes.
572-
func (bi *BlockIndex) setBlockIndexFromMap(input map[BlockHash]*BlockNode) {
573-
newHashToBlockNodeMap, _ := collections.NewLruCache[BlockHash, *BlockNode](MaxBlockIndexNodes) // TODO: parameterize this?
577+
func (bi *BlockIndex) setBlockIndexFromMap(input map[BlockHash]*BlockNode) error {
578+
newHashToBlockNodeMap, err := collections.NewLruCache[BlockHash, *BlockNode](bi.size)
579+
if err != nil {
580+
return errors.Wrapf(err, "setBlockIndexFromMap: Problem creating LRU cache")
581+
}
574582
bi.blockIndexByHash = newHashToBlockNodeMap
575583
for _, val := range input {
576584
bi.addNewBlockNodeToBlockIndex(val)
@@ -582,6 +590,7 @@ func (bi *BlockIndex) setBlockIndexFromMap(input map[BlockHash]*BlockNode) {
582590
bi.tip = val
583591
}
584592
}
593+
return nil
585594
}
586595

587596
// setHeaderTip sets the header tip of the block index to the provided block node.
@@ -879,7 +888,7 @@ func (bc *Blockchain) CopyBlockIndexes() (
879888
_blockIndexByHash *collections.LruCache[BlockHash, *BlockNode],
880889
) {
881890
// Create a new lru cache.
882-
newBlockIndexByHash, _ := collections.NewLruCache[BlockHash, *BlockNode](MaxBlockIndexNodes)
891+
newBlockIndexByHash, _ := collections.NewLruCache[BlockHash, *BlockNode](bc.blockIndex.size)
883892
// Iterate over the keys of the block index and copy them to the new lru cache.
884893
for _, key := range bc.blockIndex.blockIndexByHash.Keys() {
885894
val, _ := bc.blockIndex.blockIndexByHash.Get(key)
@@ -1039,10 +1048,15 @@ func (bc *Blockchain) _initChain() error {
10391048
if !tipNodeExists {
10401049
return fmt.Errorf("_initChain: Best hash (%#v) not found in block index", bestBlockHash)
10411050
}
1042-
// Walk back the last 6 hours of blocks.
1051+
// Walk back the last 6 hours of blocks. Or enough to fill the block index cache if the
1052+
// size of the block index cache is less than 6 * 3600
10431053
currBlockCounter := 1
10441054
parentNode := tipNode.GetParent(bc.blockIndex)
1045-
for currBlockCounter < 3600*6 && parentNode != nil {
1055+
numBlockNodesToFetch := 3600 * 6
1056+
if bc.blockIndex.size < numBlockNodesToFetch {
1057+
numBlockNodesToFetch = bc.blockIndex.size
1058+
}
1059+
for currBlockCounter < numBlockNodesToFetch && parentNode != nil {
10461060
parentNode = parentNode.GetParent(bc.blockIndex)
10471061
currBlockCounter++
10481062
}
@@ -1119,6 +1133,7 @@ func NewBlockchain(
11191133
snapshot *Snapshot,
11201134
archivalMode bool,
11211135
checkpointSyncingProviders []string,
1136+
blockIndexSize int,
11221137
) (*Blockchain, error) {
11231138
if err := RunBlockIndexMigrationOnce(db, params); err != nil {
11241139
return nil, errors.Wrapf(err, "NewBlockchain: Problem running block index migration")
@@ -1137,6 +1152,10 @@ func NewBlockchain(
11371152
timer := &Timer{}
11381153
timer.Initialize()
11391154
blockViewCache, _ := collections.NewLruCache[BlockHash, *BlockViewAndUtxoOps](100) // TODO: parameterize
1155+
blockIndex, err := NewBlockIndex(db, snapshot, nil, blockIndexSize) // This tip will be set in _initChain.
1156+
if err != nil {
1157+
return nil, errors.Wrapf(err, "NewBlockchain: Problem creating block index")
1158+
}
11401159
bc := &Blockchain{
11411160
db: db,
11421161
postgres: postgres,
@@ -1149,7 +1168,7 @@ func NewBlockchain(
11491168
eventManager: eventManager,
11501169
archivalMode: archivalMode,
11511170

1152-
blockIndex: NewBlockIndex(db, snapshot, nil), // This tip will be set in _initChain.
1171+
blockIndex: blockIndex,
11531172
blockViewCache: blockViewCache,
11541173
snapshotCache: NewSnapshotCache(),
11551174

lib/blockchain_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func NewTestBlockchain(t *testing.T) (*Blockchain, *DeSoParams, *badger.DB) {
153153
paramsCopy := DeSoTestnetParams
154154

155155
chain, err := NewBlockchain([]string{blockSignerPk}, 0, 0, &paramsCopy,
156-
timesource, db, nil, nil, nil, false, nil)
156+
timesource, db, nil, nil, nil, false, nil, MinBlockIndexSize)
157157
if err != nil {
158158
log.Fatal(err)
159159
}
@@ -255,7 +255,7 @@ func NewLowDifficultyBlockchainWithParamsAndDb(t *testing.T, params *DeSoParams,
255255
}
256256
}
257257
chain, err := NewBlockchain([]string{blockSignerPk}, 0, 0,
258-
&testParams, timesource, db, postgresDb, NewEventManager(), snap, false, nil)
258+
&testParams, timesource, db, postgresDb, NewEventManager(), snap, false, nil, MinBlockIndexSize)
259259
if err != nil {
260260
log.Fatal(err)
261261
}

lib/constants.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,3 +1962,7 @@ const BlockIndexMigrationFileName = "block_index_migration.txt"
19621962

19631963
// BtcecPubKeyBytesLenUncompressed is a constant that was removed from newer version of Btcec
19641964
const BtcecPubKeyBytesLenUncompressed = 65
1965+
1966+
const DefaultBlockIndexSize = MaxBlockIndexNodes
1967+
const MaxBlockIndexSize = 10000000
1968+
const MinBlockIndexSize = 10000

lib/db_utils_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ func TestBlockNodePutGet(t *testing.T) {
195195

196196
// Check that getting the best chain works.
197197
{
198-
bi := NewBlockIndex(db, nil, b4)
198+
bi, err := NewBlockIndex(db, nil, b4, 1000)
199+
require.NoError(err)
199200
bestChain, err := GetBestChain(b3Ret, bi)
200201
require.NoError(err)
201202
require.Len(bestChain, 3)
@@ -229,7 +230,8 @@ func TestInitDbWithGenesisBlock(t *testing.T) {
229230
require.Equal(&genesisHash, genesis.Hash)
230231

231232
// Check the bestChain.
232-
bi := NewBlockIndex(db, nil, genesis)
233+
bi, err := NewBlockIndex(db, nil, genesis, 1000)
234+
require.NoError(err)
233235
bestChain, err := GetBestChain(genesis, bi)
234236
require.NoError(err)
235237
require.Len(bestChain, 1)

lib/pos_blockchain_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func TestHasValidBlockHeight(t *testing.T) {
252252
ValidatorsVoteQC: nil,
253253
ValidatorsTimeoutAggregateQC: nil,
254254
}, StatusBlockStored|StatusBlockValidated)
255-
bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{*genesisBlock.Hash: genesisBlock})
255+
require.NoError(t, bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{*genesisBlock.Hash: genesisBlock}))
256256
bc.blockIndex.blockIndexByHash.Put(*genesisBlock.Hash, genesisBlock)
257257
// Create a block with a valid header.
258258
randomPayload := RandomBytes(256)
@@ -303,7 +303,8 @@ func TestHasValidBlockHeight(t *testing.T) {
303303

304304
block.Header.Height = 2
305305
// TODO: make sure setting to genesis block works.
306-
bc.blockIndex = NewBlockIndex(bc.db, bc.snapshot, genesisBlock)
306+
bc.blockIndex, err = NewBlockIndex(bc.db, bc.snapshot, genesisBlock, 1000)
307+
require.NoError(t, err)
307308
err = bc.hasValidBlockHeightPoS(block.Header)
308309
require.Equal(t, err, RuleErrorMissingParentBlock)
309310
}
@@ -331,10 +332,10 @@ func TestUpsertBlockAndBlockNodeToDB(t *testing.T) {
331332
ValidatorsVoteQC: nil,
332333
ValidatorsTimeoutAggregateQC: nil,
333334
}, StatusBlockStored|StatusBlockValidated)
334-
bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
335+
require.NoError(t, bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
335336
*hash1: genesisNode,
336337
*hash2: block2,
337-
})
338+
}))
338339
randomPayload := RandomBytes(256)
339340
randomBLSPrivateKey := _generateRandomBLSPrivateKey(t)
340341
signature, err := randomBLSPrivateKey.Sign(randomPayload)
@@ -470,10 +471,10 @@ func TestHasValidBlockViewPoS(t *testing.T) {
470471
ValidatorsVoteQC: nil,
471472
ValidatorsTimeoutAggregateQC: nil,
472473
}, StatusBlockStored|StatusBlockValidated)
473-
bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
474+
require.NoError(t, bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
474475
*hash1: genesisNode,
475476
*hash2: block2,
476-
})
477+
}))
477478
randomPayload := RandomBytes(256)
478479
randomBLSPrivateKey := _generateRandomBLSPrivateKey(t)
479480
signature, err := randomBLSPrivateKey.Sign(randomPayload)
@@ -802,9 +803,9 @@ func TestGetLineageFromCommittedTip(t *testing.T) {
802803
Height: 1,
803804
ProposedInView: 1,
804805
}, StatusBlockStored|StatusBlockValidated|StatusBlockCommitted)
805-
bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
806+
require.NoError(t, bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
806807
*hash1: genesisNode,
807-
})
808+
}))
808809
block := &MsgDeSoBlock{
809810
Header: &MsgDeSoHeader{
810811
Version: HeaderVersion2,
@@ -1241,10 +1242,10 @@ func TestShouldReorg(t *testing.T) {
12411242
Height: 1,
12421243
},
12431244
}
1244-
bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
1245+
require.NoError(t, bc.blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
12451246
*hash1: chain[0],
12461247
*hash3: chain[1],
1247-
})
1248+
}))
12481249

12491250
newBlock := &BlockNode{
12501251
Header: &MsgDeSoHeader{

lib/pos_consensus_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,11 @@ func TestFastHotStuffConsensusHandleLocalTimeoutEvent(t *testing.T) {
102102
currentView := blockHeader.ValidatorsVoteQC.GetView() + 1
103103
nextView := currentView + 1
104104

105-
blockIndex := NewBlockIndex(nil, nil, nil)
106-
blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
105+
blockIndex, err := NewBlockIndex(nil, nil, nil, 1000)
106+
require.NoError(t, err)
107+
require.NoError(t, blockIndex.setBlockIndexFromMap(map[BlockHash]*BlockNode{
107108
*blockHash: {Header: blockHeader, Height: uint32(blockHeader.Height), Hash: blockHash},
108-
})
109+
}))
109110

110111
// Create a mock consensus
111112
fastHotStuffConsensus := FastHotStuffConsensus{

lib/server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ func NewServer(
452452
_transactionValidationRefreshIntervalMillis uint64,
453453
_stateSyncerMempoolTxnSyncLimit uint64,
454454
_checkpointSyncingProviders []string,
455+
_blockIndexSize int,
455456
) (
456457
_srv *Server,
457458
_err error,
@@ -548,7 +549,8 @@ func NewServer(
548549

549550
_chain, err := NewBlockchain(
550551
_trustedBlockProducerPublicKeys, _trustedBlockProducerStartHeight, _maxSyncBlockHeight,
551-
_params, timesource, _db, postgres, eventManager, _snapshot, archivalMode, _checkpointSyncingProviders)
552+
_params, timesource, _db, postgres, eventManager, _snapshot, archivalMode, _checkpointSyncingProviders,
553+
_blockIndexSize)
552554
if err != nil {
553555
return nil, errors.Wrapf(err, "NewServer: Problem initializing blockchain"), true
554556
}

lib/txindex.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func NewTXIndex(coreChain *Blockchain, params *DeSoParams, dataDirectory string)
130130
// Note that we *DONT* pass server here because it is already tied to the main blockchain.
131131
txIndexChain, err := NewBlockchain(
132132
[]string{}, 0, coreChain.MaxSyncBlockHeight, params, chainlib.NewMedianTime(),
133-
txIndexDb, nil, nil, nil, false, nil)
133+
txIndexDb, nil, nil, nil, false, nil, coreChain.blockIndex.size)
134134
if err != nil {
135135
return nil, fmt.Errorf("NewTXIndex: Error initializing TxIndex: %v", err)
136136
}

0 commit comments

Comments
 (0)