1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

updated vm

- updated func/fift
- additional checks in block validator
- docs
- tunnel prototype in ADNL
This commit is contained in:
ton 2020-03-11 14:19:31 +04:00
parent ba76f1404e
commit 54c7a4dcc3
50 changed files with 972 additions and 300 deletions

View file

@ -48,6 +48,7 @@ set(TON_CRYPTO_SOURCE
common/refint.h
common/bigexp.h
common/util.h
common/linalloc.hpp
ellcurve/Ed25519.h
ellcurve/Fp25519.h

View file

@ -20,6 +20,7 @@
#include "block/block.h"
#include "block/block-auto.h"
#include "block/block-parse.h"
#include "block/mc-config.h"
#include "ton/ton-shard.h"
#include "common/bigexp.h"
#include "common/util.h"
@ -1602,33 +1603,46 @@ bool check_one_config_param(Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key, td::
const int mandatory_config_params[] = {18, 20, 21, 22, 23, 24, 25, 28, 34};
bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors, bool relax_par0) {
bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors, bool relax_par0,
Ref<vm::Cell> old_mparams) {
using namespace std::placeholders;
if (cell.is_null()) {
return false;
}
if (!catch_errors) {
vm::Dictionary dict{std::move(cell), 32};
for (int x : mandatory_config_params) {
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "mandatory configuration parameter #" << x << " is missing";
return false;
}
if (catch_errors) {
try {
return valid_config_data(std::move(cell), addr, false, relax_par0, std::move(old_mparams));
} catch (vm::VmError&) {
return false;
}
return dict.check_for_each(std::bind(check_one_config_param, _1, _2, addr.cbits(), relax_par0));
}
try {
vm::Dictionary dict{std::move(cell), 32};
for (int x : mandatory_config_params) {
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "mandatory configuration parameter #" << x << " is missing";
return false;
}
}
return dict.check_for_each(std::bind(check_one_config_param, _1, _2, addr.cbits(), relax_par0));
} catch (vm::VmError&) {
vm::Dictionary dict{std::move(cell), 32};
if (!dict.check_for_each(std::bind(check_one_config_param, _1, _2, addr.cbits(), relax_par0))) {
return false;
}
for (int x : mandatory_config_params) {
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "mandatory configuration parameter #" << x << " is missing";
return false;
}
}
return config_params_present(dict, dict.lookup_ref(td::BitArray<32>{9})) &&
config_params_present(dict, std::move(old_mparams));
}
bool config_params_present(vm::Dictionary& dict, Ref<vm::Cell> param_dict_root) {
auto res = block::Config::unpack_param_dict(std::move(param_dict_root));
if (res.is_error()) {
return false;
}
for (int x : res.move_as_ok()) {
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "configuration parameter #" << x
<< " (declared as mandatory in configuration parameter #9) is missing";
return false;
}
}
return true;
}
bool add_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res) {

View file

@ -606,7 +606,8 @@ bool unpack_CurrencyCollection(Ref<vm::CellSlice> csr, td::RefInt256& value, Ref
bool valid_library_collection(Ref<vm::Cell> cell, bool catch_errors = true);
bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors = true,
bool relax_par0 = false);
bool relax_par0 = false, Ref<vm::Cell> old_mparams = {});
bool config_params_present(vm::Dictionary& dict, Ref<vm::Cell> param_dict_root);
bool add_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res);
bool sub_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res);

View file

@ -572,6 +572,7 @@ _ to_mint:ExtraCurrencyCollection = ConfigParam 7;
capabilities#c4 version:uint32 capabilities:uint64 = GlobalVersion;
_ GlobalVersion = ConfigParam 8; // all zero if absent
_ mandatory_params:(Hashmap 32 True) = ConfigParam 9;
_ critical_params:(Hashmap 32 True) = ConfigParam 10;
wfmt_basic#1 vm_version:int32 vm_mode:uint64 = WorkchainFormat 1;
wfmt_ext#0 min_addr_len:(## 12) max_addr_len:(## 12) addr_len_step:(## 12)

View file

@ -40,6 +40,7 @@
#include <algorithm>
namespace block {
using namespace std::literals::string_literals;
using td::Ref;
Config::Config(Ref<vm::Cell> config_root, const td::Bits256& config_addr, int _mode)
@ -335,6 +336,59 @@ std::unique_ptr<vm::Dictionary> ShardConfig::extract_shard_hashes_dict(Ref<vm::C
}
}
td::Result<std::vector<int>> Config::unpack_param_dict(vm::Dictionary& dict) {
try {
std::vector<int> vect;
if (dict.check_for_each(
[&vect](Ref<vm::CellSlice> value, td::ConstBitPtr key, int key_len) {
bool ok = (key_len == 32 && value->empty_ext());
if (ok) {
vect.push_back((int)key.get_int(32));
}
return ok;
},
true)) {
return std::move(vect);
} else {
return td::Status::Error("invalid parameter list dictionary");
}
} catch (vm::VmError& vme) {
return td::Status::Error("error unpacking parameter list dictionary: "s + vme.get_msg());
}
}
td::Result<std::vector<int>> Config::unpack_param_dict(Ref<vm::Cell> dict_root) {
vm::Dictionary dict{std::move(dict_root), 32};
return unpack_param_dict(dict);
}
std::unique_ptr<vm::Dictionary> Config::get_param_dict(int idx) const {
return std::make_unique<vm::Dictionary>(get_config_param(idx), 32);
}
td::Result<std::vector<int>> Config::unpack_param_list(int idx) const {
return unpack_param_dict(*get_param_dict(idx));
}
bool Config::all_mandatory_params_defined(int* bad_idx_ptr) const {
auto res = get_mandatory_param_list();
if (res.is_error()) {
if (bad_idx_ptr) {
*bad_idx_ptr = -1;
}
return false;
}
for (int x : res.move_as_ok()) {
if (get_config_param(x).is_null()) {
if (bad_idx_ptr) {
*bad_idx_ptr = x;
}
return false;
}
}
return true;
}
std::unique_ptr<vm::AugmentedDictionary> ConfigInfo::create_accounts_dict() const {
if (mode & needAccountsRoot) {
return std::make_unique<vm::AugmentedDictionary>(accounts_root, 256, block::tlb::aug_ShardAccounts);

View file

@ -534,6 +534,21 @@ class Config {
bool create_stats_enabled() const {
return has_capability(ton::capCreateStatsEnabled);
}
std::unique_ptr<vm::Dictionary> get_param_dict(int idx) const;
td::Result<std::vector<int>> unpack_param_list(int idx) const;
std::unique_ptr<vm::Dictionary> get_mandatory_param_dict() const {
return get_param_dict(9);
}
std::unique_ptr<vm::Dictionary> get_critical_param_dict() const {
return get_param_dict(10);
}
td::Result<std::vector<int>> get_mandatory_param_list() const {
return unpack_param_list(9);
}
td::Result<std::vector<int>> get_critical_param_list() const {
return unpack_param_list(10);
}
bool all_mandatory_params_defined(int* bad_idx_ptr = nullptr) const;
td::Result<ton::StdSmcAddress> get_dns_root_addr() const;
bool set_block_id_ext(const ton::BlockIdExt& block_id_ext);
td::Result<std::vector<ton::StdSmcAddress>> get_special_smartcontracts(bool without_config = false) const;
@ -580,6 +595,8 @@ class Config {
static td::Result<std::unique_ptr<Config>> extract_from_state(Ref<vm::Cell> mc_state_root, int mode = 0);
static td::Result<std::unique_ptr<Config>> extract_from_key_block(Ref<vm::Cell> key_block_root, int mode = 0);
static td::Result<std::pair<ton::UnixTime, ton::UnixTime>> unpack_validator_set_start_stop(Ref<vm::Cell> root);
static td::Result<std::vector<int>> unpack_param_dict(vm::Dictionary& dict);
static td::Result<std::vector<int>> unpack_param_dict(Ref<vm::Cell> dict_root);
protected:
Config(int _mode) : mode(_mode) {

View file

@ -0,0 +1,50 @@
/*
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
*/
namespace td {
class LinearAllocator {
std::size_t size;
char *ptr, *cur, *end;
public:
LinearAllocator(std::size_t _size) : size(_size) {
cur = ptr = (char*)malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
end = ptr + size;
}
~LinearAllocator() {
free(ptr);
}
void* allocate(std::size_t count) {
char* t = cur;
cur += (count + 7) & -8;
if (cur > end) {
throw std::bad_alloc();
}
return (void*)t;
}
};
} // namespace td
inline void* operator new(std::size_t count, td::LinearAllocator& alloc) {
return alloc.allocate(count);
}

View file

@ -1288,7 +1288,9 @@ void parse_func_def(Lexer& lex) {
sym::close_scope(lex);
}
bool parse_source(std::istream* is, const src::FileDescr* fdescr) {
std::vector<const src::FileDescr*> source_fdescr;
bool parse_source(std::istream* is, src::FileDescr* fdescr) {
src::SourceReader reader{is, fdescr};
Lexer lex{reader, true, ";,()[] ~."};
while (lex.tp() != _Eof) {
@ -1306,6 +1308,7 @@ bool parse_source_file(const char* filename) {
throw src::Fatal{"source file name is an empty string"};
}
src::FileDescr* cur_source = new src::FileDescr{filename};
source_fdescr.push_back(cur_source);
std::ifstream ifs{filename};
if (ifs.fail()) {
throw src::Fatal{std::string{"cannot open source file `"} + filename + "`"};
@ -1314,7 +1317,9 @@ bool parse_source_file(const char* filename) {
}
bool parse_source_stdin() {
return parse_source(&std::cin, new src::FileDescr{"stdin", true});
src::FileDescr* cur_source = new src::FileDescr{"stdin", true};
source_fdescr.push_back(cur_source);
return parse_source(&std::cin, cur_source);
}
} // namespace funC

View file

@ -14,9 +14,10 @@
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 "srcread.h"
#include <algorithm>
namespace src {
@ -34,9 +35,47 @@ std::ostream& operator<<(std::ostream& os, const Fatal& fatal) {
return os << fatal.get_msg();
}
const char* FileDescr::convert_offset(long offset, long* line_no, long* line_pos, long* line_size) const {
long lno = 0, lpos = -1, lsize = 0;
const char* lstart = nullptr;
if (offset >= 0 && offset < (long)text.size()) {
auto it = std::upper_bound(line_offs.begin(), line_offs.end(), offset);
lno = it - line_offs.begin();
if (lno && it != line_offs.end()) {
lsize = it[0] - it[-1];
lpos = offset - it[-1];
lstart = text.data() + it[-1];
}
} else {
lno = (long)line_offs.size();
}
if (line_no) {
*line_no = lno;
}
if (line_pos) {
*line_pos = lpos;
}
if (line_size) {
*line_size = lsize;
}
return lstart;
}
const char* FileDescr::push_line(std::string new_line) {
if (line_offs.empty()) {
line_offs.push_back(0);
}
std::size_t cur_size = text.size();
text += new_line;
text += '\0';
line_offs.push_back((long)text.size());
return text.data() + cur_size;
}
void SrcLocation::show(std::ostream& os) const {
os << fdescr;
if (line_no > 0) {
long line_no, line_pos;
if (fdescr && convert_pos(&line_no, &line_pos)) {
os << ':' << line_no;
if (line_pos >= 0) {
os << ':' << (line_pos + 1);
@ -45,13 +84,15 @@ void SrcLocation::show(std::ostream& os) const {
}
bool SrcLocation::show_context(std::ostream& os) const {
if (text.empty() || line_pos < 0 || (unsigned)line_pos > text.size()) {
long line_no, line_pos, line_size;
if (!fdescr || !convert_pos(&line_no, &line_pos, &line_size)) {
return false;
}
bool skip_left = (line_pos > 200), skip_right = (line_pos + 200u < text.size());
const char* start = skip_left ? text.c_str() + line_pos - 100 : text.c_str();
const char* end = skip_right ? text.c_str() + line_pos + 100 : text.c_str() + text.size();
const char* here = text.c_str() + line_pos;
bool skip_left = (line_pos > 200), skip_right = (line_pos + 200u < line_size);
const char* here = fdescr->text.data() + char_offs;
const char* base = here - line_pos;
const char* start = skip_left ? here - 100 : base;
const char* end = skip_right ? here + 100 : base + line_size;
os << " ";
if (skip_left) {
os << "... ";
@ -99,8 +140,8 @@ void ParseError::show(std::ostream& os) const {
where.show_context(os);
}
SourceReader::SourceReader(std::istream* _is, const FileDescr* _fdescr)
: ifs(_is), loc(_fdescr), eof(false), cur_line_len(0), start(0), cur(0), end(0) {
SourceReader::SourceReader(std::istream* _is, FileDescr* _fdescr)
: ifs(_is), fdescr(_fdescr), loc(_fdescr), eof(false), cur_line_len(0), start(0), cur(0), end(0) {
load_line();
}
@ -139,7 +180,7 @@ const char* SourceReader::set_ptr(const char* ptr) {
if (ptr < cur || ptr > end) {
error("parsing position went outside of line");
}
loc.line_pos = (int)(ptr - start);
loc.char_offs += ptr - cur;
cur = ptr;
}
return ptr;
@ -149,12 +190,11 @@ bool SourceReader::load_line() {
if (eof) {
return false;
}
loc.set_eof();
if (ifs->eof()) {
set_eof();
return false;
}
++loc.line_no;
loc.line_pos = -1;
std::getline(*ifs, cur_line);
if (ifs->fail()) {
set_eof();
@ -174,11 +214,16 @@ bool SourceReader::load_line() {
cur_line.pop_back();
--len;
}
loc.text = cur_line;
cur_line_len = (int)len;
loc.line_pos = 0;
cur = start = cur_line.c_str();
end = start + cur_line_len;
if (fdescr) {
cur = start = fdescr->push_line(std::move(cur_line));
end = start + len;
loc.char_offs = (std::size_t)(cur - fdescr->text.data());
cur_line.clear();
} else {
cur = start = cur_line.c_str();
end = start + cur_line_len;
}
return true;
}

View file

@ -14,11 +14,12 @@
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 <string>
#include <vector>
#include <iostream>
namespace src {
@ -31,9 +32,13 @@ namespace src {
struct FileDescr {
std::string filename;
std::string text;
std::vector<long> line_offs;
bool is_stdin;
FileDescr(std::string _fname, bool _stdin = false) : filename(std::move(_fname)), is_stdin(_stdin) {
}
const char* push_line(std::string new_line);
const char* convert_offset(long offset, long* line_no, long* line_pos, long* line_size = nullptr) const;
};
struct Fatal {
@ -49,16 +54,23 @@ std::ostream& operator<<(std::ostream& os, const Fatal& fatal);
struct SrcLocation {
const FileDescr* fdescr;
int line_no;
int line_pos;
std::string text;
SrcLocation() : fdescr(nullptr), line_no(0), line_pos(-1) {
long char_offs;
SrcLocation() : fdescr(nullptr), char_offs(-1) {
}
SrcLocation(const FileDescr* _fdescr, int line = 0, int pos = -1) : fdescr(_fdescr), line_no(line), line_pos(pos) {
SrcLocation(const FileDescr* _fdescr, long offs = -1) : fdescr(_fdescr), char_offs(-1) {
}
bool defined() const {
return fdescr;
}
bool eof() const {
return char_offs == -1;
}
void set_eof() {
char_offs = -1;
}
const char* convert_pos(long* line_no, long* line_pos, long* line_size = nullptr) const {
return defined() ? fdescr->convert_offset(char_offs, line_no, line_pos, line_size) : nullptr;
}
void show(std::ostream& os) const;
bool show_context(std::ostream& os) const;
void show_gen_error(std::ostream& os, std::string message, std::string err_type = "") const;
@ -98,6 +110,7 @@ struct ParseError : Error {
class SourceReader {
std::istream* ifs;
FileDescr* fdescr;
SrcLocation loc;
bool eof;
std::string cur_line;
@ -106,7 +119,7 @@ class SourceReader {
const char *start, *cur, *end;
public:
SourceReader(std::istream* _is, const FileDescr* _fdescr);
SourceReader(std::istream* _is, FileDescr* _fdescr);
bool load_line();
bool is_eof() const {
return eof;

View file

@ -52,43 +52,50 @@
// elected-for elections-begin-before elections-end-before stakes-frozen
{ 4 0 reverse <b { swap 32 u, } 4 times b> 15 config! } : config.election_params!
dictnew 0 2constant validator-dict
{ @' validator-dict } : validator-dict@
{ validator-dict@ nip } : validator#
variable validator-dict
dictnew 0 validator-dict 2!
{ validator-dict @ second } : validator#
// val-pubkey weight --
{ dup 0<= abort"validator weight must be non-negative"
dup 64 ufits not abort"validator weight must fit into 64 bits"
over Blen 32 <> abort"validator public key must be 32 bytes long"
<b x{538e81278a} s, rot B, swap 64 u, b> <s
validator-dict@ dup 1+ 3 -roll swap
validator-dict 2@ dup 1+ 3 -roll swap
16 udict!+ 0= abort"cannot add validator"
swap 2 'nop does : validator-dict
swap validator-dict 2!
} : add-validator
// since-ut until-ut main-val-cnt-or-0 --
{ ?dup 0= { validator# } if
validator# 0= abort"no initial validators defined"
rot <b x{11} s, swap 32 u, rot 32 u, validator# 16 u, swap 16 u,
validator-dict@ drop <s s, b>
validator-dict @ first <s s, b>
34 config!
} : config.validators!
dictnew constant workchain-dict
variable workchain-dict
// root-hash file-hash enable-utime actual-min-split min-split max-split workchain-id --
{ <b x{a6} s, 5 roll 32 u, 4 roll 8 u, 3 roll 8 u, rot 8 u, x{e000} s,
3 roll 256 u, rot 256 u, 0 32 u, x{1} s, -1 32 i, 0 64 u, b>
dup isWorkchainDescr? not abort"invalid WorkchainDescr created"
<s swap @' workchain-dict 32 idict!+ 0= abort"cannot add workchain"
=: workchain-dict
<s swap workchain-dict @ 32 idict!+ 0= abort"cannot add workchain"
workchain-dict !
} : add-std-workchain
// --
{ @' workchain-dict dict>s s>c 12 config! } : config.workchains!
{ workchain-dict @ dict>s s>c 12 config! } : config.workchains!
dictnew constant special-dict
variable special-dict
// special-smc-addr --
{ x{} swap @' special-dict 256 udict! not abort"cannot add a new special smart contract"
=: special-dict
{ x{} swap special-dict @ 256 udict! not abort"cannot add a new special smart contract"
special-dict !
} : make_special
{ @' special-dict dict>s s>c 31 config! } : config.special!
{ special-dict @ dict>s s>c 31 config! } : config.special!
// ( l -- D ) Converts a list of parameter indices into a dictionary
{ dictnew { swap uncons -rot <b swap rot 32 b>idict! not abort"cannot add parameter index" over null?
} until nip
} : param-list-to-dict
{ param-list-to-dict 9 config! } : config.mandatory_params!
{ param-list-to-dict 10 config! } : config.critical_params!
// bit-pps cell-pps mc-bit-pps mc-cell-pps --
{ <b x{cc} s, 0 32 u, 4 roll 64 u, 3 roll 64 u, rot 64 u, swap 64 u,

View file

@ -217,6 +217,7 @@ builder pack_proposal(cell voters, int sum_weight, int vset_id, slice body) inli
int msg_seqno = cs~load_uint(32);
var valid_until = cs~load_uint(32);
throw_if(35, valid_until < now());
throw_if(39, slice_depth(cs) > 64);
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
throw_unless(33, msg_seqno == stored_seqno);
ifnot ((action - 0x566f7465) & -2) {
@ -228,6 +229,7 @@ builder pack_proposal(cell voters, int sum_weight, int vset_id, slice body) inli
stored_seqno += 1;
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
commit();
var (_, bits, refs) = cs.slice_compute_data_size(1024);
(vote_dict, var accepted) = register_vote(vote_dict, action, cs, idx, weight, total_weight, config_param(34).cell_hash());
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
ifnot (accepted.null?()) {

View file

@ -1,5 +1,7 @@
#!/usr/bin/create-state -s
"TonUtil.fif" include
"Asm.fif" include
"Lists.fif" include
def? $1 { @' $1 } { "" } cond constant suffix
{ suffix $+ } : +suffix
@ -199,6 +201,9 @@ smc1_addr config.minter_smc!
1000000000000 -17 of-cc 666666666666 239 of-cc cc+ config.to_mint!
( 9 10 18 20 21 22 23 24 25 28 34 ) config.mandatory_params!
( -1000 -1001 9 10 32 34 36 ) config.critical_params!
"validator-keys" +suffix +".pub" file>B
{ dup Blen } { 32 B| swap dup ."Validator public key = " Bx. cr
17 add-validator } while drop

View file

@ -42,8 +42,10 @@ int string_hash(slice s) asm "SHA256U";
int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU";
int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS";
(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE";
(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE";
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE";
(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
;; () throw_if(int excno, int cond) impure asm "THROWARGIF";

View file

@ -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 "GenericAccount.h"
@ -96,4 +96,19 @@ td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& ad
return res;
}
td::Result<td::Ed25519::PublicKey> GenericAccount::get_public_key(const SmartContract& sc) {
auto answer = sc.run_get_method("get_public_key");
if (!answer.success) {
return td::Status::Error("get_public_key failed");
}
auto do_get_public_key = [&]() -> td::Result<td::Ed25519::PublicKey> {
auto key = answer.stack.write().pop_int_finite();
td::SecureString bytes(32);
if (!key->export_bytes(bytes.as_mutable_slice().ubegin(), bytes.size(), false)) {
return td::Status::Error("get_public_key failed");
}
return td::Ed25519::PublicKey(std::move(bytes));
};
return TRY_VM(do_get_public_key());
}
} // namespace ton

View file

@ -14,11 +14,14 @@
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/cells.h"
#include "block/block.h"
#include "Ed25519.h"
#include "SmartContract.h"
namespace ton {
class GenericAccount {
public:
@ -27,5 +30,7 @@ class GenericAccount {
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
td::Ref<vm::Cell> body) noexcept;
static void store_int_message(vm::CellBuilder& cb, const block::StdAddress& dest_address, td::int64 gramms);
static td::Result<td::Ed25519::PublicKey> get_public_key(const SmartContract& sc);
};
} // namespace ton

View file

@ -26,7 +26,7 @@
#include "vm/cells/CellString.h"
namespace ton {
class HighloadWallet : ton::SmartContract, public WalletInterface {
class HighloadWallet : public ton::SmartContract, public WalletInterface {
public:
explicit HighloadWallet(State state) : ton::SmartContract(std::move(state)) {
}

View file

@ -26,7 +26,7 @@
#include "vm/cells/CellString.h"
namespace ton {
class HighloadWalletV2 : ton::SmartContract, public WalletInterface {
class HighloadWalletV2 : public ton::SmartContract, public WalletInterface {
public:
explicit HighloadWalletV2(State state) : ton::SmartContract(std::move(state)) {
}

View file

@ -26,7 +26,7 @@
#include "vm/cells/CellString.h"
namespace ton {
class Wallet : ton::SmartContract, public WalletInterface {
class Wallet : public ton::SmartContract, public WalletInterface {
public:
explicit Wallet(State state) : ton::SmartContract(std::move(state)) {
}

View file

@ -45,7 +45,7 @@ class WalletInterface {
virtual td::Result<td::Ref<vm::Cell>> make_a_gift_message(const td::Ed25519::PrivateKey &private_key,
td::uint32 valid_until, td::Span<Gift> gifts) const = 0;
virtual td::Result<td::Ed25519::PublicKey> get_public_key() const {
return td::Status::Error("TODO");
return td::Status::Error("Unsupported");
}
td::Result<td::Ref<vm::Cell>> get_init_message(const td::Ed25519::PrivateKey &private_key,

View file

@ -26,7 +26,7 @@
#include "vm/cells/CellString.h"
namespace ton {
class WalletV3 : ton::SmartContract, public WalletInterface {
class WalletV3 : public ton::SmartContract, public WalletInterface {
public:
explicit WalletV3(State state) : ton::SmartContract(std::move(state)) {
}

View file

@ -306,6 +306,8 @@ TEST(Tonlib, WalletV3) {
ASSERT_EQ(239u, wallet.get_wallet_id().ok());
ASSERT_EQ(123u, wallet.get_seqno().ok());
CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet.get_public_key().ok().as_octet_string());
CHECK(priv_key.get_public_key().ok().as_octet_string() ==
ton::GenericAccount::get_public_key(wallet).ok().as_octet_string());
auto gift_message = ton::GenericAccount::create_ext_message(
address, {}, wallet.make_a_gift_message(priv_key, 60, {gift}).move_as_ok());
@ -337,6 +339,7 @@ TEST(Tonlib, HighloadWallet) {
ASSERT_EQ(239u, wallet.get_wallet_id().ok());
ASSERT_EQ(0u, wallet.get_seqno().ok());
CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string());
CHECK(pub_key.as_octet_string() == ton::GenericAccount::get_public_key(wallet).ok().as_octet_string());
CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));
@ -417,6 +420,7 @@ TEST(Tonlib, HighloadWalletV2) {
{ton::HighloadWalletV2::get_init_code(-1), ton::HighloadWalletV2::get_init_data(pub_key, 239)});
ASSERT_EQ(239u, wallet.get_wallet_id().ok());
CHECK(pub_key.as_octet_string() == wallet.get_public_key().ok().as_octet_string());
CHECK(pub_key.as_octet_string() == ton::GenericAccount::get_public_key(wallet).ok().as_octet_string());
CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));

View file

@ -161,6 +161,10 @@ TEST(VM, infinity_loop_2) {
test_run_vm_raw("kpTt7ZLrig==");
}
TEST(VM, oom_1) {
test_run_vm_raw("bXflX/BvDw==");
}
TEST(VM, bigint) {
td::StringBuilder sb({}, true);

View file

@ -14,11 +14,12 @@
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 <string>
#include <vector>
#include "common/linalloc.hpp"
namespace tlbc {
@ -26,6 +27,8 @@ using src::Lexem;
using src::Lexer;
using sym::sym_idx_t;
extern td::LinearAllocator AR;
struct Type;
struct Constructor;

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include <vector>
#include <string>
@ -219,6 +219,8 @@ inline bool is_uc_ident(sym_idx_t idx) {
namespace tlbc {
td::LinearAllocator AR(1 << 22);
/*
*
* AUXILIARY DATA TYPES
@ -906,7 +908,7 @@ bool TypeExpr::no_tchk() const {
}
TypeExpr* TypeExpr::mk_intconst(const src::SrcLocation& loc, unsigned int_const) {
return new TypeExpr{loc, te_IntConst, (int)int_const};
return new (AR) TypeExpr{loc, te_IntConst, (int)int_const};
}
TypeExpr* TypeExpr::mk_intconst(const src::SrcLocation& loc, std::string int_const) {
@ -951,16 +953,16 @@ TypeExpr* TypeExpr::mk_mulint(const src::SrcLocation& loc, TypeExpr* expr1, Type
return expr2;
}
// delete expr2;
return new TypeExpr{loc, te_MulConst, val, {expr1}, expr1->negated};
return new (AR) TypeExpr{loc, te_MulConst, val, {expr1}, expr1->negated};
}
TypeExpr* TypeExpr::mk_apply(const src::SrcLocation& loc, int tp, TypeExpr* expr1, TypeExpr* expr2) {
TypeExpr* expr = new TypeExpr{loc, tp, 0, {expr1, expr2}};
TypeExpr* expr = new (AR) TypeExpr{loc, tp, 0, {expr1, expr2}};
return expr;
}
TypeExpr* TypeExpr::mk_cellref(const src::SrcLocation& loc, TypeExpr* expr1) {
TypeExpr* expr = new TypeExpr{loc, te_Ref, 0, {expr1}};
TypeExpr* expr = new (AR) TypeExpr{loc, te_Ref, 0, {expr1}};
return expr;
}
@ -1046,7 +1048,7 @@ bool TypeExpr::close(const src::SrcLocation& loc) {
}
TypeExpr* TypeExpr::mk_apply_empty(const src::SrcLocation& loc, sym_idx_t name, Type* type_applied) {
TypeExpr* expr = new TypeExpr{loc, te_Apply, name};
TypeExpr* expr = new (AR) TypeExpr{loc, te_Apply, name};
expr->type_applied = type_applied;
expr->is_nat_subtype = (type_applied->produces_nat && !type_applied->arity);
return expr;
@ -1984,7 +1986,7 @@ void parse_field_list(Lexer& lex, Constructor& cs);
TypeExpr* parse_anonymous_constructor(Lexer& lex, Constructor& cs) {
sym::open_scope(lex);
Constructor* cs2 = new Constructor(lex.cur().loc); // anonymous constructor
Constructor* cs2 = new (AR) Constructor(lex.cur().loc); // anonymous constructor
parse_field_list(lex, *cs2);
if (lex.tp() != ']') {
lex.expect(']');
@ -2089,7 +2091,7 @@ TypeExpr* parse_term(Lexer& lex, Constructor& cs, int mode) {
}
int i = sym_val->idx;
assert(i >= 0 && i < cs.fields_num);
auto res = new TypeExpr{lex.cur().loc, TypeExpr::te_Param, i};
auto res = new (AR) TypeExpr{lex.cur().loc, TypeExpr::te_Param, i};
auto field_type = cs.fields[i].type;
assert(field_type);
if ((mode & 4) && !cs.fields[i].known) {
@ -2345,7 +2347,7 @@ void parse_constructor_def(Lexer& lex) {
}
//std::cerr << "parsing constructor `" << sym::symbols.get_name(constr_name) << "` with tag " << std::hex << tag
// << std::dec << std::endl;
auto cs_ref = new Constructor(where, constr_name, 0, tag);
auto cs_ref = new (AR) Constructor(where, constr_name, 0, tag);
Constructor& cs = *cs_ref;
cs.is_special = is_special;
parse_field_list(lex, cs);
@ -2417,7 +2419,9 @@ void parse_constructor_def(Lexer& lex) {
*
*/
bool parse_source(std::istream* is, const src::FileDescr* fdescr) {
std::vector<const src::FileDescr*> source_fdescr;
bool parse_source(std::istream* is, src::FileDescr* fdescr) {
src::SourceReader reader{is, fdescr};
src::Lexer lex{reader, true, "(){}:;? #$. ^~ #", "//", "/*", "*/"};
while (lex.tp() != src::_Eof) {
@ -2432,6 +2436,7 @@ bool parse_source_file(const char* filename) {
throw src::Fatal{"source file name is an empty string"};
}
src::FileDescr* cur_source = new src::FileDescr{filename};
source_fdescr.push_back(cur_source);
std::ifstream ifs{filename};
if (ifs.fail()) {
throw src::Fatal{std::string{"cannot open source file `"} + filename + "`"};
@ -2440,7 +2445,9 @@ bool parse_source_file(const char* filename) {
}
bool parse_source_stdin() {
return parse_source(&std::cin, new src::FileDescr{"stdin", true});
src::FileDescr* cur_source = new src::FileDescr{"stdin", true};
source_fdescr.push_back(cur_source);
return parse_source(&std::cin, cur_source);
}
/*
@ -2466,7 +2473,7 @@ Type* define_builtin_type(std::string name_str, std::string args, bool produces_
}
auto sym_def = sym::define_global_symbol(name, true);
assert(sym_def);
sym_def->value = new SymValType{type};
sym_def->value = new (AR) SymValType{type};
if (size < 0) {
type->size = MinMaxSize::Any;
} else if (min_size >= 0 && min_size != size) {

View file

@ -610,30 +610,4 @@ Ref<OrdCont> OrdCont::deserialize(CellSlice& cs, int mode) {
: Ref<OrdCont>{};
}
void VmState::init_cregs(bool same_c3, bool push_0) {
cr.set_c0(quit0);
cr.set_c1(quit1);
cr.set_c2(Ref<ExcQuitCont>{true});
if (same_c3) {
cr.set_c3(Ref<OrdCont>{true, code, cp});
if (push_0) {
VM_LOG(this) << "implicit PUSH 0 at start\n";
get_stack().push_smallint(0);
}
} else {
cr.set_c3(Ref<QuitCont>{true, 11});
}
if (cr.d[0].is_null() || cr.d[1].is_null()) {
auto empty_cell = CellBuilder{}.finalize();
for (int i = 0; i < ControlRegs::dreg_num; i++) {
if (cr.d[i].is_null()) {
cr.d[i] = empty_cell;
}
}
}
if (cr.c7.is_null()) {
cr.set_c7(Ref<Tuple>{true});
}
}
} // namespace vm

View file

@ -72,6 +72,32 @@ VmState::VmState(Ref<CellSlice> _code, Ref<Stack> _stack, const GasLimits& gas,
init_cregs(flags & 1, flags & 2);
}
void VmState::init_cregs(bool same_c3, bool push_0) {
cr.set_c0(quit0);
cr.set_c1(quit1);
cr.set_c2(Ref<ExcQuitCont>{true});
if (same_c3) {
cr.set_c3(Ref<OrdCont>{true, code, cp});
if (push_0) {
VM_LOG(this) << "implicit PUSH 0 at start\n";
get_stack().push_smallint(0);
}
} else {
cr.set_c3(Ref<QuitCont>{true, 11});
}
if (cr.d[0].is_null() || cr.d[1].is_null()) {
auto empty_cell = CellBuilder{}.finalize();
for (int i = 0; i < ControlRegs::dreg_num; i++) {
if (cr.d[i].is_null()) {
cr.d[i] = empty_cell;
}
}
}
if (cr.c7.is_null()) {
cr.set_c7(Ref<Tuple>{true});
}
}
Ref<CellSlice> VmState::convert_code_cell(Ref<Cell> code_cell) {
if (code_cell.is_null()) {
return {};
@ -388,7 +414,7 @@ void VmState::change_gas_limit(long long new_limit) {
}
int VmState::step() {
assert(!code.is_null());
CHECK(code.not_null() && stack.not_null());
//VM_LOG(st) << "stack:"; stack->dump(VM_LOG(st));
//VM_LOG(st) << "; cr0.refcnt = " << get_c0()->get_refcnt() - 1 << std::endl;
if (stack_trace) {
@ -410,8 +436,9 @@ int VmState::step() {
}
int VmState::run() {
if (code.is_null()) {
throw VmError{Excno::fatal, "cannot run an uninitialized VM"};
if (code.is_null() || stack.is_null()) {
// throw VmError{Excno::fatal, "cannot run an uninitialized VM"};
return (int)Excno::fatal; // no ~ for unhandled exceptions
}
int res;
Guard guard(this);