Skip to content

Commit 1da78e3

Browse files
committed
datastore: move step converters to db
1 parent bf0652f commit 1da78e3

22 files changed

+296
-161
lines changed

cmd/dev/staged_pipeline.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,10 @@ void debug_unwind(datastore::kvdb::EnvConfig& config, BlockNum height, uint32_t
371371
// Unwind has just set progress for pre-Execution stages back to unwind_point even if it is within the snapshots
372372
// We need to reset progress for such stages to the max block in snapshots to avoid database update on next start
373373
auto& blocks_repository = data_store.blocks_repository();
374-
db::stages::write_stage_progress(txn, db::stages::kHeadersKey, blocks_repository.max_block_available());
375-
db::stages::write_stage_progress(txn, db::stages::kBlockBodiesKey, blocks_repository.max_block_available());
376-
db::stages::write_stage_progress(txn, db::stages::kBlockHashesKey, blocks_repository.max_block_available());
377-
db::stages::write_stage_progress(txn, db::stages::kSendersKey, blocks_repository.max_block_available());
374+
db::stages::write_stage_progress(txn, db::stages::kHeadersKey, blocks_repository.max_timestamp_available());
375+
db::stages::write_stage_progress(txn, db::stages::kBlockBodiesKey, blocks_repository.max_timestamp_available());
376+
db::stages::write_stage_progress(txn, db::stages::kBlockHashesKey, blocks_repository.max_timestamp_available());
377+
db::stages::write_stage_progress(txn, db::stages::kSendersKey, blocks_repository.max_timestamp_available());
378378

379379
txn.commit_and_stop();
380380
}

silkworm/db/access_layer.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -1064,20 +1064,20 @@ BlockNum DataModel::max_block_num() const {
10641064
}
10651065

10661066
// If none is found on db, then ask the snapshot repository (if any) for max block
1067-
return repository_.max_block_available();
1067+
return repository_.max_timestamp_available();
10681068
}
10691069

10701070
BlockNum DataModel::max_frozen_block_num() const {
10711071
// Ask the snapshot repository (if any) for max block
1072-
return repository_.max_block_available();
1072+
return repository_.max_timestamp_available();
10731073
}
10741074

10751075
std::optional<BlockHeader> DataModel::read_header(BlockNum block_num, HashAsArray hash) const {
10761076
return read_header(block_num, Hash(hash));
10771077
}
10781078

10791079
std::optional<BlockHeader> DataModel::read_header(BlockNum block_num, const Hash& hash) const {
1080-
BlockNum repository_max_block_num = repository_.max_block_available();
1080+
BlockNum repository_max_block_num = repository_.max_timestamp_available();
10811081
if ((repository_max_block_num > 0) && (block_num <= repository_max_block_num)) {
10821082
auto header = read_header_from_snapshot(block_num);
10831083
if (header && header->hash() == hash) { // reading using hash avoid this heavy hash calculation
@@ -1089,7 +1089,7 @@ std::optional<BlockHeader> DataModel::read_header(BlockNum block_num, const Hash
10891089
}
10901090

10911091
std::optional<BlockHeader> DataModel::read_header(BlockNum block_num) const {
1092-
BlockNum repository_max_block_num = repository_.max_block_available();
1092+
BlockNum repository_max_block_num = repository_.max_timestamp_available();
10931093
if ((repository_max_block_num > 0) && (block_num <= repository_max_block_num)) {
10941094
return read_header_from_snapshot(block_num);
10951095
}
@@ -1256,7 +1256,7 @@ void DataModel::for_last_n_headers(size_t n, absl::FunctionRef<void(BlockHeader)
12561256
return;
12571257
}
12581258

1259-
auto block_num_in_snapshots = repository_.max_block_available();
1259+
BlockNum block_num_in_snapshots = repository_.max_timestamp_available();
12601260

12611261
// We've reached the first header in db but still need to read more from snapshots
12621262
if (last_read_block_num_from_db > 0) {

silkworm/db/blocks/schema_config.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "schema_config.hpp"
1818

1919
#include "blocks_index_builders_factory.hpp"
20+
#include "step_block_num_converter.hpp"
2021

2122
namespace silkworm::db::blocks {
2223

@@ -65,7 +66,7 @@ snapshots::SnapshotRepository make_blocks_repository(
6566
std::move(dir_path),
6667
open,
6768
make_blocks_repository_schema(),
68-
std::make_unique<datastore::StepToBlockNumConverter>(),
69+
std::make_unique<StepToBlockNumConverter>(),
6970
index_salt,
7071
make_blocks_index_builders_factory(),
7172
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
Copyright 2025 The Silkworm Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <silkworm/core/common/base.hpp>
20+
#include <silkworm/db/datastore/common/step.hpp>
21+
22+
namespace silkworm::db::blocks {
23+
24+
struct StepToBlockNumConverter : public datastore::StepToTimestampConverter {
25+
using Step = datastore::Step;
26+
using StepRange = datastore::StepRange;
27+
using Timestamp = datastore::Timestamp;
28+
using TimestampRange = datastore::TimestampRange;
29+
static constexpr size_t kStepSize = datastore::kStepSizeForBlockSnapshots;
30+
31+
~StepToBlockNumConverter() override = default;
32+
33+
Step step_from_timestamp(Timestamp t) const override {
34+
if (t == datastore::kMaxTimestamp) return datastore::kMaxStep;
35+
return Step{static_cast<size_t>(t / kStepSize)};
36+
}
37+
38+
Timestamp timestamp_from_step(Step s) const override {
39+
if (s == datastore::kMaxStep) return datastore::kMaxTimestamp;
40+
return s.value * kStepSize;
41+
}
42+
43+
StepRange step_range_from_timestamp_range(TimestampRange range) const override {
44+
if (range.end == datastore::kMaxTimestamp) {
45+
return StepRange{step_from_timestamp(range.start), datastore::kMaxStep};
46+
}
47+
ensure(range.end <= datastore::kMaxTimestamp - kStepSize + 1, "step_range_from_timestamp_range: end step overflow");
48+
Step end = step_from_timestamp(range.end + kStepSize - 1);
49+
return StepRange{step_from_timestamp(range.start), end};
50+
}
51+
52+
TimestampRange timestamp_range_from_step_range(StepRange range) const override {
53+
return TimestampRange{timestamp_from_step(range.start), timestamp_from_step(range.end)};
54+
}
55+
56+
StepRange step_range_from_block_num_range(BlockNumRange range) const {
57+
return step_range_from_timestamp_range({range.start, range.end});
58+
}
59+
60+
BlockNumRange block_num_range_from_step_range(StepRange range) const {
61+
TimestampRange ts_range = timestamp_range_from_step_range(range);
62+
return BlockNumRange{ts_range.start, ts_range.end};
63+
}
64+
};
65+
66+
} // namespace silkworm::db::blocks
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Copyright 2025 The Silkworm Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#include "step_block_num_converter.hpp"
18+
19+
#include <catch2/catch_test_macros.hpp>
20+
21+
namespace silkworm::db::blocks {
22+
23+
using namespace silkworm::datastore;
24+
25+
TEST_CASE("StepToBlockNumConverter") {
26+
StepToBlockNumConverter converter;
27+
static constexpr size_t kStepSize = StepToBlockNumConverter::kStepSize;
28+
29+
SECTION("Step to Timestamp and back") {
30+
Step step{10};
31+
Timestamp ts = converter.timestamp_from_step(step);
32+
CHECK(ts == kStepSize * 10);
33+
CHECK(converter.step_from_timestamp(ts) == step);
34+
35+
CHECK(converter.timestamp_from_step(Step{0}) == 0);
36+
CHECK(converter.timestamp_from_step(Step{500}) == kStepSize * 500);
37+
}
38+
39+
SECTION("Step limits") {
40+
CHECK(converter.step_from_timestamp(kMaxTimestamp) == kMaxStep);
41+
CHECK(converter.timestamp_from_step(kMaxStep) == kMaxTimestamp);
42+
}
43+
44+
SECTION("StepRange to TimestampRange and back") {
45+
StepRange range{Step{10}, Step{20}};
46+
const TimestampRange ts_range = converter.timestamp_range_from_step_range(range);
47+
CHECK(ts_range == TimestampRange{kStepSize * 10, kStepSize * 20});
48+
CHECK(converter.step_range_from_timestamp_range(ts_range) == range);
49+
50+
CHECK(converter.timestamp_range_from_step_range({Step{0}, Step{0}}) == TimestampRange{0, 0});
51+
CHECK(converter.timestamp_range_from_step_range({Step{0}, Step{500}}) == TimestampRange{0, kStepSize * 500});
52+
}
53+
54+
SECTION("StepRange limits") {
55+
CHECK(converter.step_range_from_timestamp_range({kMaxTimestamp, kMaxTimestamp}) == StepRange{kMaxStep, kMaxStep});
56+
CHECK(converter.timestamp_range_from_step_range({kMaxStep, kMaxStep}) == TimestampRange{kMaxTimestamp, kMaxTimestamp});
57+
CHECK_THROWS(converter.step_range_from_timestamp_range({0, kMaxTimestamp - 1}));
58+
}
59+
}
60+
61+
} // namespace silkworm::db::blocks

silkworm/db/datastore/common/step.hpp

+3-58
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,20 @@ namespace silkworm::datastore {
2626
//! Scale factor to convert from-to block number values in block snapshot file names
2727
inline constexpr size_t kStepSizeForBlockSnapshots = 1'000;
2828

29-
//! Scale factor to convert from-to txn id values in temporal snapshot file names
30-
inline constexpr size_t kStepSizeForTemporalSnapshots = 1'562'500; // = 100M / 64
31-
3229
struct Step {
3330
size_t value;
3431

35-
explicit Step(size_t value1) : value(value1) {}
32+
constexpr explicit Step(size_t value1) : value(value1) {}
3633
friend bool operator==(const Step&, const Step&) = default;
3734
bool operator<(const Step& other) const { return this->value < other.value; }
3835
bool operator<=(const Step& other) const { return this->value <= other.value; }
3936
std::string to_string() const { return std::to_string(value) + "st"; }
4037

4138
BlockNum to_block_num() const { return value * kStepSizeForBlockSnapshots; }
42-
static Step from_block_num(BlockNum block_num) {
43-
return Step{static_cast<size_t>(block_num / kStepSizeForBlockSnapshots)};
44-
}
45-
46-
TxnId to_txn_id() const { return value * kStepSizeForTemporalSnapshots; }
47-
static Step from_txn_id(TxnId txn_id) {
48-
return Step{static_cast<size_t>(txn_id / kStepSizeForTemporalSnapshots)};
49-
}
5039
};
5140

41+
inline constexpr Step kMaxStep{std::numeric_limits<size_t>::max()};
42+
5243
struct StepRange {
5344
Step start;
5445
Step end;
@@ -63,18 +54,6 @@ struct StepRange {
6354
std::string to_string() const { return std::string("[") + start.to_string() + ", " + end.to_string() + ")"; }
6455

6556
BlockNumRange to_block_num_range() const { return {start.to_block_num(), end.to_block_num()}; }
66-
static StepRange from_block_num_range(BlockNumRange range) {
67-
return {Step::from_block_num(range.start),
68-
Step::from_block_num(range.end >= kMaxBlockNum - kStepSizeForBlockSnapshots + 1 ? kMaxBlockNum
69-
: range.end + kStepSizeForBlockSnapshots - 1)};
70-
}
71-
72-
TxnIdRange to_txn_id_range() const { return {start.to_txn_id(), end.to_txn_id()}; }
73-
static StepRange from_txn_id_range(TxnIdRange range) {
74-
return {Step::from_txn_id(range.start),
75-
Step::from_txn_id(range.end >= kMaxTxnId - kStepSizeForTemporalSnapshots + 1 ? kMaxTxnId
76-
: range.end + kStepSizeForTemporalSnapshots - 1)};
77-
}
7857
};
7958

8059
struct StepToTimestampConverter {
@@ -85,38 +64,4 @@ struct StepToTimestampConverter {
8564
virtual TimestampRange timestamp_range_from_step_range(StepRange range) const = 0;
8665
};
8766

88-
struct StepToBlockNumConverter : public StepToTimestampConverter {
89-
~StepToBlockNumConverter() override = default;
90-
Step step_from_timestamp(Timestamp t) const override {
91-
return Step::from_block_num(t);
92-
}
93-
Timestamp timestamp_from_step(Step s) const override {
94-
return s.to_block_num();
95-
}
96-
StepRange step_range_from_timestamp_range(TimestampRange range) const override {
97-
return StepRange::from_block_num_range({range.start, range.end});
98-
}
99-
TimestampRange timestamp_range_from_step_range(StepRange range) const override {
100-
auto r = range.to_block_num_range();
101-
return {r.start, r.end};
102-
}
103-
};
104-
105-
struct StepToTxnIdConverter : public StepToTimestampConverter {
106-
~StepToTxnIdConverter() override = default;
107-
Step step_from_timestamp(Timestamp t) const override {
108-
return Step::from_txn_id(t);
109-
}
110-
Timestamp timestamp_from_step(Step s) const override {
111-
return s.to_txn_id();
112-
}
113-
StepRange step_range_from_timestamp_range(TimestampRange range) const override {
114-
return StepRange::from_txn_id_range({range.start, range.end});
115-
}
116-
TimestampRange timestamp_range_from_step_range(StepRange range) const override {
117-
auto r = range.to_txn_id_range();
118-
return {r.start, r.end};
119-
}
120-
};
121-
12267
} // namespace silkworm::datastore

silkworm/db/datastore/common/step_test.cpp

+4-65
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@
2121
namespace silkworm::datastore {
2222

2323
TEST_CASE("Step", "[datastore][common]") {
24-
CHECK(Step{0}.to_block_num() == 0);
25-
CHECK(Step{500}.to_block_num() == 500'000);
26-
27-
CHECK(Step{0}.to_txn_id() == 0);
28-
CHECK(Step{64}.to_txn_id() == 100'000'000);
29-
3024
SECTION("Step constructor and value") {
3125
Step step{10};
3226
CHECK(step.value == 10);
@@ -45,36 +39,17 @@ TEST_CASE("Step", "[datastore][common]") {
4539
Step step{100};
4640
CHECK(step.to_string() == "100st");
4741
}
48-
49-
SECTION("Step to BlockNum and back") {
50-
Step step{10};
51-
BlockNum block_num = step.to_block_num();
52-
CHECK(block_num == 10'000); // 10 * 1000 = 10000
53-
CHECK(Step::from_block_num(block_num).value == 10);
54-
}
55-
56-
SECTION("Step to TxnId and back") {
57-
Step step{10};
58-
TxnId txn_id = step.to_txn_id();
59-
CHECK(txn_id == 15'625'000); // 10 * 1562500 = 15625000
60-
CHECK(Step::from_txn_id(txn_id).value == 10);
61-
}
62-
63-
SECTION("Step limits") {
64-
CHECK(Step::from_block_num(kMaxBlockNum).value == kMaxBlockNum / kStepSizeForBlockSnapshots);
65-
CHECK(Step::from_txn_id(kMaxTxnId).value == kMaxTxnId / kStepSizeForTemporalSnapshots);
66-
}
6742
}
6843

6944
TEST_CASE("StepRange", "[datastore][common]") {
70-
CHECK(StepRange{Step{0}, Step{0}}.to_block_num_range() == BlockNumRange{0, 0});
71-
CHECK(StepRange{Step{0}, Step{500}}.to_block_num_range() == BlockNumRange{0, 500'000});
72-
7345
StepRange range(Step{10}, Step{20});
7446

75-
SECTION("StepRange constructor and containment") {
47+
SECTION("StepRange constructor") {
7648
CHECK(range.start.value == 10);
7749
CHECK(range.end.value == 20);
50+
}
51+
52+
SECTION("StepRange containment") {
7853
CHECK(range.contains(Step{15}));
7954
CHECK_FALSE(range.contains(Step{25}));
8055
}
@@ -86,42 +61,6 @@ TEST_CASE("StepRange", "[datastore][common]") {
8661
SECTION("StepRange to string") {
8762
CHECK(range.to_string() == "[10st, 20st)");
8863
}
89-
90-
SECTION("StepRange to BlockNumRange and back") {
91-
const BlockNumRange block_range = range.to_block_num_range();
92-
CHECK(block_range.start == 10000);
93-
CHECK(block_range.end == 20000);
94-
95-
const StepRange step_range = StepRange::from_block_num_range(block_range);
96-
CHECK(step_range.start.value == 10);
97-
CHECK(step_range.end.value == 20);
98-
}
99-
100-
SECTION("StepRange to TxnIdRange and back") {
101-
const TxnIdRange txn_range = range.to_txn_id_range();
102-
CHECK(txn_range.start == 15625000);
103-
CHECK(txn_range.end == 31250000);
104-
105-
const StepRange restored_range = StepRange::from_txn_id_range(txn_range);
106-
CHECK(restored_range.start.value == 10);
107-
CHECK(restored_range.end.value == 20);
108-
}
109-
110-
SECTION("StepRange limits") {
111-
const StepRange r1 = StepRange::from_block_num_range(BlockNumRange{0, kMaxBlockNum - kStepSizeForBlockSnapshots + 2});
112-
CHECK(r1.end.value == kMaxBlockNum / kStepSizeForBlockSnapshots);
113-
114-
const StepRange r2 = StepRange::from_txn_id_range(TxnIdRange{0, kMaxTxnId - kStepSizeForTemporalSnapshots + 2});
115-
CHECK(r2.end.value == kMaxTxnId / kStepSizeForTemporalSnapshots);
116-
117-
const StepRange r3 = StepRange::from_block_num_range(BlockNumRange{kMaxBlockNum, kMaxBlockNum});
118-
CHECK(r3.start.value == kMaxBlockNum / kStepSizeForBlockSnapshots);
119-
CHECK(r3.end.value == kMaxBlockNum / kStepSizeForBlockSnapshots);
120-
121-
const StepRange r4 = StepRange::from_txn_id_range(TxnIdRange{kMaxTxnId, kMaxTxnId});
122-
CHECK(r4.start.value == kMaxTxnId / kStepSizeForTemporalSnapshots);
123-
CHECK(r4.end.value == kMaxTxnId / kStepSizeForTemporalSnapshots);
124-
}
12564
}
12665

12766
} // namespace silkworm::datastore

silkworm/db/datastore/common/timestamp.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace silkworm::datastore {
2424

2525
using Timestamp = uint64_t;
2626

27-
constexpr auto kMaxTimestamp = std::numeric_limits<Timestamp>::max();
27+
inline constexpr Timestamp kMaxTimestamp = std::numeric_limits<Timestamp>::max();
2828

2929
struct TimestampRange {
3030
Timestamp start;

0 commit comments

Comments
 (0)