diff --git a/.github/workflows/ton-aarch64-linux.yml b/.github/workflows/ton-aarch64-linux.yml index 83ad8694..ac0d68a5 100644 --- a/.github/workflows/ton-aarch64-linux.yml +++ b/.github/workflows/ton-aarch64-linux.yml @@ -36,6 +36,7 @@ jobs: - name: Simple binaries test run: | + sudo mv /nix/store /nix/store2 artifacts/validator-engine -V artifacts/lite-client -V artifacts/fift -V diff --git a/.github/workflows/ton-aarch64-macos.yml b/.github/workflows/ton-aarch64-macos.yml index 855ffa6c..8ef4b2b2 100644 --- a/.github/workflows/ton-aarch64-macos.yml +++ b/.github/workflows/ton-aarch64-macos.yml @@ -33,6 +33,7 @@ jobs: - name: Simple binaries test run: | + sudo mv /nix/store /nix/store2 artifacts/validator-engine -V artifacts/lite-client -V artifacts/fift -V diff --git a/.github/workflows/ton-x86-64-linux.yml b/.github/workflows/ton-x86-64-linux.yml index 0af0051b..7043d054 100644 --- a/.github/workflows/ton-x86-64-linux.yml +++ b/.github/workflows/ton-x86-64-linux.yml @@ -35,6 +35,7 @@ jobs: - name: Simple binaries test run: | + sudo mv /nix/store /nix/store2 artifacts/validator-engine -V artifacts/lite-client -V artifacts/fift -V diff --git a/.github/workflows/ton-x86-64-macos.yml b/.github/workflows/ton-x86-64-macos.yml index 9d490997..8175a366 100644 --- a/.github/workflows/ton-x86-64-macos.yml +++ b/.github/workflows/ton-x86-64-macos.yml @@ -31,6 +31,7 @@ jobs: - name: Simple binaries test run: | + sudo mv /nix/store /nix/store2 artifacts/validator-engine -V artifacts/lite-client -V artifacts/fift -V diff --git a/Changelog.md b/Changelog.md index 0f0cd833..1deebc61 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,9 @@ +## 2023.06 Update +1. (disabled by default) New deflation mechanisms: partial fee burning and blackhole address +2. Storage-contract improvement + +Besides the work of the core team, this update is based on the efforts of @DearJohnDoe from Tonbyte (Storage-contract improvement). + ## 2023.05 Update 1. Archive manager optimization 2. A series of catchain (basic consensus protocol) security improvements diff --git a/crypto/block/block.cpp b/crypto/block/block.cpp index e1790cbf..1131213c 100644 --- a/crypto/block/block.cpp +++ b/crypto/block/block.cpp @@ -1364,42 +1364,61 @@ std::ostream& operator<<(std::ostream& os, const CurrencyCollection& cc) { bool ValueFlow::set_zero() { return from_prev_blk.set_zero() && to_next_blk.set_zero() && imported.set_zero() && exported.set_zero() && fees_collected.set_zero() && fees_imported.set_zero() && recovered.set_zero() && created.set_zero() && - minted.set_zero(); + minted.set_zero() && burned.set_zero(); } bool ValueFlow::validate() const { return is_valid() && from_prev_blk + imported + fees_imported + created + minted + recovered == - to_next_blk + exported + fees_collected; + to_next_blk + exported + fees_collected + burned; } bool ValueFlow::store(vm::CellBuilder& cb) const { vm::CellBuilder cb2; - return cb.store_long_bool(block::gen::ValueFlow::cons_tag[0], 32) // value_flow ^[ - && from_prev_blk.store(cb2) // from_prev_blk:CurrencyCollection - && to_next_blk.store(cb2) // to_next_blk:CurrencyCollection - && imported.store(cb2) // imported:CurrencyCollection - && exported.store(cb2) // exported:CurrencyCollection - && cb.store_ref_bool(cb2.finalize()) // ] - && fees_collected.store(cb) // fees_collected:CurrencyCollection - && fees_imported.store(cb2) // ^[ fees_imported:CurrencyCollection - && recovered.store(cb2) // recovered:CurrencyCollection - && created.store(cb2) // created:CurrencyCollection - && minted.store(cb2) // minted:CurrencyCollection - && cb.store_ref_bool(cb2.finalize()); // ] = ValueFlow; + auto type = burned.is_zero() ? block::gen::ValueFlow::value_flow : block::gen::ValueFlow::value_flow_v2; + return cb.store_long_bool(block::gen::ValueFlow::cons_tag[type], 32) // ^[ + && from_prev_blk.store(cb2) // from_prev_blk:CurrencyCollection + && to_next_blk.store(cb2) // to_next_blk:CurrencyCollection + && imported.store(cb2) // imported:CurrencyCollection + && exported.store(cb2) // exported:CurrencyCollection + && cb.store_ref_bool(cb2.finalize()) // ] + && fees_collected.store(cb) // fees_collected:CurrencyCollection + && (burned.is_zero() || burned.store(cb)) // fees_burned:CurrencyCollection + && fees_imported.store(cb2) // ^[ fees_imported:CurrencyCollection + && recovered.store(cb2) // recovered:CurrencyCollection + && created.store(cb2) // created:CurrencyCollection + && minted.store(cb2) // minted:CurrencyCollection + && cb.store_ref_bool(cb2.finalize()); // ] = ValueFlow; } bool ValueFlow::fetch(vm::CellSlice& cs) { - block::gen::ValueFlow::Record f; - if (!(tlb::unpack(cs, f) && from_prev_blk.validate_unpack(std::move(f.r1.from_prev_blk)) && - to_next_blk.validate_unpack(std::move(f.r1.to_next_blk)) && - imported.validate_unpack(std::move(f.r1.imported)) && exported.validate_unpack(std::move(f.r1.exported)) && - fees_collected.validate_unpack(std::move(f.fees_collected)) && - fees_imported.validate_unpack(std::move(f.r2.fees_imported)) && - recovered.validate_unpack(std::move(f.r2.recovered)) && created.validate_unpack(std::move(f.r2.created)) && - minted.validate_unpack(std::move(f.r2.minted)))) { + if (cs.size() < 32) { return invalidate(); } - return true; + auto tag = cs.prefetch_ulong(32); + block::gen::ValueFlow::Record_value_flow f1; + if (tag == block::gen::ValueFlow::cons_tag[block::gen::ValueFlow::value_flow] && tlb::unpack(cs, f1) && + from_prev_blk.validate_unpack(std::move(f1.r1.from_prev_blk)) && + to_next_blk.validate_unpack(std::move(f1.r1.to_next_blk)) && + imported.validate_unpack(std::move(f1.r1.imported)) && exported.validate_unpack(std::move(f1.r1.exported)) && + fees_collected.validate_unpack(std::move(f1.fees_collected)) && burned.set_zero() && + fees_imported.validate_unpack(std::move(f1.r2.fees_imported)) && + recovered.validate_unpack(std::move(f1.r2.recovered)) && created.validate_unpack(std::move(f1.r2.created)) && + minted.validate_unpack(std::move(f1.r2.minted))) { + return true; + } + block::gen::ValueFlow::Record_value_flow_v2 f2; + if (tag == block::gen::ValueFlow::cons_tag[block::gen::ValueFlow::value_flow_v2] && tlb::unpack(cs, f2) && + from_prev_blk.validate_unpack(std::move(f2.r1.from_prev_blk)) && + to_next_blk.validate_unpack(std::move(f2.r1.to_next_blk)) && + imported.validate_unpack(std::move(f2.r1.imported)) && exported.validate_unpack(std::move(f2.r1.exported)) && + fees_collected.validate_unpack(std::move(f2.fees_collected)) && + burned.validate_unpack(std::move(f2.burned)) && + fees_imported.validate_unpack(std::move(f2.r2.fees_imported)) && + recovered.validate_unpack(std::move(f2.r2.recovered)) && created.validate_unpack(std::move(f2.r2.created)) && + minted.validate_unpack(std::move(f2.r2.minted))) { + return true; + } + return invalidate(); } bool ValueFlow::unpack(Ref csr) { @@ -1424,7 +1443,8 @@ bool ValueFlow::show(std::ostream& os) const { show_one(os, " to_next_blk:", to_next_blk) && show_one(os, " imported:", imported) && show_one(os, " exported:", exported) && show_one(os, " fees_collected:", fees_collected) && show_one(os, " fees_imported:", fees_imported) && show_one(os, " recovered:", recovered) && - show_one(os, " created:", created) && show_one(os, " minted:", minted) && say(os, ")")) || + show_one(os, " created:", created) && show_one(os, " minted:", minted) && + (burned.is_zero() || show_one(os, " burned:", burned)) && say(os, ")")) || (say(os, "...)") && false); } diff --git a/crypto/block/block.h b/crypto/block/block.h index f5b47a63..19d99e6a 100644 --- a/crypto/block/block.h +++ b/crypto/block/block.h @@ -456,7 +456,7 @@ struct ShardState { struct ValueFlow { struct SetZero {}; CurrencyCollection from_prev_blk, to_next_blk, imported, exported, fees_collected, fees_imported, recovered, created, - minted; + minted, burned; ValueFlow() = default; ValueFlow(SetZero) : from_prev_blk{0} @@ -467,7 +467,8 @@ struct ValueFlow { , fees_imported{0} , recovered{0} , created{0} - , minted{0} { + , minted{0} + , burned{0} { } bool is_valid() const { return from_prev_blk.is_valid() && minted.is_valid(); diff --git a/crypto/block/block.tlb b/crypto/block/block.tlb index 6ab03508..6b9473ca 100644 --- a/crypto/block/block.tlb +++ b/crypto/block/block.tlb @@ -472,6 +472,19 @@ value_flow#b8e48dfb ^[ from_prev_blk:CurrencyCollection minted:CurrencyCollection ] = ValueFlow; +value_flow_v2#3ebf98b7 ^[ from_prev_blk:CurrencyCollection + to_next_blk:CurrencyCollection + imported:CurrencyCollection + exported:CurrencyCollection ] + fees_collected:CurrencyCollection + burned:CurrencyCollection + ^[ + fees_imported:CurrencyCollection + recovered:CurrencyCollection + created:CurrencyCollection + minted:CurrencyCollection + ] = ValueFlow; + // // bt_leaf$0 {X:Type} leaf:X = BinTree X; @@ -595,6 +608,11 @@ _ minter_addr:bits256 = ConfigParam 2; // ConfigParam 0 is used if absent _ fee_collector_addr:bits256 = ConfigParam 3; // ConfigParam 1 is used if absent _ dns_root_addr:bits256 = ConfigParam 4; // root TON DNS resolver +burning_config#01 + blackhole_addr:(Maybe bits256) + fee_burn_nom:# fee_burn_denom:# { fee_burn_nom <= fee_burn_denom } { fee_burn_denom >= 1 } = BurningConfig; +_ BurningConfig = ConfigParam 5; + _ mint_new_price:Grams mint_add_price:Grams = ConfigParam 6; _ to_mint:ExtraCurrencyCollection = ConfigParam 7; diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index 9b43075a..e94ff0a4 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -855,11 +855,12 @@ Ref McShardHash::from_block(Ref block_root, const ton::Fi ton::RootHash rhash = block_root->get_hash().bits(); CurrencyCollection fees_collected, funds_created; if (init_fees) { - block::gen::ValueFlow::Record flow; - if (!(tlb::unpack_cell(rec.value_flow, flow) && fees_collected.unpack(flow.fees_collected) && - funds_created.unpack(flow.r2.created))) { + block::ValueFlow flow; + if (!flow.unpack(vm::load_cell_slice_ref(rec.value_flow))) { return {}; } + fees_collected = flow.fees_collected; + funds_created = flow.created; } return Ref(true, ton::BlockId{ton::ShardIdFull(shard), (unsigned)info.seq_no}, info.start_lt, info.end_lt, info.gen_utime, rhash, fhash, fees_collected, funds_created, ~0U, @@ -909,11 +910,12 @@ Ref McShardDescr::from_block(Ref block_root, Refget_hash().bits(); CurrencyCollection fees_collected, funds_created; if (init_fees) { - block::gen::ValueFlow::Record flow; - if (!(tlb::unpack_cell(rec.value_flow, flow) && fees_collected.unpack(flow.fees_collected) && - funds_created.unpack(flow.r2.created))) { + block::ValueFlow flow; + if (!flow.unpack(vm::load_cell_slice_ref(rec.value_flow))) { return {}; } + fees_collected = flow.fees_collected; + funds_created = flow.created; } auto res = Ref(true, ton::BlockId{ton::ShardIdFull(shard), (unsigned)info.seq_no}, info.start_lt, info.end_lt, info.gen_utime, rhash, fhash, fees_collected, funds_created, ~0U, @@ -1954,6 +1956,24 @@ std::unique_ptr Config::get_suspended_addresses(ton::UnixTime no return std::make_unique(rec.addresses->prefetch_ref(), 288); } +BurningConfig Config::get_burning_config() const { + td::Ref param = get_config_param(5); + gen::BurningConfig::Record rec; + if (param.is_null() || !tlb::unpack_cell(param, rec)) { + return {}; + } + BurningConfig c; + c.fee_burn_nom = rec.fee_burn_nom; + c.fee_burn_denom = rec.fee_burn_denom; + vm::CellSlice& addr = rec.blackhole_addr.write(); + if (addr.fetch_long(1)) { + td::Bits256 x; + addr.fetch_bits_to(x.bits(), 256); + c.blackhole_addr = x; + } + return c; +} + td::Result> Config::unpack_validator_set_start_stop(Ref vset_root) { if (vset_root.is_null()) { return td::Status::Error("validator set absent"); diff --git a/crypto/block/mc-config.h b/crypto/block/mc-config.h index aca21475..c56be474 100644 --- a/crypto/block/mc-config.h +++ b/crypto/block/mc-config.h @@ -504,6 +504,22 @@ class ShardConfig { bool set_shard_info(ton::ShardIdFull shard, Ref value); }; +struct BurningConfig { + td::optional blackhole_addr; + td::uint32 fee_burn_nom = 0, fee_burn_denom = 1; + + td::RefInt256 calculate_burned_fees(const td::RefInt256& x) const { + if (x.is_null()) { + return x; + } + return x * fee_burn_nom / td::make_refint(fee_burn_denom); + } + + CurrencyCollection calculate_burned_fees(const CurrencyCollection& x) const { + return CurrencyCollection{calculate_burned_fees(x.grams)}; + } +}; + class Config { enum { default_mc_catchain_lifetime = 200, @@ -617,6 +633,7 @@ class Config { std::vector compute_total_validator_set(int next) const; td::Result get_size_limits_config() const; std::unique_ptr get_suspended_addresses(ton::UnixTime now) const; + BurningConfig get_burning_config() const; static std::vector do_compute_validator_set(const block::CatchainValidatorsConfig& ccv_conf, ton::ShardIdFull shard, const block::ValidatorSet& vset, ton::UnixTime time, diff --git a/crypto/block/transaction.cpp b/crypto/block/transaction.cpp index 1a8f111c..0a02d6fd 100644 --- a/crypto/block/transaction.cpp +++ b/crypto/block/transaction.cpp @@ -672,6 +672,12 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* return false; } total_fees += in_fwd_fee; + if (account.workchain == ton::masterchainId && cfg->mc_blackhole_addr && + cfg->mc_blackhole_addr.value() == account.addr) { + blackhole_burned.grams = msg_balance_remaining.grams; + msg_balance_remaining.grams = td::zero_refint(); + LOG(DEBUG) << "Burning " << blackhole_burned.grams << " nanoton (blackhole address)"; + } return true; } @@ -2618,6 +2624,7 @@ td::Status FetchConfigParams::fetch_config_params(const block::Config& config, action_phase_cfg->workchains = &config.get_workchain_list(); action_phase_cfg->bounce_msg_body = (config.has_capability(ton::capBounceMsgBody) ? 256 : 0); action_phase_cfg->size_limits = size_limits; + action_phase_cfg->mc_blackhole_addr = config.get_burning_config().blackhole_addr; } { // fetch block_grams_created diff --git a/crypto/block/transaction.h b/crypto/block/transaction.h index 6346ddcd..bc5adff2 100644 --- a/crypto/block/transaction.h +++ b/crypto/block/transaction.h @@ -153,6 +153,7 @@ struct ActionPhaseConfig { MsgPrices fwd_mc; // from/to masterchain SizeLimitsConfig size_limits; const WorkchainSet* workchains{nullptr}; + td::optional mc_blackhole_addr; const MsgPrices& fetch_msg_prices(bool is_masterchain) const { return is_masterchain ? fwd_mc : fwd_std; } @@ -332,6 +333,7 @@ struct Transaction { td::RefInt256 due_payment; td::RefInt256 in_fwd_fee, msg_fwd_fees; block::CurrencyCollection total_fees{0}; + block::CurrencyCollection blackhole_burned{0}; ton::UnixTime last_paid; Ref root; Ref new_total_state; diff --git a/crypto/tl/tlbc.cpp b/crypto/tl/tlbc.cpp index 01b8a31a..409ac538 100644 --- a/crypto/tl/tlbc.cpp +++ b/crypto/tl/tlbc.cpp @@ -1998,7 +1998,7 @@ TypeExpr* parse_anonymous_constructor(Lexer& lex, Constructor& cs) { if (types[i].parent_type_idx >= 0) { types[i].parent_type_idx = -2; } - delete cs2; + cs2->~Constructor(); return TypeExpr::mk_apply_empty(lex.cur().loc, 0, &types[i]); } } diff --git a/flake.lock b/flake.lock index 9a8b67eb..ca44d4c0 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1650374568, - "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "owner": "edolstra", "repo": "flake-compat", - "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "type": "github" }, "original": { @@ -17,12 +17,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1652776076, - "narHash": "sha256-gzTw/v1vj4dOVbpBSJX4J0DwUR6LIyXo7/SuuTJp1kM=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "04c1b180862888302ddfb2e3ad9eaa63afc60cf8", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -33,11 +36,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1659445012, - "narHash": "sha256-n8/7npmp3hLbPSTRHPW8EPO8qh9vJ10RgkRM3Ve4vfc=", + "lastModified": 1682600000, + "narHash": "sha256-ha4BehR1dh8EnXSoE1m/wyyYVvHI9txjW4w5/oxsW5Y=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a9f66ae640146ac16b6e33d2359e9171b27b0993", + "rev": "50fc86b75d2744e1ab3837ef74b53f103a9b55a0", "type": "github" }, "original": { @@ -49,11 +52,11 @@ }, "nixpkgs-trunk": { "locked": { - "lastModified": 1659597264, - "narHash": "sha256-aI/r4XEZwMJnuDjIMnSiDm34vVXP6TPaWgqPIF/65SI=", + "lastModified": 1683098912, + "narHash": "sha256-bFHOixPoHZ5y44FvFgpEuZV0UYTQPNDZK/XqeUi1Lbs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "2b22614150a727a8aeedc10395dbd2ff6430841b", + "rev": "abc97d3572dec126eba9fec358eb2f359a944683", "type": "github" }, "original": { @@ -69,8 +72,23 @@ "nixpkgs-stable": "nixpkgs-stable", "nixpkgs-trunk": "nixpkgs-trunk" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", "version": 7 -} +} \ No newline at end of file diff --git a/flake.nix b/flake.nix index d3fca85c..36849ddf 100644 --- a/flake.nix +++ b/flake.nix @@ -31,12 +31,16 @@ openssl_1_1 zlib libmicrohttpd - ] else - [ + ] else [ (openssl_1_1.override { static = true; }).dev (zlib.override { shared = false; }).dev - pkgsStatic.libmicrohttpd.dev - ] ++ optional staticGlibc glibc.static; + ] + ++ optionals (!stdenv.isDarwin) [ pkgsStatic.libmicrohttpd.dev ] + ++ optionals stdenv.isDarwin [ (libiconv.override { enableStatic = true; enableShared = false; }) ] + ++ optionals stdenv.isDarwin (forEach [ libmicrohttpd.dev gmp.dev nettle.dev (gnutls.override { withP11-kit = false; }).dev libtasn1.dev libidn2.dev libunistring.dev gettext ] (x: x.overrideAttrs(oldAttrs: rec { configureFlags = (oldAttrs.configureFlags or []) ++ [ "--enable-static" "--disable-shared" ]; dontDisableStatic = true; }))) + ++ optionals staticGlibc [ glibc.static ]; + + dontAddStaticConfigureFlags = stdenv.isDarwin; cmakeFlags = [ "-DTON_USE_ABSEIL=OFF" "-DNIX=ON" ] ++ optionals staticMusl [ "-DCMAKE_CROSSCOMPILING=OFF" # pkgsStatic sets cross @@ -47,6 +51,7 @@ LDFLAGS = optional staticExternalDeps (concatStringsSep " " [ (optionalString stdenv.cc.isGNU "-static-libgcc") + (optionalString stdenv.isDarwin "-framework CoreFoundation") "-static-libstdc++" ]); @@ -57,6 +62,14 @@ moveToOutput bin "$bin" ''; + preFixup = optionalString stdenv.isDarwin '' + for fn in "$bin"/bin/* "$out"/lib/*.dylib; do + echo Fixing libc++ in "$fn" + install_name_tool -change "$(otool -L "$fn" | grep libc++.1 | cut -d' ' -f1 | xargs)" libc++.1.dylib "$fn" + install_name_tool -change "$(otool -L "$fn" | grep libc++abi.1 | cut -d' ' -f1 | xargs)" libc++abi.dylib "$fn" + done + ''; + outputs = [ "bin" "out" ]; }; hostPkgs = system: @@ -131,10 +144,10 @@ }; ton-staticbin-dylib = host.symlinkJoin { name = "ton"; - paths = [ ton-static.bin ton-normal.out ]; + paths = [ ton-static.bin ton-static.out ]; }; }; devShells.default = host.mkShell { inputsFrom = [ packages.ton-normal ]; }; }))); -} +} \ No newline at end of file diff --git a/recent_changelog.md b/recent_changelog.md index 39ca5c94..fe2c34b2 100644 --- a/recent_changelog.md +++ b/recent_changelog.md @@ -1,8 +1,5 @@ -## 2023.05 Update -1. Archive manager optimization -2. A series of catchain (basic consensus protocol) security improvements -3. Update for Fift libraries and FunC: better error-handling, fixes for `catch` stack recovery -4. A series of out message queue handling optimization (already deployed during emergency upgrades between releases) -5. Improvement of binaries portability +## 2023.06 Update +1. (disabled by default) New deflation mechanisms: partial fee burning and blackhole address +2. Storage-contract improvement -Besides the work of the core team, this update is based on the efforts of @aleksej-paschenko (portability improvement), [Disintar team](https://github.com/disintar/) (archive manager optimization) and [sec3-service](https://github.com/sec3-service) security auditors (funC improvements). +Besides the work of the core team, this update is based on the efforts of @DearJohnDoe from Tonbyte (Storage-contract improvement). diff --git a/storage/storage-daemon/smartcont/storage-provider-code.boc b/storage/storage-daemon/smartcont/storage-provider-code.boc index b2f96a42..e331154f 100644 Binary files a/storage/storage-daemon/smartcont/storage-provider-code.boc and b/storage/storage-daemon/smartcont/storage-provider-code.boc differ diff --git a/storage/storage-daemon/smartcont/storage-provider.fc b/storage/storage-daemon/smartcont/storage-provider.fc index dce2ea6b..07d6b563 100644 --- a/storage/storage-daemon/smartcont/storage-provider.fc +++ b/storage/storage-daemon/smartcont/storage-provider.fc @@ -2,7 +2,7 @@ #include "constants.fc"; -const min_deploy_amount = 50000000; +const min_deploy_amount = 60000000; ;; cell storage_contract_code() asm """ "storage-contract-code.boc" file>B B>boc PUSHREF """; ;; the same constant but more "compiler" friendly diff --git a/storage/storage-daemon/smartcont/storage-provider.fif b/storage/storage-daemon/smartcont/storage-provider.fif index c4503485..d926c1c6 100644 --- a/storage/storage-daemon/smartcont/storage-provider.fif +++ b/storage/storage-daemon/smartcont/storage-provider.fif @@ -143,7 +143,7 @@ PROGRAM{ IFJMP:<{ // msg_value sender_address op query_id in_msg_body s2 POP // msg_value sender_address in_msg_body query_id s0 s3 XCHG - 50000000 PUSHINT // query_id sender_address in_msg_body msg_value _29=50000000 + 60000000 PUSHINT // query_id sender_address in_msg_body msg_value _29=60000000 GEQ // query_id sender_address in_msg_body _30 1001 THROWIFNOT LDREF // query_id sender_address torrent_info in_msg_body diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 34dfca61..db86cef1 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -1393,7 +1393,13 @@ bool Collator::import_new_shard_top_blocks() { } LOG(INFO) << "total fees_imported = " << value_flow_.fees_imported.to_str() << " ; out of them, total fees_created = " << import_created_.to_str(); - value_flow_.fees_collected += value_flow_.fees_imported; + block::CurrencyCollection burned = + config_->get_burning_config().calculate_burned_fees(value_flow_.fees_imported - import_created_); + if (!burned.is_valid()) { + return fatal_error("cannot calculate amount of burned imported fees"); + } + value_flow_.burned += burned; + value_flow_.fees_collected += value_flow_.fees_imported - burned; return true; } @@ -2208,6 +2214,7 @@ Ref Collator::create_ordinary_transaction(Ref msg_root) { register_new_msgs(*trans); update_max_lt(acc->last_trans_end_lt_); + value_flow_.burned += trans->blackhole_burned; return trans_root; } @@ -3733,7 +3740,16 @@ bool Collator::compute_total_balance() { LOG(ERROR) << "cannot unpack CurrencyCollection from the root of OutMsgDescr"; return false; } - value_flow_.fees_collected += new_transaction_fees + new_import_fees; + block::CurrencyCollection total_fees = new_transaction_fees + new_import_fees; + value_flow_.fees_collected += total_fees; + if (is_masterchain()) { + block::CurrencyCollection burned = config_->get_burning_config().calculate_burned_fees(total_fees); + if (!burned.is_valid()) { + return fatal_error("cannot calculate amount of burned masterchain fees"); + } + value_flow_.fees_collected -= burned; + value_flow_.burned += burned; + } // 3. compute total_validator_fees total_validator_fees_ += value_flow_.fees_collected; total_validator_fees_ -= value_flow_.recovered; diff --git a/validator/impl/top-shard-descr.cpp b/validator/impl/top-shard-descr.cpp index c6e00edf..8ff8862d 100644 --- a/validator/impl/top-shard-descr.cpp +++ b/validator/impl/top-shard-descr.cpp @@ -62,12 +62,10 @@ td::Status ShardTopBlockDescrQ::unpack_one_proof(BlockIdExt& cur_id, Refget_workchain_list(); action_phase_cfg_.bounce_msg_body = (config_->has_capability(ton::capBounceMsgBody) ? 256 : 0); action_phase_cfg_.size_limits = size_limits; + action_phase_cfg_.mc_blackhole_addr = config_->get_burning_config().blackhole_addr; } { // fetch block_grams_created @@ -2161,6 +2162,11 @@ bool ValidateQuery::unpack_precheck_value_flow(Ref value_flow_root) { return reject_query("ValueFlow of block "s + id_.to_str() + " is invalid (non-zero recovered value in a non-masterchain block)"); } + if (!is_masterchain() && !value_flow_.burned.is_zero()) { + LOG(INFO) << "invalid value flow: " << os.str(); + return reject_query("ValueFlow of block "s + id_.to_str() + + " is invalid (non-zero burned value in a non-masterchain block)"); + } if (!value_flow_.recovered.is_zero() && recover_create_msg_.is_null()) { return reject_query("ValueFlow of block "s + id_.to_str() + " has a non-zero recovered fees value, but there is no recovery InMsg"); @@ -2243,15 +2249,10 @@ bool ValidateQuery::unpack_precheck_value_flow(Ref value_flow_root) { "cannot unpack CurrencyCollection with total transaction fees from the augmentation of the ShardAccountBlocks " "dictionary"); } - auto expected_fees = value_flow_.fees_imported + value_flow_.created + transaction_fees_ + import_fees_; - if (value_flow_.fees_collected != expected_fees) { - return reject_query(PSTRING() << "ValueFlow for " << id_.to_str() << " declares fees_collected=" - << value_flow_.fees_collected.to_str() << " but the total message import fees are " - << import_fees_ << ", the total transaction fees are " << transaction_fees_.to_str() - << ", creation fee for this block is " << value_flow_.created.to_str() - << " and the total imported fees from shards are " - << value_flow_.fees_imported.to_str() << " with a total of " - << expected_fees.to_str()); + if (is_masterchain()) { + auto x = config_->get_burning_config().calculate_burned_fees(transaction_fees_ + import_fees_); + fees_burned_ += x; + total_burned_ += x; } return true; } @@ -4564,6 +4565,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT << "transaction " << lt << " of " << addr.to_hex() << " is invalid: it has produced a set of outbound messages different from that listed in the transaction"); } + total_burned_ += trs->blackhole_burned; // check new balance and value flow auto new_balance = account.get_balance(); block::CurrencyCollection total_fees; @@ -4571,12 +4573,14 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex() << " has an invalid total_fees value"); } - if (old_balance + money_imported != new_balance + money_exported + total_fees) { - return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex() - << " violates the currency flow condition: old balance=" << old_balance.to_str() - << " + imported=" << money_imported.to_str() << " does not equal new balance=" - << new_balance.to_str() << " + exported=" << money_exported.to_str() - << " + total_fees=" << total_fees.to_str()); + if (old_balance + money_imported != new_balance + money_exported + total_fees + trs->blackhole_burned) { + return reject_query( + PSTRING() << "transaction " << lt << " of " << addr.to_hex() + << " violates the currency flow condition: old balance=" << old_balance.to_str() + << " + imported=" << money_imported.to_str() << " does not equal new balance=" << new_balance.to_str() + << " + exported=" << money_exported.to_str() << " + total_fees=" << total_fees.to_str() + << (trs->blackhole_burned.is_zero() ? "" + : PSTRING() << " burned=" << trs->blackhole_burned.to_str())); } return true; } @@ -5447,6 +5451,9 @@ bool ValidateQuery::check_mc_block_extra() { return reject_query("invalid fees_imported in value flow: declared "s + value_flow_.fees_imported.to_str() + ", correct value is " + fees_imported.to_str()); } + auto x = config_->get_burning_config().calculate_burned_fees(fees_imported - import_created_); + total_burned_ += x; + fees_burned_ += x; // ^[ prev_blk_signatures:(HashmapE 16 CryptoSignaturePair) if (prev_signatures_.not_null() && id_.seqno() == 1) { return reject_query("block contains non-empty signature set for the zero state of the masterchain"); @@ -5464,6 +5471,26 @@ bool ValidateQuery::check_mc_block_extra() { return true; } +bool ValidateQuery::postcheck_value_flow() { + auto expected_fees = + value_flow_.fees_imported + value_flow_.created + transaction_fees_ + import_fees_ - fees_burned_; + if (value_flow_.fees_collected != expected_fees) { + return reject_query(PSTRING() << "ValueFlow for " << id_.to_str() << " declares fees_collected=" + << value_flow_.fees_collected.to_str() << " but the total message import fees are " + << import_fees_ << ", the total transaction fees are " << transaction_fees_.to_str() + << ", creation fee for this block is " << value_flow_.created.to_str() + << ", the total imported fees from shards are " << value_flow_.fees_imported.to_str() + << " and the burned fees are " << fees_burned_.to_str() + << " with a total of " << expected_fees.to_str()); + } + if (total_burned_ != value_flow_.burned) { + return reject_query(PSTRING() << "invalid burned in value flow: " << id_.to_str() << " declared " + << value_flow_.burned.to_str() << ", correct value is " + << total_burned_.to_str()); + } + return true; +} + /* * * MAIN VALIDATOR FUNCTION @@ -5565,6 +5592,9 @@ bool ValidateQuery::try_validate() { if (!check_mc_state_extra()) { return reject_query("new McStateExtra is invalid"); } + if (!postcheck_value_flow()) { + return reject_query("new ValueFlow is invalid"); + } } catch (vm::VmError& err) { return fatal_error(-666, err.get_msg()); } catch (vm::VmVirtError& err) { diff --git a/validator/impl/validate-query.hpp b/validator/impl/validate-query.hpp index 4ef02c86..13a05ec4 100644 --- a/validator/impl/validate-query.hpp +++ b/validator/impl/validate-query.hpp @@ -217,7 +217,7 @@ class ValidateQuery : public td::actor::Actor { std::unique_ptr in_msg_dict_, out_msg_dict_, account_blocks_dict_; block::ValueFlow value_flow_; - block::CurrencyCollection import_created_, transaction_fees_; + block::CurrencyCollection import_created_, transaction_fees_, total_burned_{0}, fees_burned_{0}; td::RefInt256 import_fees_; ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL}; @@ -361,6 +361,7 @@ class ValidateQuery : public td::actor::Actor { bool check_one_prev_dict_update(ton::BlockSeqno seqno, Ref old_val_extra, Ref new_val_extra); bool check_mc_state_extra(); + bool postcheck_value_flow(); td::Status check_counter_update(const block::DiscountedCounter& oc, const block::DiscountedCounter& nc, unsigned expected_incr); bool check_one_block_creator_update(td::ConstBitPtr key, Ref old_val, Ref new_val);