mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
bugfixes + doc update
This commit is contained in:
parent
77842f9b63
commit
1de39f5d7c
44 changed files with 652 additions and 272 deletions
|
@ -55,8 +55,16 @@ Ref<DataCell> CellBuilder::finalize_copy(bool special) const {
|
|||
LOG(ERROR) << res.error();
|
||||
throw CellWriteError{};
|
||||
}
|
||||
CHECK(res.ok().not_null());
|
||||
return res.move_as_ok();
|
||||
auto cell = res.move_as_ok();
|
||||
CHECK(cell.not_null());
|
||||
if (vm_state_interface) {
|
||||
vm_state_interface->register_new_cell(cell);
|
||||
if (cell.is_null()) {
|
||||
LOG(ERROR) << "cannot register new data cell";
|
||||
throw CellWriteError{};
|
||||
}
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
Ref<DataCell> CellBuilder::finalize_novm(bool special) {
|
||||
|
@ -72,10 +80,17 @@ Ref<DataCell> CellBuilder::finalize_novm(bool special) {
|
|||
|
||||
Ref<DataCell> CellBuilder::finalize(bool special) {
|
||||
auto* vm_state_interface = VmStateInterface::get();
|
||||
if (vm_state_interface) {
|
||||
vm_state_interface->register_cell_create();
|
||||
if (!vm_state_interface) {
|
||||
return finalize_novm(special);
|
||||
}
|
||||
return finalize_novm(special);
|
||||
vm_state_interface->register_cell_create();
|
||||
auto cell = finalize_novm(special);
|
||||
vm_state_interface->register_new_cell(cell);
|
||||
if (cell.is_null()) {
|
||||
LOG(ERROR) << "cannot register new data cell";
|
||||
throw CellWriteError{};
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
Ref<Cell> CellBuilder::create_pruned_branch(Ref<Cell> cell, td::uint32 new_level, td::uint32 virt_level) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "vm/dict.h"
|
||||
#include "vm/log.h"
|
||||
#include "vm/vm.h"
|
||||
#include "vm/vmstate.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
|
@ -190,6 +191,10 @@ bool ControlData::deserialize(CellSlice& cs, int mode) {
|
|||
}
|
||||
|
||||
bool Continuation::serialize_ref(CellBuilder& cb) const {
|
||||
auto* vsi = VmStateInterface::get();
|
||||
if (vsi && !vsi->register_op()) {
|
||||
return false;
|
||||
}
|
||||
vm::CellBuilder cb2;
|
||||
return serialize(cb2) && cb.store_ref_bool(cb2.finalize());
|
||||
}
|
||||
|
@ -198,6 +203,11 @@ Ref<Continuation> Continuation::deserialize(CellSlice& cs, int mode) {
|
|||
if (mode & 0x1002) {
|
||||
return {};
|
||||
}
|
||||
auto* vsi = VmStateInterface::get();
|
||||
if (vsi && !vsi->register_op()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
mode |= 0x1000;
|
||||
switch (cs.bselect_ext(6, 0x100f011100010001ULL)) {
|
||||
case 0:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "cp0.h"
|
||||
#include "opctable.h"
|
||||
|
@ -29,7 +29,8 @@
|
|||
|
||||
namespace vm {
|
||||
|
||||
const OpcodeTable* init_op_cp0() {
|
||||
const OpcodeTable* init_op_cp0(bool enable_debug) {
|
||||
set_debug_enabled(enable_debug);
|
||||
static const OpcodeTable* static_op_cp0 = [] {
|
||||
auto op_cp0 = new OpcodeTable("TEST CODEPAGE", Codepage::test_cp);
|
||||
register_stack_ops(*op_cp0); // stackops.cpp
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "vm/dispatch.h"
|
||||
|
@ -23,6 +23,6 @@ namespace vm {
|
|||
|
||||
class OpcodeTable;
|
||||
|
||||
const OpcodeTable* init_op_cp0();
|
||||
const OpcodeTable* init_op_cp0(bool debug_enabled = false);
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -28,6 +28,10 @@ namespace vm {
|
|||
|
||||
bool vm_debug_enabled = true;
|
||||
|
||||
void set_debug_enabled(bool enable_debug) {
|
||||
vm_debug_enabled = enable_debug;
|
||||
}
|
||||
|
||||
int exec_dummy_debug(VmState* st, int args) {
|
||||
VM_LOG(st) << "execute DEBUG " << (args & 0xff);
|
||||
return 0;
|
||||
|
@ -66,6 +70,9 @@ int compute_len_debug_str(const CellSlice& cs, unsigned args, int pfx_bits) {
|
|||
|
||||
int exec_dump_stack(VmState* st) {
|
||||
VM_LOG(st) << "execute DUMPSTK";
|
||||
if (!vm_debug_enabled) {
|
||||
return 0;
|
||||
}
|
||||
Stack& stack = st->get_stack();
|
||||
int d = stack.depth();
|
||||
std::cerr << "#DEBUG#: stack(" << d << " values) : ";
|
||||
|
@ -84,6 +91,9 @@ int exec_dump_stack(VmState* st) {
|
|||
int exec_dump_value(VmState* st, unsigned arg) {
|
||||
arg &= 15;
|
||||
VM_LOG(st) << "execute DUMP s" << arg;
|
||||
if (!vm_debug_enabled) {
|
||||
return 0;
|
||||
}
|
||||
Stack& stack = st->get_stack();
|
||||
if ((int)arg < stack.depth()) {
|
||||
std::cerr << "#DEBUG#: s" << arg << " = ";
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -25,5 +25,6 @@ class OpcodeTable;
|
|||
extern bool vm_debug_enabled;
|
||||
|
||||
void register_debug_ops(OpcodeTable& cp0);
|
||||
void set_debug_enabled(bool enable_debug);
|
||||
|
||||
} // namespace vm
|
||||
|
|
33
crypto/vm/memo.cpp
Normal file
33
crypto/vm/memo.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "vm/memo.h"
|
||||
#include "vm/excno.hpp"
|
||||
|
||||
namespace vm {
|
||||
using td::Ref;
|
||||
|
||||
bool FakeVmStateLimits::register_op(int op_units) {
|
||||
bool ok = (ops_remaining -= op_units) >= 0;
|
||||
if (!ok && !quiet) {
|
||||
throw VmError{Excno::out_of_gas, "too many operations"};
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace vm
|
37
crypto/vm/memo.h
Normal file
37
crypto/vm/memo.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "common/refcnt.hpp"
|
||||
#include "vm/cells.h"
|
||||
#include "vm/vmstate.h"
|
||||
|
||||
namespace vm {
|
||||
using td::Ref;
|
||||
|
||||
class FakeVmStateLimits : public VmStateInterface {
|
||||
long long ops_remaining;
|
||||
bool quiet;
|
||||
|
||||
public:
|
||||
FakeVmStateLimits(long long max_ops = 1LL << 62, bool _quiet = true) : ops_remaining(max_ops), quiet(_quiet) {
|
||||
}
|
||||
bool register_op(int op_units = 1) override;
|
||||
};
|
||||
|
||||
} // namespace vm
|
|
@ -20,6 +20,7 @@
|
|||
#include "vm/continuation.h"
|
||||
#include "vm/box.hpp"
|
||||
#include "vm/atom.h"
|
||||
#include "vm/vmstate.h"
|
||||
|
||||
namespace td {
|
||||
template class td::Cnt<std::string>;
|
||||
|
@ -678,6 +679,10 @@ void Stack::push_maybe_cellslice(Ref<CellSlice> cs) {
|
|||
*/
|
||||
|
||||
bool StackEntry::serialize(vm::CellBuilder& cb, int mode) const {
|
||||
auto* vsi = VmStateInterface::get();
|
||||
if (vsi && !vsi->register_op()) {
|
||||
return false;
|
||||
}
|
||||
switch (tp) {
|
||||
case t_null:
|
||||
return cb.store_long_bool(0, 8); // vm_stk_null#00 = VmStackValue;
|
||||
|
@ -739,6 +744,10 @@ bool StackEntry::serialize(vm::CellBuilder& cb, int mode) const {
|
|||
}
|
||||
|
||||
bool StackEntry::deserialize(CellSlice& cs, int mode) {
|
||||
auto* vsi = VmStateInterface::get();
|
||||
if (vsi && !vsi->register_op()) {
|
||||
return false;
|
||||
}
|
||||
clear();
|
||||
int t = (mode & 0xf000) ? ((mode >> 12) & 15) : (int)cs.prefetch_ulong(8);
|
||||
switch (t) {
|
||||
|
@ -843,6 +852,10 @@ bool StackEntry::deserialize(Ref<Cell> cell, int mode) {
|
|||
}
|
||||
|
||||
bool Stack::serialize(vm::CellBuilder& cb, int mode) const {
|
||||
auto* vsi = VmStateInterface::get();
|
||||
if (vsi && !vsi->register_op()) {
|
||||
return false;
|
||||
}
|
||||
// vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack;
|
||||
unsigned n = depth();
|
||||
if (!cb.store_ulong_rchk_bool(n, 24)) { // vm_stack#_ depth:(## 24)
|
||||
|
@ -863,6 +876,10 @@ bool Stack::serialize(vm::CellBuilder& cb, int mode) const {
|
|||
}
|
||||
|
||||
bool Stack::deserialize(vm::CellSlice& cs, int mode) {
|
||||
auto* vsi = VmStateInterface::get();
|
||||
if (vsi && !vsi->register_op()) {
|
||||
return false;
|
||||
}
|
||||
clear();
|
||||
// vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack;
|
||||
int n;
|
||||
|
|
|
@ -53,6 +53,23 @@ int exec_null_swap_if(VmState* st, bool cond, int depth) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int exec_null_swap_if_many(VmState* st, bool cond, int depth, int count) {
|
||||
Stack& stack = st->get_stack();
|
||||
VM_LOG(st) << "execute NULL" << (depth ? "ROTR" : "SWAP") << (cond ? "IF" : "IFNOT") << count;
|
||||
stack.check_underflow(depth + 1);
|
||||
auto x = stack.pop_int_finite();
|
||||
if (!x->sgn() != cond) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
stack.push({});
|
||||
}
|
||||
for (int i = 0; i < depth; i++) {
|
||||
swap(stack[i], stack[i + count]);
|
||||
}
|
||||
}
|
||||
stack.push_int(std::move(x));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec_mktuple_common(VmState* st, unsigned n) {
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(n);
|
||||
|
@ -374,6 +391,10 @@ void register_tuple_ops(OpcodeTable& cp0) {
|
|||
.insert(OpcodeInstr::mksimple(0x6fa1, 16, "NULLSWAPIFNOT", std::bind(exec_null_swap_if, _1, false, 0)))
|
||||
.insert(OpcodeInstr::mksimple(0x6fa2, 16, "NULLROTRIF", std::bind(exec_null_swap_if, _1, true, 1)))
|
||||
.insert(OpcodeInstr::mksimple(0x6fa3, 16, "NULLROTRIFNOT", std::bind(exec_null_swap_if, _1, false, 1)))
|
||||
.insert(OpcodeInstr::mksimple(0x6fa4, 16, "NULLSWAPIF2", std::bind(exec_null_swap_if_many, _1, true, 0, 2)))
|
||||
.insert(OpcodeInstr::mksimple(0x6fa5, 16, "NULLSWAPIFNOT2", std::bind(exec_null_swap_if_many, _1, false, 0, 2)))
|
||||
.insert(OpcodeInstr::mksimple(0x6fa6, 16, "NULLROTRIF2", std::bind(exec_null_swap_if_many, _1, true, 1, 2)))
|
||||
.insert(OpcodeInstr::mksimple(0x6fa7, 16, "NULLROTRIFNOT2", std::bind(exec_null_swap_if_many, _1, false, 1, 2)))
|
||||
.insert(OpcodeInstr::mkfixed(0x6fb, 12, 4, dump_tuple_index2, exec_tuple_index2))
|
||||
.insert(OpcodeInstr::mkfixed(0x6fc >> 2, 10, 6, dump_tuple_index3, exec_tuple_index3));
|
||||
}
|
||||
|
|
|
@ -28,12 +28,16 @@ using td::Ref;
|
|||
class VmStateInterface : public td::Context<VmStateInterface> {
|
||||
public:
|
||||
virtual ~VmStateInterface() = default;
|
||||
virtual Ref<vm::Cell> load_library(
|
||||
virtual Ref<Cell> load_library(
|
||||
td::ConstBitPtr hash) { // may throw a dictionary exception; returns nullptr if library is not found
|
||||
return {};
|
||||
}
|
||||
virtual void register_cell_load(const CellHash& cell_hash){};
|
||||
virtual void register_cell_create(){};
|
||||
virtual void register_new_cell(Ref<DataCell>& cell){};
|
||||
virtual bool register_op(int op_units = 1) {
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace vm
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue