mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 19:22:37 +00:00
Limit maximal Merkle depth (#626)
This commit is contained in:
parent
0578cb4a42
commit
706be23c83
12 changed files with 196 additions and 84 deletions
|
@ -308,7 +308,7 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, R
|
|||
THRERR("cannot create smart-contract AccountStorage");
|
||||
Ref<vm::DataCell> storage = cb.finalize();
|
||||
vm::CellStorageStat stats;
|
||||
PDO(stats.compute_used_storage(Ref<vm::Cell>(storage)));
|
||||
PDO(stats.compute_used_storage(Ref<vm::Cell>(storage)).is_ok());
|
||||
if (verbosity > 2) {
|
||||
std::cerr << "storage is:\n";
|
||||
vm::load_cell_slice(storage).print_rec(std::cerr);
|
||||
|
|
|
@ -590,15 +590,19 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig*
|
|||
in_msg_type = 2;
|
||||
in_msg_extern = true;
|
||||
// compute forwarding fees for this external message
|
||||
vm::CellStorageStat sstat; // for message size
|
||||
sstat.compute_used_storage(cs); // message body
|
||||
sstat.bits -= cs.size(); // bits in the root cells are free
|
||||
sstat.cells--; // the root cell itself is not counted as a cell
|
||||
vm::CellStorageStat sstat; // for message size
|
||||
auto cell_info = sstat.compute_used_storage(cs).move_as_ok(); // message body
|
||||
sstat.bits -= cs.size(); // bits in the root cells are free
|
||||
sstat.cells--; // the root cell itself is not counted as a cell
|
||||
LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
|
||||
if (sstat.bits > cfg->size_limits.max_msg_bits || sstat.cells > cfg->size_limits.max_msg_cells) {
|
||||
LOG(DEBUG) << "inbound external message too large, invalid";
|
||||
return false;
|
||||
}
|
||||
if (cell_info.max_merkle_depth > max_allowed_merkle_depth) {
|
||||
LOG(DEBUG) << "inbound external message has too big merkle depth, invalid";
|
||||
return false;
|
||||
}
|
||||
// fetch message pricing info
|
||||
CHECK(cfg);
|
||||
const MsgPrices& msg_prices = cfg->fetch_msg_prices(account.is_masterchain());
|
||||
|
@ -1157,19 +1161,20 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
|
|||
ap.reserved_balance.set_zero();
|
||||
|
||||
td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
|
||||
auto enforce_state_size_limits = [&]() {
|
||||
auto enforce_state_limits = [&]() {
|
||||
if (account.is_special) {
|
||||
return true;
|
||||
}
|
||||
if (!check_state_size_limit(cfg)) {
|
||||
auto S = check_state_limits(cfg);
|
||||
if (S.is_error()) {
|
||||
// Rollback changes to state, fail action phase
|
||||
LOG(INFO) << "Account state size exceeded limits";
|
||||
LOG(INFO) << "Account state size exceeded limits: " << S.move_as_error();
|
||||
new_storage_stat.clear();
|
||||
new_code = old_code;
|
||||
new_data = old_data;
|
||||
new_library = old_library;
|
||||
ap.result_code = 50;
|
||||
ap.state_size_too_big = true;
|
||||
ap.state_exceeds_limits = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1250,8 +1255,8 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
|
|||
ap.no_funds = true;
|
||||
}
|
||||
LOG(DEBUG) << "invalid action " << ap.result_arg << " in action list: error code " << ap.result_code;
|
||||
// This is reuqired here because changes to libraries are applied even if actipn phase fails
|
||||
enforce_state_size_limits();
|
||||
// This is reuqired here because changes to libraries are applied even if action phase fails
|
||||
enforce_state_limits();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1261,7 +1266,7 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
|
|||
new_code = ap.new_code;
|
||||
}
|
||||
new_data = compute_phase->new_data; // tentative persistent data update applied
|
||||
if (!enforce_state_size_limits()) {
|
||||
if (!enforce_state_limits()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1334,8 +1339,8 @@ int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, c
|
|||
return 41;
|
||||
}
|
||||
vm::CellStorageStat sstat;
|
||||
sstat.compute_used_storage(lib_ref);
|
||||
if (sstat.cells > cfg.size_limits.max_library_cells) {
|
||||
auto cell_info = sstat.compute_used_storage(lib_ref).move_as_ok();
|
||||
if (sstat.cells > cfg.size_limits.max_library_cells || cell_info.max_merkle_depth > max_allowed_merkle_depth) {
|
||||
return 43;
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
|
@ -1608,16 +1613,27 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
// compute size of message
|
||||
vm::CellStorageStat sstat; // for message size
|
||||
// preliminary storage estimation of the resulting message
|
||||
sstat.add_used_storage(msg.init, true, 3); // message init
|
||||
sstat.add_used_storage(msg.body, true, 3); // message body (the root cell itself is not counted)
|
||||
unsigned max_merkle_depth = 0;
|
||||
auto add_used_storage = [&](const auto& x, unsigned skip_root_count) {
|
||||
if (x.not_null()) {
|
||||
auto res = sstat.add_used_storage(x, true, skip_root_count).move_as_ok();
|
||||
max_merkle_depth = std::max(max_merkle_depth, res.max_merkle_depth);
|
||||
}
|
||||
};
|
||||
add_used_storage(msg.init, 3); // message init
|
||||
add_used_storage(msg.body, 3); // message body (the root cell itself is not counted)
|
||||
if (!ext_msg) {
|
||||
sstat.add_used_storage(info.value->prefetch_ref());
|
||||
add_used_storage(info.value->prefetch_ref(), 0);
|
||||
}
|
||||
LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits";
|
||||
if (sstat.bits > cfg.size_limits.max_msg_bits || sstat.cells > cfg.size_limits.max_msg_cells) {
|
||||
LOG(DEBUG) << "message too large, invalid";
|
||||
return skip_invalid ? 0 : 40;
|
||||
}
|
||||
if (max_merkle_depth > max_allowed_merkle_depth) {
|
||||
LOG(DEBUG) << "message has too big merkle depth, invalid";
|
||||
return skip_invalid ? 0 : 40;
|
||||
}
|
||||
|
||||
// compute forwarding fees
|
||||
auto fees_c = msg_prices.compute_fwd_ihr_fees(sstat.cells, sstat.bits, info.ihr_disabled);
|
||||
|
@ -1869,7 +1885,7 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) {
|
||||
td::Status Transaction::check_state_limits(const ActionPhaseConfig& cfg) {
|
||||
auto cell_equal = [](const td::Ref<vm::Cell>& a, const td::Ref<vm::Cell>& b) -> bool {
|
||||
if (a.is_null()) {
|
||||
return b.is_null();
|
||||
|
@ -1881,21 +1897,36 @@ bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) {
|
|||
};
|
||||
if (cell_equal(account.code, new_code) && cell_equal(account.data, new_data) &&
|
||||
cell_equal(account.library, new_library)) {
|
||||
return true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
// new_storage_stat is used here beause these stats will be reused in compute_state()
|
||||
new_storage_stat.limit_cells = cfg.size_limits.max_acc_state_cells;
|
||||
new_storage_stat.limit_bits = cfg.size_limits.max_acc_state_bits;
|
||||
new_storage_stat.add_used_storage(new_code);
|
||||
new_storage_stat.add_used_storage(new_data);
|
||||
new_storage_stat.add_used_storage(new_library);
|
||||
td::Timer timer;
|
||||
auto add_used_storage = [&](const td::Ref<vm::Cell>& cell) -> td::Status {
|
||||
if (cell.not_null()) {
|
||||
TRY_RESULT(res, new_storage_stat.add_used_storage(cell));
|
||||
if (res.max_merkle_depth > max_allowed_merkle_depth) {
|
||||
return td::Status::Error("too big merkle depth");
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
};
|
||||
TRY_STATUS(add_used_storage(new_code));
|
||||
TRY_STATUS(add_used_storage(new_data));
|
||||
TRY_STATUS(add_used_storage(new_library));
|
||||
if (timer.elapsed() > 0.1) {
|
||||
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
|
||||
}
|
||||
if (acc_status == Account::acc_active) {
|
||||
new_storage_stat.clear_limit();
|
||||
} else {
|
||||
new_storage_stat.clear();
|
||||
}
|
||||
return new_storage_stat.cells <= cfg.size_limits.max_acc_state_cells &&
|
||||
new_storage_stat.bits <= cfg.size_limits.max_acc_state_bits;
|
||||
new_storage_stat.bits <= cfg.size_limits.max_acc_state_bits
|
||||
? td::Status::OK()
|
||||
: td::Status::Error("state too big");
|
||||
}
|
||||
|
||||
bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
|
||||
|
@ -2124,7 +2155,7 @@ bool Transaction::compute_state() {
|
|||
stats = new_stats.unwrap();
|
||||
} else {
|
||||
td::Timer timer;
|
||||
CHECK(stats.add_used_storage(Ref<vm::Cell>(storage)));
|
||||
stats.add_used_storage(Ref<vm::Cell>(storage)).ensure();
|
||||
if (timer.elapsed() > 0.1) {
|
||||
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ struct ActionPhase {
|
|||
bool code_changed{false};
|
||||
bool action_list_invalid{false};
|
||||
bool acc_delete_req{false};
|
||||
bool state_size_too_big{false};
|
||||
bool state_exceeds_limits{false};
|
||||
enum { acst_unchanged = 0, acst_frozen = 2, acst_deleted = 3 };
|
||||
int acc_status_change{acst_unchanged};
|
||||
td::RefInt256 total_fwd_fees; // all fees debited from the account
|
||||
|
@ -295,6 +295,7 @@ struct Account {
|
|||
|
||||
namespace transaction {
|
||||
struct Transaction {
|
||||
static constexpr unsigned max_allowed_merkle_depth = 2;
|
||||
enum {
|
||||
tr_none,
|
||||
tr_ord,
|
||||
|
@ -360,7 +361,7 @@ struct Transaction {
|
|||
std::vector<Ref<vm::Cell>> compute_vm_libraries(const ComputePhaseConfig& cfg);
|
||||
bool prepare_compute_phase(const ComputePhaseConfig& cfg);
|
||||
bool prepare_action_phase(const ActionPhaseConfig& cfg);
|
||||
bool check_state_size_limit(const ActionPhaseConfig& cfg);
|
||||
td::Status check_state_limits(const ActionPhaseConfig& cfg);
|
||||
bool prepare_bounce_phase(const ActionPhaseConfig& cfg);
|
||||
bool compute_state();
|
||||
bool serialize();
|
||||
|
|
|
@ -1008,27 +1008,40 @@ td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> roots
|
|||
*
|
||||
*/
|
||||
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cs_ref), kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(std::move(cs_ref), kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(cs, kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(cs, kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cs), kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(std::move(cs), kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cell), kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(std::move(cell), kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (cs_ref->is_unique()) {
|
||||
return add_used_storage(std::move(cs_ref.unique_write()), kill_dup, skip_count_root);
|
||||
} else {
|
||||
|
@ -1036,56 +1049,67 @@ bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
|||
}
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (!(skip_count_root & 1)) {
|
||||
++cells;
|
||||
if (cells > limit_cells) {
|
||||
return false;
|
||||
return td::Status::Error("too many cells");
|
||||
}
|
||||
}
|
||||
if (!(skip_count_root & 2)) {
|
||||
bits += cs.size();
|
||||
if (bits > limit_bits) {
|
||||
return false;
|
||||
return td::Status::Error("too many bits");
|
||||
}
|
||||
}
|
||||
CellInfo res;
|
||||
for (unsigned i = 0; i < cs.size_refs(); i++) {
|
||||
if (!add_used_storage(cs.prefetch_ref(i), kill_dup)) {
|
||||
return false;
|
||||
}
|
||||
TRY_RESULT(child, add_used_storage(cs.prefetch_ref(i), kill_dup));
|
||||
res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth);
|
||||
}
|
||||
return true;
|
||||
if (cs.special_type() == CellTraits::SpecialType::MerkleProof ||
|
||||
cs.special_type() == CellTraits::SpecialType::MerkleUpdate) {
|
||||
++res.max_merkle_depth;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (!(skip_count_root & 1)) {
|
||||
++cells;
|
||||
if (cells > limit_cells) {
|
||||
return false;
|
||||
return td::Status::Error("too many cells");
|
||||
}
|
||||
}
|
||||
if (!(skip_count_root & 2)) {
|
||||
bits += cs.size();
|
||||
if (bits > limit_bits) {
|
||||
return false;
|
||||
return td::Status::Error("too many bits");
|
||||
}
|
||||
}
|
||||
CellInfo res;
|
||||
while (cs.size_refs()) {
|
||||
if (!add_used_storage(cs.fetch_ref(), kill_dup)) {
|
||||
return false;
|
||||
}
|
||||
TRY_RESULT(child, add_used_storage(cs.fetch_ref(), kill_dup));
|
||||
res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth);
|
||||
}
|
||||
return true;
|
||||
if (cs.special_type() == CellTraits::SpecialType::MerkleProof ||
|
||||
cs.special_type() == CellTraits::SpecialType::MerkleUpdate) {
|
||||
++res.max_merkle_depth;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (cell.is_null()) {
|
||||
return false;
|
||||
return td::Status::Error("cell is null");
|
||||
}
|
||||
if (kill_dup) {
|
||||
auto ins = seen.insert(cell->get_hash());
|
||||
auto ins = seen.emplace(cell->get_hash(), CellInfo{});
|
||||
if (!ins.second) {
|
||||
return true;
|
||||
return ins.first->second;
|
||||
}
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVm{}, std::move(cell)};
|
||||
|
|
|
@ -108,12 +108,14 @@ struct CellStorageStat {
|
|||
unsigned long long cells;
|
||||
unsigned long long bits;
|
||||
unsigned long long public_cells;
|
||||
std::set<vm::Cell::Hash> seen;
|
||||
struct CellInfo {
|
||||
td::uint32 max_merkle_depth = 0;
|
||||
};
|
||||
std::map<vm::Cell::Hash, CellInfo> seen;
|
||||
CellStorageStat() : cells(0), bits(0), public_cells(0) {
|
||||
}
|
||||
bool clear_seen() {
|
||||
void clear_seen() {
|
||||
seen.clear();
|
||||
return true;
|
||||
}
|
||||
void clear() {
|
||||
cells = bits = public_cells = 0;
|
||||
|
@ -124,15 +126,16 @@ struct CellStorageStat {
|
|||
limit_cells = std::numeric_limits<unsigned long long>::max();
|
||||
limit_bits = std::numeric_limits<unsigned long long>::max();
|
||||
}
|
||||
bool compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true,
|
||||
unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
|
||||
bool add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
|
||||
unsigned long long limit_cells = std::numeric_limits<unsigned long long>::max();
|
||||
unsigned long long limit_bits = std::numeric_limits<unsigned long long>::max();
|
||||
|
|
|
@ -39,7 +39,13 @@ class MerkleProofImpl {
|
|||
dfs_usage_tree(cell, usage_tree_->root_id());
|
||||
is_prunned_ = [this](const Ref<Cell> &cell) { return visited_cells_.count(cell->get_hash()) == 0; };
|
||||
}
|
||||
return dfs(cell, cell->get_level());
|
||||
try {
|
||||
return dfs(cell, cell->get_level());
|
||||
} catch (CellBuilder::CellWriteError &) {
|
||||
return {};
|
||||
} catch (CellBuilder::CellCreateError &) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -119,6 +125,9 @@ Ref<Cell> MerkleProof::generate(Ref<Cell> cell, CellUsageTree *usage_tree) {
|
|||
return {};
|
||||
}
|
||||
auto raw = generate_raw(std::move(cell), usage_tree);
|
||||
if (raw.is_null()) {
|
||||
return {};
|
||||
}
|
||||
return CellBuilder::create_merkle_proof(std::move(raw));
|
||||
}
|
||||
|
||||
|
@ -384,21 +393,29 @@ bool MerkleProofBuilder::clear() {
|
|||
return true;
|
||||
}
|
||||
|
||||
Ref<Cell> MerkleProofBuilder::extract_proof() const {
|
||||
return MerkleProof::generate(orig_root, usage_tree.get());
|
||||
td::Result<Ref<Cell>> MerkleProofBuilder::extract_proof() const {
|
||||
Ref<Cell> proof = MerkleProof::generate(orig_root, usage_tree.get());
|
||||
if (proof.is_null()) {
|
||||
return td::Status::Error("cannot create Merkle proof");
|
||||
}
|
||||
return proof;
|
||||
}
|
||||
|
||||
bool MerkleProofBuilder::extract_proof_to(Ref<Cell> &proof_root) const {
|
||||
return orig_root.not_null() && (proof_root = extract_proof()).not_null();
|
||||
if (orig_root.is_null()) {
|
||||
return false;
|
||||
}
|
||||
auto R = extract_proof();
|
||||
if (R.is_error()) {
|
||||
return false;
|
||||
}
|
||||
proof_root = R.move_as_ok();
|
||||
return true;
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> MerkleProofBuilder::extract_proof_boc() const {
|
||||
Ref<Cell> proof_root = extract_proof();
|
||||
if (proof_root.is_null()) {
|
||||
return td::Status::Error("cannot create Merkle proof");
|
||||
} else {
|
||||
return std_boc_serialize(std::move(proof_root));
|
||||
}
|
||||
TRY_RESULT(proof_root, extract_proof());
|
||||
return std_boc_serialize(std::move(proof_root));
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -63,7 +63,7 @@ class MerkleProofBuilder {
|
|||
Ref<Cell> root() const {
|
||||
return usage_root;
|
||||
}
|
||||
Ref<Cell> extract_proof() const;
|
||||
td::Result<Ref<Cell>> extract_proof() const;
|
||||
bool extract_proof_to(Ref<Cell> &proof_root) const;
|
||||
td::Result<td::BufferSlice> extract_proof_boc() const;
|
||||
};
|
||||
|
|
|
@ -221,6 +221,9 @@ Ref<Cell> MerkleUpdate::generate(Ref<Cell> from, Ref<Cell> to, CellUsageTree *us
|
|||
return {};
|
||||
}
|
||||
auto res = generate_raw(std::move(from), std::move(to), usage_tree);
|
||||
if (res.first.is_null() || res.second.is_null()) {
|
||||
return {};
|
||||
}
|
||||
return CellBuilder::create_merkle_update(res.first, res.second);
|
||||
}
|
||||
|
||||
|
|
|
@ -225,6 +225,9 @@ bool AcceptBlockQuery::create_new_proof() {
|
|||
}
|
||||
// 5. finish constructing Merkle proof from visited cells
|
||||
auto proof = vm::MerkleProof::generate(block_root_, usage_tree.get());
|
||||
if (proof.is_null()) {
|
||||
return fatal_error("cannot create proof");
|
||||
}
|
||||
proof_roots_.push_back(proof);
|
||||
// 6. extract some information from state update
|
||||
state_old_hash_ = upd_cs.prefetch_ref(0)->get_hash(0).bits();
|
||||
|
|
|
@ -2274,7 +2274,7 @@ td::Result<std::unique_ptr<block::transaction::Transaction>> Collator::impl_crea
|
|||
return td::Status::Error(
|
||||
-669, "cannot create action phase of a new transaction for smart contract "s + acc->addr.to_hex());
|
||||
}
|
||||
if (trans->bounce_enabled && (!trans->compute_phase->success || trans->action_phase->state_size_too_big) &&
|
||||
if (trans->bounce_enabled && (!trans->compute_phase->success || trans->action_phase->state_exceeds_limits) &&
|
||||
!trans->prepare_bounce_phase(*action_phase_cfg)) {
|
||||
return td::Status::Error(
|
||||
-669, "cannot create bounce phase of a new transaction for smart contract "s + acc->addr.to_hex());
|
||||
|
@ -3640,6 +3640,9 @@ bool Collator::create_shard_state() {
|
|||
}
|
||||
LOG(INFO) << "creating Merkle update for the ShardState";
|
||||
state_update = vm::MerkleUpdate::generate(prev_state_root_, state_root, state_usage_tree_.get());
|
||||
if (state_update.is_null()) {
|
||||
return fatal_error("cannot create Merkle update for ShardState");
|
||||
}
|
||||
if (verbosity > 2) {
|
||||
std::cerr << "Merkle Update for ShardState: ";
|
||||
vm::CellSlice cs{vm::NoVm{}, state_update};
|
||||
|
|
|
@ -1168,7 +1168,7 @@ void LiteQuery::continue_getAccountState() {
|
|||
|
||||
void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
|
||||
LOG(INFO) << "completing getAccountState() query";
|
||||
Ref<vm::Cell> proof1;
|
||||
Ref<vm::Cell> proof1, proof2;
|
||||
if (!make_state_root_proof(proof1)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1197,7 +1197,11 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
|
|||
if (acc_csr.not_null()) {
|
||||
acc_root = acc_csr->prefetch_ref();
|
||||
}
|
||||
auto proof = vm::std_boc_serialize_multi({std::move(proof1), pb.extract_proof()});
|
||||
if (!pb.extract_proof_to(proof2)) {
|
||||
fatal_error("unknown error creating Merkle proof");
|
||||
return;
|
||||
}
|
||||
auto proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
|
||||
pb.clear();
|
||||
if (proof.is_error()) {
|
||||
fatal_error(proof.move_as_error());
|
||||
|
@ -1221,7 +1225,10 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
|
|||
fatal_error(S.move_as_error_prefix("Failed to load account: "));
|
||||
return;
|
||||
}
|
||||
acc_root = mpb.extract_proof();
|
||||
if (!mpb.extract_proof_to(acc_root)) {
|
||||
fatal_error("unknown error creating Merkle proof");
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto res = vm::std_boc_serialize(std::move(acc_root));
|
||||
if (res.is_error()) {
|
||||
|
@ -1283,10 +1290,20 @@ void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice
|
|||
balance.validate_unpack(store.balance) && store.state->prefetch_ulong(1) == 1 &&
|
||||
store.state.write().advance(1) && tlb::csr_unpack(std::move(store.state), state_init))) {
|
||||
LOG(INFO) << "error unpacking account state, or account is frozen or uninitialized";
|
||||
td::Result<td::BufferSlice> proof_boc;
|
||||
if (mode & 2) {
|
||||
proof_boc = pb.extract_proof_boc();
|
||||
if (proof_boc.is_error()) {
|
||||
fatal_error(proof_boc.move_as_error());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
proof_boc = td::BufferSlice();
|
||||
}
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
|
||||
mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
|
||||
std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), td::BufferSlice(),
|
||||
td::BufferSlice(), -0x100, td::BufferSlice());
|
||||
std::move(state_proof), proof_boc.move_as_ok(), td::BufferSlice(), td::BufferSlice(), -0x100,
|
||||
td::BufferSlice());
|
||||
finish_query(std::move(b));
|
||||
return;
|
||||
}
|
||||
|
@ -1340,10 +1357,20 @@ void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice
|
|||
}
|
||||
result = res.move_as_ok();
|
||||
}
|
||||
td::Result<td::BufferSlice> proof_boc;
|
||||
if (mode & 2) {
|
||||
proof_boc = pb.extract_proof_boc();
|
||||
if (proof_boc.is_error()) {
|
||||
fatal_error(proof_boc.move_as_error());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
proof_boc = td::BufferSlice();
|
||||
}
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_runMethodResult>(
|
||||
mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof),
|
||||
std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), std::move(c7_info),
|
||||
td::BufferSlice(), exit_code, std::move(result));
|
||||
std::move(state_proof), proof_boc.move_as_ok(), std::move(c7_info), td::BufferSlice(), exit_code,
|
||||
std::move(result));
|
||||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
|
|
|
@ -4506,7 +4506,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
|
|||
return reject_query(PSTRING() << "cannot re-create action phase of transaction " << lt << " for smart contract "
|
||||
<< addr.to_hex());
|
||||
}
|
||||
if (trs->bounce_enabled && (!trs->compute_phase->success || trs->action_phase->state_size_too_big) &&
|
||||
if (trs->bounce_enabled && (!trs->compute_phase->success || trs->action_phase->state_exceeds_limits) &&
|
||||
!trs->prepare_bounce_phase(action_phase_cfg_)) {
|
||||
return reject_query(PSTRING() << "cannot re-create bounce phase of transaction " << lt << " for smart contract "
|
||||
<< addr.to_hex());
|
||||
|
|
Loading…
Reference in a new issue