mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
slightly changed block format
- small change in block format - added config in blockchain explorer - bugfixes
This commit is contained in:
parent
7f3a22a217
commit
090e0c16eb
82 changed files with 1852 additions and 391 deletions
|
@ -708,6 +708,9 @@ int VmState::step() {
|
|||
}
|
||||
|
||||
int VmState::run() {
|
||||
if (code.is_null()) {
|
||||
throw VmError{Excno::fatal, "cannot run an uninitialized VM"};
|
||||
}
|
||||
int res;
|
||||
Guard guard(this);
|
||||
do {
|
||||
|
|
|
@ -237,6 +237,11 @@ class DictionaryFixed : public DictionaryBase {
|
|||
Ref<CellSlice> get_minmax_key(T& key_buffer, bool fetch_max = false, bool invert_first = false) {
|
||||
return get_minmax_key(key_buffer.bits(), key_buffer.size(), fetch_max, invert_first);
|
||||
}
|
||||
template <typename T>
|
||||
Ref<CellSlice> lookup_nearest_key(T& key_buffer, bool fetch_next = false, bool allow_eq = false,
|
||||
bool invert_first = false) {
|
||||
return lookup_nearest_key(key_buffer.bits(), key_buffer.size(), fetch_next, allow_eq, invert_first);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int label_mode() const {
|
||||
|
|
|
@ -57,6 +57,11 @@ class Atom;
|
|||
|
||||
using Tuple = td::Cnt<std::vector<StackEntry>>;
|
||||
|
||||
template <typename... Args>
|
||||
Ref<Tuple> make_tuple_ref(Args&&... args) {
|
||||
return td::make_cnt_ref<std::vector<vm::StackEntry>>(std::vector<vm::StackEntry>{std::forward<Args>(args)...});
|
||||
}
|
||||
|
||||
struct from_object_t {};
|
||||
constexpr from_object_t from_object{};
|
||||
|
||||
|
@ -192,6 +197,10 @@ class StackEntry {
|
|||
public:
|
||||
static StackEntry make_list(std::vector<StackEntry>&& elems);
|
||||
static StackEntry make_list(const std::vector<StackEntry>& elems);
|
||||
template <typename T1, typename T2>
|
||||
static StackEntry cons(T1&& x, T2&& y) {
|
||||
return StackEntry{make_tuple_ref(std::forward<T1>(x), std::forward<T2>(y))};
|
||||
}
|
||||
template <typename T>
|
||||
static StackEntry maybe(Ref<T> ref) {
|
||||
if (ref.is_null()) {
|
||||
|
@ -268,11 +277,6 @@ inline void swap(StackEntry& se1, StackEntry& se2) {
|
|||
se1.swap(se2);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Ref<Tuple> make_tuple_ref(Args&&... args) {
|
||||
return td::make_cnt_ref<std::vector<vm::StackEntry>>(std::vector<vm::StackEntry>{std::forward<Args>(args)...});
|
||||
}
|
||||
|
||||
const StackEntry& tuple_index(const Tuple& tup, unsigned idx);
|
||||
StackEntry tuple_extend_index(const Ref<Tuple>& tup, unsigned idx);
|
||||
unsigned tuple_extend_set_index(Ref<Tuple>& tup, unsigned idx, StackEntry&& value, bool force = false);
|
||||
|
|
|
@ -662,12 +662,49 @@ int exec_set_code(VmState* st) {
|
|||
return install_output_action(st, cb.finalize());
|
||||
}
|
||||
|
||||
int exec_set_lib_code(VmState* st) {
|
||||
VM_LOG(st) << "execute SETLIBCODE";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(2);
|
||||
int mode = stack.pop_smallint_range(2);
|
||||
auto code = stack.pop_cell();
|
||||
CellBuilder cb;
|
||||
if (!(cb.store_ref_bool(get_actions(st)) // out_list$_ {n:#} prev:^(OutList n)
|
||||
&& cb.store_long_bool(0x26fa1dd4, 32) // action_change_library#26fa1dd4
|
||||
&& cb.store_long_bool(mode * 2 + 1, 8) // mode:(## 7) { mode <= 2 }
|
||||
&& cb.store_ref_bool(std::move(code)))) { // libref:LibRef = OutAction;
|
||||
throw VmError{Excno::cell_ov, "cannot serialize new library code into an output action cell"};
|
||||
}
|
||||
return install_output_action(st, cb.finalize());
|
||||
}
|
||||
|
||||
int exec_change_lib(VmState* st) {
|
||||
VM_LOG(st) << "execute CHANGELIB";
|
||||
Stack& stack = st->get_stack();
|
||||
stack.check_underflow(2);
|
||||
int mode = stack.pop_smallint_range(2);
|
||||
auto hash = stack.pop_int_finite();
|
||||
if (!hash->unsigned_fits_bits(256)) {
|
||||
throw VmError{Excno::range_chk, "library hash must be non-negative"};
|
||||
}
|
||||
CellBuilder cb;
|
||||
if (!(cb.store_ref_bool(get_actions(st)) // out_list$_ {n:#} prev:^(OutList n)
|
||||
&& cb.store_long_bool(0x26fa1dd4, 32) // action_change_library#26fa1dd4
|
||||
&& cb.store_long_bool(mode * 2, 8) // mode:(## 7) { mode <= 2 }
|
||||
&& cb.store_int256_bool(hash, 256, false))) { // libref:LibRef = OutAction;
|
||||
throw VmError{Excno::cell_ov, "cannot serialize library hash into an output action cell"};
|
||||
}
|
||||
return install_output_action(st, cb.finalize());
|
||||
}
|
||||
|
||||
void register_ton_message_ops(OpcodeTable& cp0) {
|
||||
using namespace std::placeholders;
|
||||
cp0.insert(OpcodeInstr::mksimple(0xfb00, 16, "SENDRAWMSG", exec_send_raw_message))
|
||||
.insert(OpcodeInstr::mksimple(0xfb02, 16, "RESERVERAW", std::bind(exec_reserve_raw, _1, 0)))
|
||||
.insert(OpcodeInstr::mksimple(0xfb03, 16, "RESERVERAWX", std::bind(exec_reserve_raw, _1, 1)))
|
||||
.insert(OpcodeInstr::mksimple(0xfb04, 16, "SETCODE", exec_set_code));
|
||||
.insert(OpcodeInstr::mksimple(0xfb04, 16, "SETCODE", exec_set_code))
|
||||
.insert(OpcodeInstr::mksimple(0xfb06, 16, "SETLIBCODE", exec_set_lib_code))
|
||||
.insert(OpcodeInstr::mksimple(0xfb07, 16, "CHANGELIB", exec_change_lib));
|
||||
}
|
||||
|
||||
void register_ton_ops(OpcodeTable& cp0) {
|
||||
|
|
134
crypto/vm/utils.cpp
Normal file
134
crypto/vm/utils.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include "utils.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
td::Result<vm::StackEntry> convert_stack_entry(td::Slice word);
|
||||
td::Result<std::vector<vm::StackEntry>> parse_stack_entries_in(td::Slice& str, bool prefix_only = false);
|
||||
td::Result<vm::StackEntry> parse_stack_entry_in(td::Slice& str, bool prefix_only = false);
|
||||
|
||||
namespace {
|
||||
|
||||
td::Slice& skip_spaces(td::Slice& str, const char* delims) {
|
||||
while (str.size() > 0 && strchr(delims, str[0])) {
|
||||
str.remove_prefix(1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
td::Slice get_word(td::Slice& str, const char* delims, const char* specials) {
|
||||
skip_spaces(str, delims);
|
||||
|
||||
size_t p = 0;
|
||||
while (p < str.size() && !strchr(delims, str[p])) {
|
||||
if (specials && strchr(specials, str[p])) {
|
||||
if (!p) {
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
td::Slice ret = str.copy().truncate(p);
|
||||
str.remove_prefix(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
td::Result<vm::StackEntry> parse_stack_entry_in(td::Slice& str, bool prefix_only) {
|
||||
auto word = get_word(str, " \t", "[()]");
|
||||
if (word.empty()) {
|
||||
return td::Status::Error("stack value expected instead of end-of-line");
|
||||
}
|
||||
if (word.size() == 1 && (word[0] == '[' || word[0] == '(')) {
|
||||
int expected = (word[0] == '(' ? ')' : ']');
|
||||
TRY_RESULT(values, parse_stack_entries_in(str, true));
|
||||
word = get_word(str, " \t", "[()]");
|
||||
if (word.size() != 1 || word[0] != expected) {
|
||||
return td::Status::Error("closing bracket expected");
|
||||
}
|
||||
vm::StackEntry value;
|
||||
if (expected == ']') {
|
||||
value = vm::StackEntry{std::move(values)};
|
||||
} else {
|
||||
value = vm::StackEntry::make_list(std::move(values));
|
||||
}
|
||||
if (prefix_only || (skip_spaces(str, " \t").size() == 0)) {
|
||||
return value;
|
||||
} else {
|
||||
return td::Status::Error("extra data at the end");
|
||||
}
|
||||
} else {
|
||||
return convert_stack_entry(word);
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<vm::StackEntry> convert_stack_entry(td::Slice str) {
|
||||
if (str.empty() || str.size() > 65535) {
|
||||
return td::Status::Error("too long string");
|
||||
}
|
||||
int l = (int)str.size();
|
||||
if (str[0] == '"') {
|
||||
vm::CellBuilder cb;
|
||||
if (l == 1 || str.back() != '"' || l >= 127 + 2 || !cb.store_bytes_bool(str.data() + 1, l - 2)) {
|
||||
return td::Status::Error("incomplete (or too long) string");
|
||||
}
|
||||
return vm::StackEntry{vm::load_cell_slice_ref(cb.finalize())};
|
||||
}
|
||||
if (l >= 3 && (str[0] == 'x' || str[0] == 'b') && str[1] == '{' && str.back() == '}') {
|
||||
unsigned char buff[128];
|
||||
int bits =
|
||||
(str[0] == 'x')
|
||||
? (int)td::bitstring::parse_bitstring_hex_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1)
|
||||
: (int)td::bitstring::parse_bitstring_binary_literal(buff, sizeof(buff), str.begin() + 2, str.end() - 1);
|
||||
if (bits < 0) {
|
||||
return td::Status::Error("failed to parse raw b{...}/x{...} number");
|
||||
}
|
||||
return vm::StackEntry{
|
||||
Ref<vm::CellSlice>{true, vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize()}};
|
||||
}
|
||||
auto num = td::RefInt256{true};
|
||||
auto& x = num.unique_write();
|
||||
if (l >= 3 && str[0] == '0' && str[1] == 'x') {
|
||||
if (x.parse_hex(str.data() + 2, l - 2) != l - 2) {
|
||||
return td::Status::Error("failed to parse 0x... hex number");
|
||||
}
|
||||
} else if (l >= 4 && str[0] == '-' && str[1] == '0' && str[2] == 'x') {
|
||||
if (x.parse_hex(str.data() + 3, l - 3) != l - 3) {
|
||||
return td::Status::Error("failed to parse -0x... hex number");
|
||||
}
|
||||
x.negate().normalize();
|
||||
} else if (!l || x.parse_dec(str.data(), l) != l) {
|
||||
return td::Status::Error("failed to parse dec number");
|
||||
}
|
||||
return vm::StackEntry{std::move(num)};
|
||||
}
|
||||
|
||||
td::Result<std::vector<vm::StackEntry>> parse_stack_entries_in(td::Slice& str, bool prefix_only) {
|
||||
std::vector<vm::StackEntry> ret;
|
||||
while (!skip_spaces(str, " \t").empty()) {
|
||||
auto c = str.copy();
|
||||
auto word = get_word(c, " \t", "[()]");
|
||||
if (word == "]" || word == ")") {
|
||||
if (prefix_only) {
|
||||
return ret;
|
||||
} else {
|
||||
return td::Status::Error("not paired closing bracket");
|
||||
}
|
||||
}
|
||||
TRY_RESULT(value, parse_stack_entry_in(str, true));
|
||||
ret.push_back(std::move(value));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
td::Result<std::vector<vm::StackEntry>> parse_stack_entries(td::Slice str, bool prefix_only) {
|
||||
return parse_stack_entries_in(str, prefix_only);
|
||||
}
|
||||
|
||||
td::Result<vm::StackEntry> parse_stack_entry(td::Slice str, bool prefix_only) {
|
||||
return parse_stack_entry_in(str, prefix_only);
|
||||
}
|
||||
|
||||
} // namespace vm
|
11
crypto/vm/utils.h
Normal file
11
crypto/vm/utils.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
#include "stack.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace vm {
|
||||
|
||||
td::Result<std::vector<vm::StackEntry>> parse_stack_entries(td::Slice str, bool prefix_only = false);
|
||||
td::Result<vm::StackEntry> parse_stack_entry(td::Slice str, bool prefix_only = false);
|
||||
|
||||
} // namespace vm
|
Loading…
Add table
Add a link
Reference in a new issue