mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated smartcontracts
- updated smartcontracts - updated fullnode database layout - fixed memory leak in blockchain-explorer - updated tonlib
This commit is contained in:
parent
9c9248a9ae
commit
c860ce3d1e
104 changed files with 7309 additions and 1335 deletions
64
crypto/vm/cells/CellString.cpp
Normal file
64
crypto/vm/cells/CellString.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "CellString.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include "vm/cells/CellSlice.h"
|
||||
|
||||
namespace vm {
|
||||
td::Status CellString::store(CellBuilder &cb, td::Slice slice, unsigned int top_bits) {
|
||||
td::uint32 size = td::narrow_cast<td::uint32>(slice.size() * 8);
|
||||
return store(cb, td::BitSlice(slice.ubegin(), size), top_bits);
|
||||
}
|
||||
|
||||
td::Status CellString::store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits) {
|
||||
if (slice.size() > max_bytes * 8) {
|
||||
return td::Status::Error("String is too long (1)");
|
||||
}
|
||||
unsigned int head = td::min(slice.size(), td::min(cb.remaining_bits(), top_bits)) / 8 * 8;
|
||||
auto max_bits = vm::Cell::max_bits / 8 * 8;
|
||||
auto depth = 1 + (slice.size() - head + max_bits - 1) / max_bits;
|
||||
if (depth > max_chain_length) {
|
||||
return td::Status::Error("String is too long (2)");
|
||||
}
|
||||
cb.append_bitslice(slice.subslice(0, head));
|
||||
slice.advance(head);
|
||||
if (slice.size() == 0) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
CellBuilder child_cb;
|
||||
store(child_cb, std::move(slice));
|
||||
cb.store_ref(child_cb.finalize());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void CellString::for_each(F &&f, CellSlice &cs, unsigned int top_bits) {
|
||||
unsigned int head = td::min(cs.size(), top_bits);
|
||||
f(cs.prefetch_bits(head));
|
||||
if (!cs.have_refs()) {
|
||||
return;
|
||||
}
|
||||
auto ref = cs.prefetch_ref();
|
||||
while (true) {
|
||||
auto cs = vm::load_cell_slice(ref);
|
||||
f(cs.prefetch_bits(cs.size()));
|
||||
if (!cs.have_refs()) {
|
||||
return;
|
||||
}
|
||||
ref = cs.prefetch_ref();
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::string> CellString::load(CellSlice &cs, unsigned int top_bits) {
|
||||
unsigned int size = 0;
|
||||
for_each([&](auto slice) { size += slice.size(); }, cs, top_bits);
|
||||
if (size % 8 != 0) {
|
||||
return td::Status::Error("Size is not divisible by 8");
|
||||
}
|
||||
std::string res(size / 8, 0);
|
||||
|
||||
td::BitPtr to(td::MutableSlice(res).ubegin());
|
||||
for_each([&](auto slice) { to.concat(slice); }, cs, top_bits);
|
||||
CHECK(to.offs == (int)size);
|
||||
return res;
|
||||
}
|
||||
} // namespace vm
|
22
crypto/vm/cells/CellString.h
Normal file
22
crypto/vm/cells/CellString.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include "vm/cells/CellBuilder.h"
|
||||
|
||||
namespace vm {
|
||||
class CellString {
|
||||
public:
|
||||
static constexpr unsigned int max_bytes = 1024;
|
||||
static constexpr unsigned int max_chain_length = 16;
|
||||
|
||||
static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits);
|
||||
static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits);
|
||||
static td::Result<td::string> load(CellSlice &cs, unsigned int top_bits = Cell::max_bits);
|
||||
|
||||
private:
|
||||
template <class F>
|
||||
static void for_each(F &&f, CellSlice &cs, unsigned int top_bits = Cell::max_bits);
|
||||
};
|
||||
|
||||
} // namespace vm
|
|
@ -744,6 +744,9 @@ int VmState::run() {
|
|||
}
|
||||
} while (!res);
|
||||
// LOG(INFO) << "[EN] data cells: " << DataCell::get_total_data_cells();
|
||||
if ((res | 1) == -1) {
|
||||
commit();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ struct ControlData {
|
|||
|
||||
class Continuation : public td::CntObject {
|
||||
public:
|
||||
virtual int jump(VmState* st) const & = 0;
|
||||
virtual int jump(VmState* st) const& = 0;
|
||||
virtual int jump_w(VmState* st) &;
|
||||
virtual ControlData* get_cdata() {
|
||||
return 0;
|
||||
|
@ -184,7 +184,7 @@ class QuitCont : public Continuation {
|
|||
QuitCont(int _code = 0) : exit_code(_code) {
|
||||
}
|
||||
~QuitCont() override = default;
|
||||
int jump(VmState* st) const & override {
|
||||
int jump(VmState* st) const& override {
|
||||
return ~exit_code;
|
||||
}
|
||||
};
|
||||
|
@ -193,7 +193,7 @@ class ExcQuitCont : public Continuation {
|
|||
public:
|
||||
ExcQuitCont() = default;
|
||||
~ExcQuitCont() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
};
|
||||
|
||||
class PushIntCont : public Continuation {
|
||||
|
@ -204,7 +204,7 @@ class PushIntCont : public Continuation {
|
|||
PushIntCont(int val, Ref<Continuation> _next) : push_val(val), next(_next) {
|
||||
}
|
||||
~PushIntCont() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
};
|
||||
|
||||
|
@ -217,7 +217,7 @@ class RepeatCont : public Continuation {
|
|||
: body(std::move(_body)), after(std::move(_after)), count(_count) {
|
||||
}
|
||||
~RepeatCont() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
};
|
||||
|
||||
|
@ -228,7 +228,7 @@ class AgainCont : public Continuation {
|
|||
AgainCont(Ref<Continuation> _body) : body(std::move(_body)) {
|
||||
}
|
||||
~AgainCont() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
};
|
||||
|
||||
|
@ -239,7 +239,7 @@ class UntilCont : public Continuation {
|
|||
UntilCont(Ref<Continuation> _body, Ref<Continuation> _after) : body(std::move(_body)), after(std::move(_after)) {
|
||||
}
|
||||
~UntilCont() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
};
|
||||
|
||||
|
@ -252,7 +252,7 @@ class WhileCont : public Continuation {
|
|||
: cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) {
|
||||
}
|
||||
~WhileCont() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
};
|
||||
|
||||
|
@ -268,7 +268,7 @@ class ArgContExt : public Continuation {
|
|||
ArgContExt(const ArgContExt&) = default;
|
||||
ArgContExt(ArgContExt&&) = default;
|
||||
~ArgContExt() override = default;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
ControlData* get_cdata() override {
|
||||
return &data;
|
||||
|
@ -303,7 +303,7 @@ class OrdCont : public Continuation {
|
|||
td::CntObject* make_copy() const override {
|
||||
return new OrdCont{*this};
|
||||
}
|
||||
int jump(VmState* st) const & override;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump_w(VmState* st) & override;
|
||||
|
||||
ControlData* get_cdata() override {
|
||||
|
@ -321,7 +321,7 @@ class OrdCont : public Continuation {
|
|||
Ref<Stack> get_stack_ref() const {
|
||||
return data.stack;
|
||||
}
|
||||
Ref<OrdCont> copy_ord() const & {
|
||||
Ref<OrdCont> copy_ord() const& {
|
||||
return Ref<OrdCont>{true, *this};
|
||||
}
|
||||
Ref<OrdCont> copy_ord() && {
|
||||
|
@ -375,10 +375,16 @@ struct GasLimits {
|
|||
}
|
||||
};
|
||||
|
||||
struct CommittedState {
|
||||
Ref<vm::Cell> c4, c5;
|
||||
bool committed{false};
|
||||
};
|
||||
|
||||
class VmState final : public VmStateInterface {
|
||||
Ref<CellSlice> code;
|
||||
Ref<Stack> stack;
|
||||
ControlRegs cr;
|
||||
CommittedState cstate;
|
||||
int cp;
|
||||
long long steps{0};
|
||||
const DispatchTable* dispatch;
|
||||
|
@ -388,6 +394,8 @@ class VmState final : public VmStateInterface {
|
|||
std::vector<Ref<Cell>> libraries;
|
||||
int stack_trace{0}, debug_off{0};
|
||||
|
||||
bool chksig_always_succeed{false};
|
||||
|
||||
public:
|
||||
static constexpr unsigned cell_load_gas_price = 100, cell_create_gas_price = 500, exception_gas_price = 50,
|
||||
tuple_entry_gas_price = 1;
|
||||
|
@ -401,6 +409,10 @@ class VmState final : public VmStateInterface {
|
|||
VmState(Ref<Cell> code_cell, Args&&... args)
|
||||
: VmState(convert_code_cell(std::move(code_cell)), std::forward<Args>(args)...) {
|
||||
}
|
||||
VmState(const VmState&) = delete;
|
||||
VmState(VmState&&) = delete;
|
||||
VmState& operator=(const VmState&) = delete;
|
||||
VmState& operator=(VmState&&) = delete;
|
||||
bool set_gas_limits(long long _max, long long _limit, long long _credit = 0);
|
||||
bool final_gas_ok() const {
|
||||
return gas.final_ok();
|
||||
|
@ -408,6 +420,12 @@ class VmState final : public VmStateInterface {
|
|||
long long gas_consumed() const {
|
||||
return gas.gas_consumed();
|
||||
}
|
||||
bool committed() const {
|
||||
return cstate.committed;
|
||||
}
|
||||
const CommittedState& get_committed_state() const {
|
||||
return cstate;
|
||||
}
|
||||
void consume_gas(long long amount) {
|
||||
gas.consume(amount);
|
||||
}
|
||||
|
@ -567,6 +585,18 @@ class VmState final : public VmStateInterface {
|
|||
return cont->is_unique() ? cont.unique_write().jump_w(this) : cont->jump(this);
|
||||
}
|
||||
static Ref<CellSlice> convert_code_cell(Ref<Cell> code_cell);
|
||||
void commit() {
|
||||
cstate.c4 = cr.d[0];
|
||||
cstate.c5 = cr.d[1];
|
||||
cstate.committed = true;
|
||||
}
|
||||
|
||||
void set_chksig_always_succeed(bool flag) {
|
||||
chksig_always_succeed = flag;
|
||||
}
|
||||
bool get_chksig_always_succeed() const {
|
||||
return chksig_always_succeed;
|
||||
}
|
||||
|
||||
private:
|
||||
void init_cregs(bool same_c3 = false, bool push_0 = true);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
enum class Excno : int {
|
||||
|
@ -95,4 +97,19 @@ struct VmVirtError {
|
|||
|
||||
struct VmFatal {};
|
||||
|
||||
template <class F>
|
||||
auto try_f(F&& f) noexcept -> decltype(f()) {
|
||||
try {
|
||||
return f();
|
||||
} catch (vm::VmError error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm exception: " << error.get_msg());
|
||||
} catch (vm::VmVirtError error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm virtualization exception: " << error.get_msg());
|
||||
} catch (vm::VmNoGas error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm no gas exception: " << error.get_msg());
|
||||
}
|
||||
}
|
||||
|
||||
#define TRY_VM(f) ::vm::try_f([&] { return f; })
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -75,10 +75,17 @@ int exec_set_gas_limit(VmState* st) {
|
|||
return exec_set_gas_generic(st, gas);
|
||||
}
|
||||
|
||||
int exec_commit(VmState* st) {
|
||||
VM_LOG(st) << "execute COMMIT";
|
||||
st->commit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void register_basic_gas_ops(OpcodeTable& cp0) {
|
||||
using namespace std::placeholders;
|
||||
cp0.insert(OpcodeInstr::mksimple(0xf800, 16, "ACCEPT", exec_accept))
|
||||
.insert(OpcodeInstr::mksimple(0xf801, 16, "SETGASLIMIT", exec_set_gas_limit));
|
||||
.insert(OpcodeInstr::mksimple(0xf801, 16, "SETGASLIMIT", exec_set_gas_limit))
|
||||
.insert(OpcodeInstr::mksimple(0xf80f, 16, "COMMIT", exec_commit));
|
||||
}
|
||||
|
||||
void register_ton_gas_ops(OpcodeTable& cp0) {
|
||||
|
@ -268,7 +275,7 @@ int exec_ed25519_check_signature(VmState* st, bool from_slice) {
|
|||
}
|
||||
td::Ed25519::PublicKey pub_key{td::SecureString(td::Slice{key, 32})};
|
||||
auto res = pub_key.verify_signature(td::Slice{data, data_len}, td::Slice{signature, 64});
|
||||
stack.push_bool(res.is_ok());
|
||||
stack.push_bool(res.is_ok() || st->get_chksig_always_succeed());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue