Skip to content

Commit 5a86f0a

Browse files
authored
Fix calculating storage dict, simplify storage stat code (#1643)
1 parent 0b024a6 commit 5a86f0a

File tree

3 files changed

+47
-35
lines changed

3 files changed

+47
-35
lines changed

crypto/block/account-storage-stat.cpp

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ td::Status AccountStorageStat::replace_roots(std::vector<Ref<vm::Cell>> new_root
6363
for (const Ref<vm::Cell>& root : to_add) {
6464
TRY_RESULT(info, add_cell(root));
6565
if (check_merkle_depth && info.max_merkle_depth > MAX_MERKLE_DEPTH) {
66-
return td::Status::Error("too big Merkle depth");
66+
return td::Status::Error(errorcode_limits_exceeded, "too big Merkle depth");
6767
}
6868
}
6969
for (const Ref<vm::Cell>& root : to_del) {
@@ -92,10 +92,10 @@ void AccountStorageStat::add_hint(const td::HashSet<vm::CellHash>& hint) {
9292
return;
9393
}
9494
}
95+
e.max_merkle_depth = 0;
9596
if (hint.contains(cell->get_hash())) {
9697
bool spec;
9798
vm::CellSlice cs = vm::load_cell_slice_special(cell, spec);
98-
e.size_bits = cs.size();
9999
for (unsigned i = 0; i < cs.size_refs(); ++i) {
100100
dfs(cs.prefetch_ref(i), false);
101101
}
@@ -108,11 +108,11 @@ void AccountStorageStat::add_hint(const td::HashSet<vm::CellHash>& hint) {
108108

109109
td::Result<AccountStorageStat::CellInfo> AccountStorageStat::add_cell(const Ref<vm::Cell>& cell) {
110110
Entry& e = get_entry(cell);
111-
if (!e.exists_known || e.refcnt_diff < 0) {
111+
if (!e.exists_known) {
112112
TRY_STATUS(fetch_from_dict(e));
113113
}
114114
++e.refcnt_diff;
115-
if (e.exists || e.refcnt_diff > 1 || (e.refcnt && e.refcnt.value() + e.refcnt_diff != 1)) {
115+
if (e.exists || e.refcnt_diff > 1) {
116116
if (!e.max_merkle_depth) {
117117
TRY_STATUS(fetch_from_dict(e));
118118
if (!e.max_merkle_depth) {
@@ -125,7 +125,6 @@ td::Result<AccountStorageStat::CellInfo> AccountStorageStat::add_cell(const Ref<
125125
td::uint32 max_merkle_depth = 0;
126126
bool spec;
127127
vm::CellSlice cs = vm::load_cell_slice_special(cell, spec);
128-
e.size_bits = cs.size();
129128
for (unsigned i = 0; i < cs.size_refs(); ++i) {
130129
TRY_RESULT(info, add_cell(cs.prefetch_ref(i)));
131130
max_merkle_depth = std::max(max_merkle_depth, info.max_merkle_depth);
@@ -137,6 +136,8 @@ td::Result<AccountStorageStat::CellInfo> AccountStorageStat::add_cell(const Ref<
137136
max_merkle_depth = std::min(max_merkle_depth, MERKLE_DEPTH_LIMIT);
138137
Entry& e2 = get_entry(cell);
139138
e2.max_merkle_depth = max_merkle_depth;
139+
++total_cells_;
140+
total_bits_ += cs.size();
140141
return CellInfo{max_merkle_depth};
141142
}
142143

@@ -158,16 +159,28 @@ td::Status AccountStorageStat::remove_cell(const Ref<vm::Cell>& cell) {
158159
}
159160
bool spec;
160161
vm::CellSlice cs = vm::load_cell_slice_special(cell, spec);
161-
e.size_bits = cs.size();
162162
for (unsigned i = 0; i < cs.size_refs(); ++i) {
163163
TRY_STATUS(remove_cell(cs.prefetch_ref(i)));
164164
}
165+
--total_cells_;
166+
total_bits_ -= cs.size();
165167
return td::Status::OK();
166168
}
167169

168170
td::Result<Ref<vm::Cell>> AccountStorageStat::get_dict_root() {
169171
if (!dict_up_to_date_) {
170172
std::vector<std::pair<td::ConstBitPtr, Ref<vm::CellBuilder>>> values;
173+
if (parent_ && !parent_->dict_up_to_date_) {
174+
for (auto& [_, ep] : parent_->cache_) {
175+
if (ep.dict_refcnt_diff == 0) {
176+
continue;
177+
}
178+
Entry& e = cache_[ep.hash];
179+
if (!e.inited) {
180+
e = ep;
181+
}
182+
}
183+
}
171184
for (auto& [_, e] : cache_) {
172185
if (e.dict_refcnt_diff == 0) {
173186
continue;
@@ -259,25 +272,9 @@ td::Status AccountStorageStat::finalize_entry(Entry& e) {
259272
e.refcnt.value() += e.refcnt_diff;
260273
e.dict_refcnt_diff += e.refcnt_diff;
261274
e.refcnt_diff = 0;
262-
if (e.refcnt.value() == 0) {
263-
if (!e.size_bits) {
264-
return td::Status::Error(PSTRING() << "Failed to store entry " << e.hash.to_hex() << " : unknown cell bits");
265-
}
266-
--total_cells_;
267-
total_bits_ -= e.size_bits.value();
268-
e.exists = false;
269-
} else {
270-
if (!e.exists) {
271-
if (!e.size_bits) {
272-
return td::Status::Error(PSTRING() << "Failed to store entry " << e.hash.to_hex() << " : unknown cell bits");
273-
}
274-
++total_cells_;
275-
total_bits_ += e.size_bits.value();
276-
}
277-
e.exists = true;
278-
if (!e.max_merkle_depth) {
279-
return td::Status::Error(PSTRING() << "Failed to store entry " << e.hash.to_hex() << " : unknown merkle depth");
280-
}
275+
e.exists = (e.refcnt.value() != 0);
276+
if (e.exists && !e.max_merkle_depth) {
277+
return td::Status::Error(PSTRING() << "Error on entry " << e.hash.to_hex() << " : unknown merkle depth");
281278
}
282279
return td::Status::OK();
283280
}

crypto/block/account-storage-stat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ class AccountStorageStat {
5959

6060
void apply_child_stat(AccountStorageStat &&child);
6161

62+
static constexpr int errorcode_limits_exceeded = 999;
63+
6264
private:
6365
vm::Dictionary dict_;
6466
bool dict_up_to_date_ = true;
@@ -76,7 +78,6 @@ class AccountStorageStat {
7678
struct Entry {
7779
bool inited = false;
7880
vm::CellHash hash;
79-
td::optional<unsigned> size_bits;
8081
bool exists_known = false;
8182
bool exists = false;
8283
td::optional<td::uint32> refcnt, max_merkle_depth;

crypto/block/transaction.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,12 +1930,17 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
19301930
ap.action_fine = td::zero_refint();
19311931

19321932
td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
1933-
auto enforce_state_limits = [&]() {
1933+
// 1 - ok, 0 - limits exceeded, -1 - fatal error
1934+
auto enforce_state_limits = [&]() -> int {
19341935
if (account.is_special) {
1935-
return true;
1936+
return 1;
19361937
}
19371938
auto S = check_state_limits(cfg.size_limits);
19381939
if (S.is_error()) {
1940+
if (S.code() != AccountStorageStat::errorcode_limits_exceeded) {
1941+
LOG(ERROR) << "Account storage stat error: " << S.move_as_error();
1942+
return -1;
1943+
}
19391944
// Rollback changes to state, fail action phase
19401945
LOG(INFO) << "Account state size exceeded limits: " << S.move_as_error();
19411946
new_account_storage_stat = {};
@@ -1944,9 +1949,9 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
19441949
new_library = old_library;
19451950
ap.result_code = 50;
19461951
ap.state_exceeds_limits = true;
1947-
return false;
1952+
return 0;
19481953
}
1949-
return true;
1954+
return 1;
19501955
};
19511956

19521957
int n = 0;
@@ -2057,7 +2062,9 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
20572062
}
20582063
LOG(DEBUG) << "invalid action " << ap.result_arg << " in action list: error code " << ap.result_code;
20592064
// This is required here because changes to libraries are applied even if action phase fails
2060-
enforce_state_limits();
2065+
if (enforce_state_limits() == -1) {
2066+
return false;
2067+
}
20612068
if (cfg.action_fine_enabled) {
20622069
ap.action_fine = std::min(ap.action_fine, balance.grams);
20632070
ap.total_action_fees = ap.action_fine;
@@ -2079,7 +2086,11 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
20792086
new_code = ap.new_code;
20802087
}
20812088
new_data = compute_phase->new_data; // tentative persistent data update applied
2082-
if (!enforce_state_limits()) {
2089+
int res = enforce_state_limits();
2090+
if (res == -1) {
2091+
return false;
2092+
}
2093+
if (res == 0) {
20832094
if (cfg.extra_currency_v2) {
20842095
end_lt = ap.end_lt = start_lt + 1;
20852096
if (cfg.action_fine_enabled) {
@@ -3054,7 +3065,8 @@ static td::uint32 get_public_libraries_diff_count(const td::Ref<vm::Cell>& old_l
30543065
*
30553066
* @returns A `td::Status` indicating the result of the check.
30563067
* - If the state limits are within the allowed range, returns OK.
3057-
* - If the state limits exceed the maximum allowed range, returns an error.
3068+
* - If the state limits exceed the maximum allowed range, returns an error with AccountStorageStat::errorcode_limits_exceeded code.
3069+
* - If an error occurred during storage stat calculation, returns other error.
30583070
*/
30593071
td::Status Transaction::check_state_limits(const SizeLimitsConfig& size_limits, bool update_storage_stat) {
30603072
auto cell_equal = [](const td::Ref<vm::Cell>& a, const td::Ref<vm::Cell>& b) -> bool {
@@ -3079,15 +3091,17 @@ td::Status Transaction::check_state_limits(const SizeLimitsConfig& size_limits,
30793091

30803092
if (storage_stat.get_total_cells() > size_limits.max_acc_state_cells ||
30813093
storage_stat.get_total_bits() > size_limits.max_acc_state_bits) {
3082-
return td::Status::Error(PSTRING() << "account state is too big: cells=" << storage_stat.get_total_cells()
3094+
return td::Status::Error(AccountStorageStat::errorcode_limits_exceeded,
3095+
PSTRING() << "account state is too big: cells=" << storage_stat.get_total_cells()
30833096
<< ", bits=" << storage_stat.get_total_bits()
30843097
<< " (max cells=" << size_limits.max_acc_state_cells
30853098
<< ", max bits=" << size_limits.max_acc_state_bits << ")");
30863099
}
30873100
if (account.is_masterchain() && !cell_equal(account.library, new_library)) {
30883101
auto libraries_count = get_public_libraries_count(new_library);
30893102
if (libraries_count > size_limits.max_acc_public_libraries) {
3090-
return td::Status::Error(PSTRING() << "too many public libraries: " << libraries_count << " (max "
3103+
return td::Status::Error(AccountStorageStat::errorcode_limits_exceeded,
3104+
PSTRING() << "too many public libraries: " << libraries_count << " (max "
30913105
<< size_limits.max_acc_public_libraries << ")");
30923106
}
30933107
}

0 commit comments

Comments
 (0)