Ton
170 строк · 7.1 Кб
1/*
2This file is part of TON Blockchain Library.
3
4TON Blockchain Library is free software: you can redistribute it and/or modify
5it under the terms of the GNU Lesser General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9TON Blockchain Library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public License
15along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "common.h"18#include <memory>19#include "vm/memo.h"20
21namespace block::precompiled {22
23using namespace vm;24
25Result PrecompiledSmartContract::run(td::Ref<vm::CellSlice> my_address, ton::UnixTime now, ton::LogicalTime cur_lt,26CurrencyCollection balance, td::Ref<vm::Cell> c4, vm::CellSlice msg_body,27td::Ref<vm::Cell> msg, CurrencyCollection msg_balance, bool is_external,28std::vector<td::Ref<vm::Cell>> libraries, int global_version,29td::uint16 max_data_depth, td::Ref<vm::Cell> my_code,30td::Ref<vm::Tuple> unpacked_config, td::RefInt256 due_payment,31td::uint64 precompiled_gas_usage) {32my_address_ = std::move(my_address);33now_ = now;34cur_lt_ = cur_lt;35balance_ = std::move(balance);36c4_ = (c4.not_null() ? std::move(c4) : CellBuilder().finalize());37in_msg_body_ = std::move(msg_body);38in_msg_ = std::move(msg);39in_msg_balance_ = std::move(msg_balance);40is_external_ = is_external;41my_code_ = std::move(my_code);42unpacked_config_ = std::move(unpacked_config);43due_payment_ = std::move(due_payment);44precompiled_gas_usage_ = precompiled_gas_usage;45
46vm::DummyVmState vm_state{std::move(libraries), global_version};47vm::VmStateInterface::Guard guard{&vm_state};48
49Result result;50try {51result = do_run();52} catch (vm::VmError &e) {53result = Result::error(e.get_errno(), e.get_arg());54} catch (Result &r) {55result = std::move(r);56}57
58if (result.exit_code != 0 && result.exit_code != 1) {59// see VmState::try_commit()60if (c4_.is_null() || c4_->get_depth() > max_data_depth || c4_->get_level() != 0 || c5_.is_null() ||61c5_->get_depth() > max_data_depth || c5_->get_level() != 0) {62result = Result::error(Excno::cell_ov, 0);63}64}65return result;66}
67
68void PrecompiledSmartContract::send_raw_message(const td::Ref<Cell> &msg, int mode) {69CellBuilder cb;70if (!(cb.store_ref_bool(c5_) // out_list$_ {n:#} prev:^(OutList n)71&& cb.store_long_bool(0x0ec3c86d, 32) // action_send_msg#0ec3c86d72&& cb.store_long_bool(mode, 8) // mode:(## 8)73&& cb.store_ref_bool(msg))) {74throw VmError{Excno::cell_ov, "cannot serialize raw output message into an output action cell"};75}76c5_ = cb.finalize_novm();77}
78
79void PrecompiledSmartContract::raw_reserve(const td::RefInt256 &amount, int mode) {80if (amount->sgn() < 0) {81throw VmError{Excno::range_chk, "amount of nanograms must be non-negative"};82}83CellBuilder cb;84if (!(cb.store_ref_bool(c5_) // out_list$_ {n:#} prev:^(OutList n)85&& cb.store_long_bool(0x36e6b809, 32) // action_reserve_currency#36e6b80986&& cb.store_long_bool(mode, 8) // mode:(## 8)87&& util::store_coins(cb, std::move(amount), true) //88&& cb.store_maybe_ref({}))) {89throw VmError{Excno::cell_ov, "cannot serialize raw reserved currency amount into an output action cell"};90}91c5_ = cb.finalize_novm();92}
93
94td::RefInt256 PrecompiledSmartContract::get_compute_fee(ton::WorkchainId wc, td::uint64 gas_used) {95if (gas_used >= (1ULL << 63)) {96throw VmError{Excno::range_chk};97}98block::GasLimitsPrices prices = util::get_gas_prices(unpacked_config_, wc);99return util::check_finite(prices.compute_gas_price(gas_used));100}
101
102td::RefInt256 PrecompiledSmartContract::get_forward_fee(ton::WorkchainId wc, td::uint64 bits, td::uint64 cells) {103if (bits >= (1ULL << 63) || cells >= (1ULL << 63)) {104throw VmError{Excno::range_chk};105}106block::MsgPrices prices = util::get_msg_prices(unpacked_config_, wc);107return util::check_finite(prices.compute_fwd_fees256(cells, bits));108}
109
110td::RefInt256 PrecompiledSmartContract::get_storage_fee(ton::WorkchainId wc, td::uint64 duration, td::uint64 bits,111td::uint64 cells) {112if (bits >= (1ULL << 63) || cells >= (1ULL << 63) || duration >= (1ULL << 63)) {113throw VmError{Excno::range_chk};114}115td::optional<block::StoragePrices> maybe_prices = util::get_storage_prices(unpacked_config_);116return util::check_finite(util::calculate_storage_fee(maybe_prices, wc, duration, bits, cells));117}
118
119td::RefInt256 PrecompiledSmartContract::get_simple_compute_fee(ton::WorkchainId wc, td::uint64 gas_used) {120if (gas_used >= (1ULL << 63)) {121throw VmError{Excno::range_chk};122}123block::GasLimitsPrices prices = util::get_gas_prices(unpacked_config_, wc);124return util::check_finite(td::rshift(td::make_refint(prices.gas_price) * gas_used, 16, 1));125}
126
127td::RefInt256 PrecompiledSmartContract::get_simple_forward_fee(ton::WorkchainId wc, td::uint64 bits, td::uint64 cells) {128if (bits >= (1ULL << 63) || cells >= (1ULL << 63)) {129throw VmError{Excno::range_chk};130}131block::MsgPrices prices = util::get_msg_prices(unpacked_config_, wc);132return util::check_finite(133td::rshift(td::make_refint(prices.bit_price) * bits + td::make_refint(prices.cell_price) * cells, 16, 1));134}
135
136td::RefInt256 PrecompiledSmartContract::get_original_fwd_fee(ton::WorkchainId wc, const td::RefInt256 &x) {137if (x->sgn() < 0) {138throw VmError{Excno::range_chk, "fwd_fee is negative"};139}140block::MsgPrices prices = util::get_msg_prices(unpacked_config_, wc);141return util::check_finite(td::muldiv(x, td::make_refint(1 << 16), td::make_refint((1 << 16) - prices.first_frac)));142}
143
144static std::atomic_bool precompiled_execution_enabled{false};145
146std::unique_ptr<PrecompiledSmartContract> get_implementation(td::Bits256 code_hash) {147if (!precompiled_execution_enabled) {148return nullptr;149}150static std::map<td::Bits256, std::unique_ptr<PrecompiledSmartContract> (*)()> map = []() {151auto from_hex = [](td::Slice s) -> td::Bits256 {152td::Bits256 x;153CHECK(x.from_hex(s) == 256);154return x;155};156std::map<td::Bits256, std::unique_ptr<PrecompiledSmartContract> (*)()> map;157#define CONTRACT(hash, cls) \158map[from_hex(hash)] = []() -> std::unique_ptr<PrecompiledSmartContract> { return std::make_unique<cls>(); };159// CONTRACT("CODE_HASH_HEX", ClassName);160return map;161}();162auto it = map.find(code_hash);163return it == map.end() ? nullptr : it->second();164}
165
166void set_precompiled_execution_enabled(bool value) {167precompiled_execution_enabled = value;168}
169
170} // namespace block::precompiled171