Skip to content

Commit

Permalink
Cheap fee calculations (ton-blockchain#878)
Browse files Browse the repository at this point in the history
* TVM v6

* New tuple with unpacked config parameters in c7
* New instructions for calculating fees

* Change unpacked_config_tuple, fix typo

---------

Co-authored-by: SpyCheese <[email protected]>
  • Loading branch information
EmelyanenkoK and SpyCheese authored Jan 26, 2024
1 parent e459aea commit 64b04e4
Show file tree
Hide file tree
Showing 12 changed files with 384 additions and 73 deletions.
2 changes: 1 addition & 1 deletion common/global-version.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
namespace ton {

// See doc/GlobalVersions.md
const int SUPPORTED_VERSION = 5;
const int SUPPORTED_VERSION = 6;

}
84 changes: 70 additions & 14 deletions crypto/block/mc-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,29 +621,40 @@ td::Result<std::vector<StoragePrices>> Config::get_storage_prices() const {
}
vm::Dictionary dict{std::move(cell), 32};
if (!dict.check_for_each([&res](Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key, int n) -> bool {
block::gen::StoragePrices::Record data;
if (!tlb::csr_unpack(std::move(cs_ref), data) || data.utime_since != key.get_uint(n)) {
auto r_prices = do_get_one_storage_prices(*cs_ref);
if (r_prices.is_error()) {
return false;
}
res.push_back(r_prices.move_as_ok());
if (res.back().valid_since != key.get_uint(n)) {
return false;
}
res.emplace_back(data.utime_since, data.bit_price_ps, data.cell_price_ps, data.mc_bit_price_ps,
data.mc_cell_price_ps);
return true;
})) {
return td::Status::Error("invalid storage prices dictionary in configuration parameter 18");
}
return std::move(res);
}

td::Result<GasLimitsPrices> Config::do_get_gas_limits_prices(td::Ref<vm::Cell> cell, int id) {
td::Result<StoragePrices> Config::do_get_one_storage_prices(vm::CellSlice cs) {
block::gen::StoragePrices::Record data;
if (!tlb::unpack(cs, data)) {
return td::Status::Error("invalid storage prices dictionary in configuration parameter 18");
}
return StoragePrices{data.utime_since, data.bit_price_ps, data.cell_price_ps, data.mc_bit_price_ps,
data.mc_cell_price_ps};
}

td::Result<GasLimitsPrices> Config::do_get_gas_limits_prices(vm::CellSlice cs, int id) {
GasLimitsPrices res;
auto cs = vm::load_cell_slice(cell);
vm::CellSlice cs0 = cs;
block::gen::GasLimitsPrices::Record_gas_flat_pfx flat;
if (tlb::unpack(cs, flat)) {
cs = *flat.other;
res.flat_gas_limit = flat.flat_gas_limit;
res.flat_gas_price = flat.flat_gas_price;
} else {
cs = vm::load_cell_slice(cell);
cs = cs0;
}
auto f = [&](const auto& r, td::uint64 spec_limit) {
res.gas_limit = r.gas_limit;
Expand All @@ -654,7 +665,6 @@ td::Result<GasLimitsPrices> Config::do_get_gas_limits_prices(td::Ref<vm::Cell> c
res.delete_due_limit = r.delete_due_limit;
};
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
vm::CellSlice cs0 = cs;
if (tlb::unpack(cs, rec)) {
f(rec, rec.special_gas_limit);
} else {
Expand Down Expand Up @@ -689,7 +699,7 @@ td::Result<GasLimitsPrices> Config::get_gas_limits_prices(bool is_masterchain) c
if (cell.is_null()) {
return td::Status::Error(PSLICE() << "configuration parameter " << id << " with gas prices is absent");
}
return do_get_gas_limits_prices(std::move(cell), id);
return do_get_gas_limits_prices(vm::load_cell_slice(cell), id);
}

td::Result<MsgPrices> Config::get_msg_prices(bool is_masterchain) const {
Expand All @@ -698,7 +708,10 @@ td::Result<MsgPrices> Config::get_msg_prices(bool is_masterchain) const {
if (cell.is_null()) {
return td::Status::Error(PSLICE() << "configuration parameter " << id << " with msg prices is absent");
}
auto cs = vm::load_cell_slice(std::move(cell));
return do_get_msg_prices(vm::load_cell_slice(cell), id);
}

td::Result<MsgPrices> Config::do_get_msg_prices(vm::CellSlice cs, int id) {
block::gen::MsgForwardPrices::Record rec;
if (!tlb::unpack(cs, rec)) {
return td::Status::Error(PSLICE() << "configuration parameter " << id
Expand Down Expand Up @@ -1917,10 +1930,17 @@ std::vector<ton::ValidatorDescr> Config::compute_total_validator_set(int next) c
}

td::Result<SizeLimitsConfig> Config::get_size_limits_config() const {
SizeLimitsConfig limits;
td::Ref<vm::Cell> param = get_config_param(43);
if (param.is_null()) {
return limits;
return do_get_size_limits_config({});
}
return do_get_size_limits_config(vm::load_cell_slice_ref(param));
}

td::Result<SizeLimitsConfig> Config::do_get_size_limits_config(td::Ref<vm::CellSlice> cs) {
SizeLimitsConfig limits;
if (cs.is_null()) {
return limits; // default values
}
auto unpack_v1 = [&](auto& rec) {
limits.max_msg_bits = rec.max_msg_bits;
Expand All @@ -1939,9 +1959,9 @@ td::Result<SizeLimitsConfig> Config::get_size_limits_config() const {
};
gen::SizeLimitsConfig::Record_size_limits_config rec_v1;
gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2;
if (tlb::unpack_cell(param, rec_v1)) {
if (tlb::csr_unpack(cs, rec_v1)) {
unpack_v1(rec_v1);
} else if (tlb::unpack_cell(param, rec_v2)) {
} else if (tlb::csr_unpack(cs, rec_v2)) {
unpack_v2(rec_v2);
} else {
return td::Status::Error("configuration parameter 43 is invalid");
Expand Down Expand Up @@ -1976,6 +1996,42 @@ BurningConfig Config::get_burning_config() const {
return c;
}

td::Ref<vm::Tuple> Config::get_unpacked_config_tuple(ton::UnixTime now) const {
auto get_param = [&](td::int32 idx) -> vm::StackEntry {
auto cell = get_config_param(idx);
if (cell.is_null()) {
return {};
}
return vm::load_cell_slice_ref(cell);
};
auto get_current_storage_prices = [&]() -> vm::StackEntry {
auto cell = get_config_param(18);
if (cell.is_null()) {
return {};
}
vm::StackEntry res;
vm::Dictionary dict{std::move(cell), 32};
dict.check_for_each([&](Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key, int n) -> bool {
auto utime_since = key.get_uint(n);
if (now >= utime_since) {
res = std::move(cs_ref);
return true;
}
return false;
});
return res;
};
std::vector<vm::StackEntry> tuple;
tuple.push_back(get_current_storage_prices()); // storage_prices
tuple.push_back(get_param(19)); // global_id
tuple.push_back(get_param(20)); // config_mc_gas_prices
tuple.push_back(get_param(21)); // config_gas_prices
tuple.push_back(get_param(24)); // config_mc_fwd_prices
tuple.push_back(get_param(25)); // config_fwd_prices
tuple.push_back(get_param(43)); // size_limits_config
return td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
}

td::Result<std::pair<ton::UnixTime, ton::UnixTime>> Config::unpack_validator_set_start_stop(Ref<vm::Cell> vset_root) {
if (vset_root.is_null()) {
return td::Status::Error("validator set absent");
Expand Down
13 changes: 11 additions & 2 deletions crypto/block/mc-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,11 @@ struct GasLimitsPrices {
td::uint64 freeze_due_limit{0};
td::uint64 delete_due_limit{0};

td::RefInt256 compute_gas_price(td::uint64 gas_used) const;
td::RefInt256 compute_gas_price(td::uint64 gas_used) const {
return gas_used <= flat_gas_limit
? td::make_refint(flat_gas_price)
: td::rshift(td::make_refint(gas_price) * (gas_used - flat_gas_limit), 16, 1) + flat_gas_price;
}
};

// msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
Expand All @@ -365,6 +369,7 @@ struct MsgPrices {
td::uint32 first_frac;
td::uint32 next_frac;
td::uint64 compute_fwd_fees(td::uint64 cells, td::uint64 bits) const;
td::RefInt256 compute_fwd_fees256(td::uint64 cells, td::uint64 bits) const;
std::pair<td::uint64, td::uint64> compute_fwd_ihr_fees(td::uint64 cells, td::uint64 bits,
bool ihr_disabled = false) const;
MsgPrices() = default;
Expand Down Expand Up @@ -604,9 +609,11 @@ class Config {
bool is_special_smartcontract(const ton::StdSmcAddress& addr) const;
static td::Result<std::unique_ptr<ValidatorSet>> unpack_validator_set(Ref<vm::Cell> valset_root);
td::Result<std::vector<StoragePrices>> get_storage_prices() const;
static td::Result<StoragePrices> do_get_one_storage_prices(vm::CellSlice cs);
td::Result<GasLimitsPrices> get_gas_limits_prices(bool is_masterchain = false) const;
static td::Result<GasLimitsPrices> do_get_gas_limits_prices(td::Ref<vm::Cell> cell, int id);
static td::Result<GasLimitsPrices> do_get_gas_limits_prices(vm::CellSlice cs, int id);
td::Result<MsgPrices> get_msg_prices(bool is_masterchain = false) const;
static td::Result<MsgPrices> do_get_msg_prices(vm::CellSlice cs, int id);
static CatchainValidatorsConfig unpack_catchain_validators_config(Ref<vm::Cell> cell);
CatchainValidatorsConfig get_catchain_validators_config() const;
td::Status visit_validator_params() const;
Expand All @@ -633,8 +640,10 @@ class Config {
ton::CatchainSeqno cc_seqno) const;
std::vector<ton::ValidatorDescr> compute_total_validator_set(int next) const;
td::Result<SizeLimitsConfig> get_size_limits_config() const;
static td::Result<SizeLimitsConfig> do_get_size_limits_config(td::Ref<vm::CellSlice> cs);
std::unique_ptr<vm::Dictionary> get_suspended_addresses(ton::UnixTime now) const;
BurningConfig get_burning_config() const;
td::Ref<vm::Tuple> get_unpacked_config_tuple(ton::UnixTime now) const;
static std::vector<ton::ValidatorDescr> do_compute_validator_set(const block::CatchainValidatorsConfig& ccv_conf,
ton::ShardIdFull shard,
const block::ValidatorSet& vset, ton::UnixTime time,
Expand Down
26 changes: 26 additions & 0 deletions crypto/block/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,10 @@ Ref<vm::Tuple> Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const {
// may only return tuple or raise Error (See crypto/block/mc-config.cpp#2223)
tuple.push_back(cfg.prev_blocks_info.not_null() ? vm::StackEntry(cfg.prev_blocks_info) : vm::StackEntry());
}
if (cfg.global_version >= 6) {
tuple.push_back(cfg.unpacked_config_tuple.not_null() ? vm::StackEntry(cfg.unpacked_config_tuple)
: vm::StackEntry()); // unpacked_config_tuple:[...]
}
auto tuple_ref = td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple_ref).to_string();
return vm::make_tuple_ref(std::move(tuple_ref));
Expand Down Expand Up @@ -1920,6 +1924,25 @@ td::uint64 MsgPrices::compute_fwd_fees(td::uint64 cells, td::uint64 bits) const
.lo();
}

/**
* Computes the forward fees for a message based on the number of cells and bits.
* Return the result as td::RefInt256
*
* msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
* ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms
* bits in the root cell of a message are not included in msg.bits (lump_price pays for them)
*
* @param cells The number of cells in the message.
* @param bits The number of bits in the message.
*
* @returns The computed forward fees for the message as td::RefInt256j.
*/
td::RefInt256 MsgPrices::compute_fwd_fees256(td::uint64 cells, td::uint64 bits) const {
return td::rshift(
td::make_refint(lump_price) + td::make_refint(bit_price) * bits + td::make_refint(cell_price) * cells, 16,
1); // divide by 2^16 with ceil rounding
}

/**
* Computes the forward fees and IHR fees for a message with the given number of cells and bits.
*
Expand Down Expand Up @@ -3539,6 +3562,9 @@ td::Status FetchConfigParams::fetch_config_params(
if (compute_phase_cfg->global_version >= 4) {
compute_phase_cfg->prev_blocks_info = std::move(prev_blocks_info);
}
if (compute_phase_cfg->global_version >= 6) {
compute_phase_cfg->unpacked_config_tuple = config.get_unpacked_config_tuple(now);
}
compute_phase_cfg->suspended_addresses = config.get_suspended_addresses(now);
compute_phase_cfg->size_limits = size_limits;
}
Expand Down
1 change: 1 addition & 0 deletions crypto/block/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ struct ComputePhaseConfig {
td::uint16 max_vm_data_depth = 512;
int global_version = 0;
Ref<vm::Tuple> prev_blocks_info;
Ref<vm::Tuple> unpacked_config_tuple;
std::unique_ptr<vm::Dictionary> suspended_addresses;
SizeLimitsConfig size_limits;
int vm_log_verbosity = 0;
Expand Down
7 changes: 6 additions & 1 deletion crypto/fift/lib/Asm.fif
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ library TVM_Asm
// simple TVM Assembler
namespace Asm
Asm definitions
"0.4.4" constant asm-fif-version
"0.4.5" constant asm-fif-version

variable @atend
variable @was-split
Expand Down Expand Up @@ -1295,12 +1295,17 @@ x{F82A} @Defop MYCODE
x{F82B} @Defop INCOMINGVALUE
x{F82C} @Defop STORAGEFEES
x{F82D} @Defop PREVBLOCKSINFOTUPLE
x{F82E} @Defop UNPACKEDCONFIGTUPLE
x{F830} @Defop CONFIGDICT
x{F832} @Defop CONFIGPARAM
x{F833} @Defop CONFIGOPTPARAM
x{F83400} @Defop PREVMCBLOCKS
x{F83401} @Defop PREVKEYBLOCK
x{F835} @Defop GLOBALID
x{F836} @Defop GETEXECUTIONPRICE
x{F837} @Defop GETSTORAGEPRICE
x{F838} @Defop GETFORWARDPRICE
x{F839} @Defop GETPRECOMPILEDGAS

x{F840} @Defop GETGLOBVAR
{ dup 1 31 @rangechk <b x{F85_} s, swap 5 u, @addopb } : GETGLOB
Expand Down
3 changes: 3 additions & 0 deletions crypto/smc-envelope/SmartContract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args, td::Ref<vm::Cell> cod
// prev_key_block:BlockId ] : PrevBlocksInfo
tuple.push_back(args.prev_blocks_info ? args.prev_blocks_info.value() : vm::StackEntry{}); // prev_block_info
}
if (args.config && args.config.value()->get_global_version() >= 6) {
tuple.push_back(args.config.value()->get_unpacked_config_tuple(now)); // unpacked_config_tuple
}
auto tuple_ref = td::make_cnt_ref<std::vector<vm::StackEntry>>(std::move(tuple));
//LOG(DEBUG) << "SmartContractInfo initialized with " << vm::StackEntry(tuple).to_string();
return vm::make_tuple_ref(std::move(tuple_ref));
Expand Down
Loading

0 comments on commit 64b04e4

Please sign in to comment.