mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-14 12:12:21 +00:00
bugfixes
This commit is contained in:
parent
a73d202ba2
commit
28735ddc9e
21 changed files with 856 additions and 218 deletions
|
@ -164,7 +164,9 @@ void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
|
|||
// accepted
|
||||
// delivering
|
||||
|
||||
add_received_packet(static_cast<td::uint32>(packet.seqno()));
|
||||
if (packet.seqno() > 0) {
|
||||
add_received_packet(static_cast<td::uint32>(packet.seqno()));
|
||||
}
|
||||
|
||||
if (packet.confirm_seqno() > ack_seqno_) {
|
||||
ack_seqno_ = packet.confirm_seqno();
|
||||
|
|
|
@ -388,7 +388,7 @@ HttpAnswer& HttpAnswer::operator<<(AccountCell acc_c) {
|
|||
<< "<input type=\"text\" class=\"form-control mr-2\" name=\"method\" placeholder=\"method\">"
|
||||
<< "</div>\n"
|
||||
<< "<div class=\"form-group col-lg-4 col-md-6\">"
|
||||
<< "<input type=\"text\" class=\"form-control mr-2\" name=\"params\" placeholder=\"paramerers\"></div>"
|
||||
<< "<input type=\"text\" class=\"form-control mr-2\" name=\"params\" placeholder=\"parameters\"></div>"
|
||||
<< "<input type=\"hidden\" name=\"account\" value=\"" << acc_c.addr.rserialize(true) << "\">"
|
||||
<< "<input type=\"hidden\" name=\"workchain\" value=\"" << block_id.id.workchain << "\">"
|
||||
<< "<input type=\"hidden\" name=\"shard\" value=\"" << ton::shard_to_str(block_id.id.shard) << "\">"
|
||||
|
|
|
@ -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 "common/refint.h"
|
||||
#include <utility>
|
||||
|
@ -213,12 +213,18 @@ int sgn(RefInt256 x) {
|
|||
return x->sgn();
|
||||
}
|
||||
|
||||
extern RefInt256 make_refint(long long x) {
|
||||
RefInt256 make_refint(long long x) {
|
||||
auto xx = td::RefInt256{true, x};
|
||||
xx.unique_write().normalize();
|
||||
return xx;
|
||||
}
|
||||
|
||||
RefInt256 bits_to_refint(td::ConstBitPtr bits, int n, bool sgnd) {
|
||||
td::RefInt256 x{true};
|
||||
x.unique_write().import_bits(bits, n, sgnd);
|
||||
return x;
|
||||
}
|
||||
|
||||
std::string dec_string(RefInt256 x) {
|
||||
return x.is_null() ? "(null)" : (x.is_unique() ? x.unique_write().to_dec_string_destroy() : x->to_dec_string());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -101,6 +101,7 @@ extern int cmp(RefInt256 x, long long y);
|
|||
extern int sgn(RefInt256 x);
|
||||
|
||||
extern RefInt256 make_refint(long long x);
|
||||
extern RefInt256 bits_to_refint(td::ConstBitPtr bits, int n, bool sgnd = false);
|
||||
|
||||
extern std::string dec_string(RefInt256 x);
|
||||
extern std::string dec_string2(RefInt256&& x);
|
||||
|
|
|
@ -1556,64 +1556,69 @@ void interpret_dict_get(vm::Stack& stack, int sgnd, int mode) {
|
|||
}
|
||||
}
|
||||
|
||||
void interpret_dict_map(IntCtx& ctx) {
|
||||
void interpret_dict_map(IntCtx& ctx, bool ext, bool sgnd) {
|
||||
auto func = pop_exec_token(ctx);
|
||||
int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits);
|
||||
vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary::simple_map_func_t simple_map = [&ctx, func](vm::CellBuilder& cb, Ref<vm::CellSlice> cs_ref) -> bool {
|
||||
ctx.stack.push_builder(Ref<vm::CellBuilder>(cb));
|
||||
ctx.stack.push_cellslice(std::move(cs_ref));
|
||||
func->run(ctx);
|
||||
assert(cb.is_unique());
|
||||
if (!ctx.stack.pop_bool()) {
|
||||
return false;
|
||||
vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n}, dict2{n};
|
||||
for (auto entry : dict.range(false, sgnd)) {
|
||||
ctx.stack.push_builder(Ref<vm::CellBuilder>{true});
|
||||
if (ext) {
|
||||
ctx.stack.push_int(dict.key_as_integer(entry.first, sgnd));
|
||||
}
|
||||
ctx.stack.push_cellslice(std::move(entry.second));
|
||||
func->run(ctx);
|
||||
if (ctx.stack.pop_bool()) {
|
||||
if (!dict2.set_builder(entry.first, n, ctx.stack.pop_builder())) {
|
||||
throw IntError{"cannot insert value into dictionary"};
|
||||
}
|
||||
}
|
||||
Ref<vm::CellBuilder> cb_ref = ctx.stack.pop_builder();
|
||||
cb = *cb_ref;
|
||||
return true;
|
||||
};
|
||||
dict.map(std::move(simple_map));
|
||||
ctx.stack.push_maybe_cell(std::move(dict).extract_root_cell());
|
||||
ctx.stack.push_maybe_cell(std::move(dict2).extract_root_cell());
|
||||
}
|
||||
|
||||
void interpret_dict_map_ext(IntCtx& ctx, bool sgnd) {
|
||||
void interpret_dict_foreach(IntCtx& ctx, bool reverse, bool sgnd) {
|
||||
auto func = pop_exec_token(ctx);
|
||||
int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits);
|
||||
vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary::map_func_t map_func = [&ctx, func, sgnd](vm::CellBuilder& cb, Ref<vm::CellSlice> cs_ref,
|
||||
td::ConstBitPtr key, int key_len) -> bool {
|
||||
ctx.stack.push_builder(Ref<vm::CellBuilder>(cb));
|
||||
td::RefInt256 x{true};
|
||||
x.unique_write().import_bits(key, key_len, sgnd);
|
||||
ctx.stack.push_int(std::move(x));
|
||||
ctx.stack.push_cellslice(std::move(cs_ref));
|
||||
for (auto entry : dict.range(reverse, sgnd)) {
|
||||
ctx.stack.push_int(dict.key_as_integer(entry.first, sgnd));
|
||||
ctx.stack.push_cellslice(std::move(entry.second));
|
||||
func->run(ctx);
|
||||
assert(cb.is_unique());
|
||||
if (!ctx.stack.pop_bool()) {
|
||||
return false;
|
||||
ctx.stack.push_bool(false);
|
||||
return;
|
||||
}
|
||||
Ref<vm::CellBuilder> cb_ref = ctx.stack.pop_builder();
|
||||
cb = *cb_ref;
|
||||
return true;
|
||||
};
|
||||
dict.map(std::move(map_func));
|
||||
ctx.stack.push_maybe_cell(std::move(dict).extract_root_cell());
|
||||
ctx.stack.push_bool(true);
|
||||
}
|
||||
|
||||
void interpret_dict_foreach(IntCtx& ctx, bool sgnd) {
|
||||
// mode: +1 = reverse, +2 = signed, +4 = strict, +8 = lookup backwards, +16 = with hint
|
||||
void interpret_dict_foreach_from(IntCtx& ctx, int mode) {
|
||||
if (mode < 0) {
|
||||
mode = ctx.stack.pop_smallint_range(31);
|
||||
}
|
||||
auto func = pop_exec_token(ctx);
|
||||
int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits);
|
||||
vm::Dictionary dict{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary::foreach_func_t foreach_func = [&ctx, func, sgnd](Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key,
|
||||
int key_len) -> bool {
|
||||
td::RefInt256 x{true};
|
||||
x.unique_write().import_bits(key, key_len, sgnd);
|
||||
ctx.stack.push_int(std::move(x));
|
||||
ctx.stack.push_cellslice(std::move(cs_ref));
|
||||
vm::DictIterator it{dict, mode & 3};
|
||||
unsigned char buffer[vm::Dictionary::max_key_bytes];
|
||||
for (int s = (mode >> 4) & 1; s >= 0; --s) {
|
||||
auto key = dict.integer_key(ctx.stack.pop_int(), n, mode & 2, buffer);
|
||||
if (!key.is_valid()) {
|
||||
throw IntError{"not enough bits for a dictionary key"};
|
||||
}
|
||||
it.lookup(key, mode & 4, mode & 8);
|
||||
}
|
||||
for (; !it.eof(); ++it) {
|
||||
ctx.stack.push_int(dict.key_as_integer(it.cur_pos(), mode & 2));
|
||||
ctx.stack.push_cellslice(it.cur_value());
|
||||
func->run(ctx);
|
||||
return ctx.stack.pop_bool();
|
||||
if (!ctx.stack.pop_bool()) {
|
||||
ctx.stack.push_bool(false);
|
||||
return;
|
||||
}
|
||||
};
|
||||
ctx.stack.push_bool(dict.check_for_each(std::move(foreach_func), sgnd));
|
||||
ctx.stack.push_bool(true);
|
||||
}
|
||||
|
||||
void interpret_dict_merge(IntCtx& ctx) {
|
||||
|
@ -1621,24 +1626,33 @@ void interpret_dict_merge(IntCtx& ctx) {
|
|||
int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits);
|
||||
vm::Dictionary dict2{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary dict1{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary::simple_combine_func_t simple_combine = [&ctx, func](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
|
||||
Ref<vm::CellSlice> cs2_ref) -> bool {
|
||||
ctx.stack.push_builder(Ref<vm::CellBuilder>(cb));
|
||||
ctx.stack.push_cellslice(std::move(cs1_ref));
|
||||
ctx.stack.push_cellslice(std::move(cs2_ref));
|
||||
func->run(ctx);
|
||||
assert(cb.is_unique());
|
||||
if (!ctx.stack.pop_bool()) {
|
||||
return false;
|
||||
vm::Dictionary dict3{n};
|
||||
auto it1 = dict1.begin(), it2 = dict2.begin();
|
||||
while (!it1.eof() || !it2.eof()) {
|
||||
int c = it1.eof() ? 1 : (it2.eof() ? -1 : it1.cur_pos().compare(it2.cur_pos(), n));
|
||||
bool ok = true;
|
||||
if (c < 0) {
|
||||
ok = dict3.set(it1.cur_pos(), n, it1.cur_value());
|
||||
++it1;
|
||||
} else if (c > 0) {
|
||||
ok = dict3.set(it2.cur_pos(), n, it2.cur_value());
|
||||
++it2;
|
||||
} else {
|
||||
ctx.stack.push_builder(Ref<vm::CellBuilder>{true});
|
||||
ctx.stack.push_cellslice(it1.cur_value());
|
||||
ctx.stack.push_cellslice(it2.cur_value());
|
||||
func->run(ctx);
|
||||
if (ctx.stack.pop_bool()) {
|
||||
ok = dict3.set_builder(it1.cur_pos(), n, ctx.stack.pop_builder());
|
||||
}
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
if (!ok) {
|
||||
throw IntError{"cannot insert value into dictionary"};
|
||||
}
|
||||
Ref<vm::CellBuilder> cb_ref = ctx.stack.pop_builder();
|
||||
cb = *cb_ref;
|
||||
return true;
|
||||
};
|
||||
if (!dict1.combine_with(dict2, std::move(simple_combine))) {
|
||||
throw IntError{"cannot combine dictionaries"};
|
||||
}
|
||||
ctx.stack.push_maybe_cell(std::move(dict1).extract_root_cell());
|
||||
ctx.stack.push_maybe_cell(std::move(dict3).extract_root_cell());
|
||||
}
|
||||
|
||||
void interpret_dict_diff(IntCtx& ctx) {
|
||||
|
@ -1646,17 +1660,40 @@ void interpret_dict_diff(IntCtx& ctx) {
|
|||
int n = ctx.stack.pop_smallint_range(vm::Dictionary::max_key_bits);
|
||||
vm::Dictionary dict2{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary dict1{ctx.stack.pop_maybe_cell(), n};
|
||||
vm::Dictionary::scan_diff_func_t scan_value_pair =
|
||||
[&ctx, func](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> cs1_ref, Ref<vm::CellSlice> cs2_ref) -> bool {
|
||||
td::RefInt256 x{true};
|
||||
x.unique_write().import_bits(key, key_len, false);
|
||||
ctx.stack.push_int(std::move(x));
|
||||
ctx.stack.push_maybe_cellslice(std::move(cs1_ref));
|
||||
ctx.stack.push_maybe_cellslice(std::move(cs2_ref));
|
||||
func->run(ctx);
|
||||
return ctx.stack.pop_bool();
|
||||
};
|
||||
ctx.stack.push_bool(dict1.scan_diff(dict2, std::move(scan_value_pair)));
|
||||
auto it1 = dict1.begin(), it2 = dict2.begin();
|
||||
while (!it1.eof() || !it2.eof()) {
|
||||
int c = it1.eof() ? 1 : (it2.eof() ? -1 : it1.cur_pos().compare(it2.cur_pos(), n));
|
||||
bool run = true;
|
||||
if (c < 0) {
|
||||
ctx.stack.push_int(dict1.key_as_integer(it1.cur_pos()));
|
||||
ctx.stack.push_cellslice(it1.cur_value());
|
||||
ctx.stack.push_null();
|
||||
++it1;
|
||||
} else if (c > 0) {
|
||||
ctx.stack.push_int(dict2.key_as_integer(it2.cur_pos()));
|
||||
ctx.stack.push_null();
|
||||
ctx.stack.push_cellslice(it2.cur_value());
|
||||
++it2;
|
||||
} else {
|
||||
if (!it1.cur_value()->contents_equal(*it2.cur_value())) {
|
||||
ctx.stack.push_int(dict1.key_as_integer(it1.cur_pos()));
|
||||
ctx.stack.push_cellslice(it1.cur_value());
|
||||
ctx.stack.push_cellslice(it2.cur_value());
|
||||
} else {
|
||||
run = false;
|
||||
}
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
if (run) {
|
||||
func->run(ctx);
|
||||
if (!ctx.stack.pop_bool()) {
|
||||
ctx.stack.push_bool(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.stack.push_bool(true);
|
||||
}
|
||||
|
||||
void interpret_pfx_dict_add(vm::Stack& stack, vm::Dictionary::SetMode mode, bool add_builder) {
|
||||
|
@ -2776,11 +2813,14 @@ void init_words_common(Dictionary& d) {
|
|||
d.def_stack_word("pfxdict!+ ", std::bind(interpret_pfx_dict_add, _1, vm::Dictionary::SetMode::Add, false));
|
||||
d.def_stack_word("pfxdict! ", std::bind(interpret_pfx_dict_add, _1, vm::Dictionary::SetMode::Set, false));
|
||||
d.def_stack_word("pfxdict@ ", interpret_pfx_dict_get);
|
||||
d.def_ctx_word("dictmap ", interpret_dict_map);
|
||||
d.def_ctx_word("dictmapext ", std::bind(interpret_dict_map_ext, _1, false));
|
||||
d.def_ctx_word("idictmapext ", std::bind(interpret_dict_map_ext, _1, true));
|
||||
d.def_ctx_word("dictforeach ", std::bind(interpret_dict_foreach, _1, false));
|
||||
d.def_ctx_word("idictforeach ", std::bind(interpret_dict_foreach, _1, true));
|
||||
d.def_ctx_word("dictmap ", std::bind(interpret_dict_map, _1, false, false));
|
||||
d.def_ctx_word("dictmapext ", std::bind(interpret_dict_map, _1, true, false));
|
||||
d.def_ctx_word("idictmapext ", std::bind(interpret_dict_map, _1, true, true));
|
||||
d.def_ctx_word("dictforeach ", std::bind(interpret_dict_foreach, _1, false, false));
|
||||
d.def_ctx_word("idictforeach ", std::bind(interpret_dict_foreach, _1, false, true));
|
||||
d.def_ctx_word("dictforeachrev ", std::bind(interpret_dict_foreach, _1, true, false));
|
||||
d.def_ctx_word("idictforeachrev ", std::bind(interpret_dict_foreach, _1, true, true));
|
||||
d.def_ctx_word("dictforeachfromx ", std::bind(interpret_dict_foreach_from, _1, -1));
|
||||
d.def_ctx_word("dictmerge ", interpret_dict_merge);
|
||||
d.def_ctx_word("dictdiff ", interpret_dict_diff);
|
||||
// slice/bitstring constants
|
||||
|
|
|
@ -362,6 +362,8 @@ bool apply_op(StackTransform& trans, const AsmOp& op) {
|
|||
return trans.apply_pop(op.a);
|
||||
case AsmOp::a_const:
|
||||
return !op.a && op.b == 1 && trans.apply_push_newconst();
|
||||
case AsmOp::a_custom:
|
||||
return op.is_gconst() && trans.apply_push_newconst();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -905,6 +905,7 @@ struct AsmOp {
|
|||
int t{a_none};
|
||||
int indent{0};
|
||||
int a, b, c;
|
||||
bool gconst{false};
|
||||
std::string op;
|
||||
struct SReg {
|
||||
int idx;
|
||||
|
@ -923,6 +924,7 @@ struct AsmOp {
|
|||
AsmOp(int _t, int _a, int _b) : t(_t), a(_a), b(_b) {
|
||||
}
|
||||
AsmOp(int _t, int _a, int _b, std::string _op) : t(_t), a(_a), b(_b), op(std::move(_op)) {
|
||||
compute_gconst();
|
||||
}
|
||||
AsmOp(int _t, int _a, int _b, int _c) : t(_t), a(_a), b(_b), c(_c) {
|
||||
}
|
||||
|
@ -931,6 +933,9 @@ struct AsmOp {
|
|||
void out(std::ostream& os) const;
|
||||
void out_indent_nl(std::ostream& os, bool no_nl = false) const;
|
||||
std::string to_string() const;
|
||||
void compute_gconst() {
|
||||
gconst = (is_custom() && (op == "PUSHNULL" || op == "NEWC"));
|
||||
}
|
||||
bool is_nop() const {
|
||||
return t == a_none && op.empty();
|
||||
}
|
||||
|
@ -977,7 +982,7 @@ struct AsmOp {
|
|||
return t == a_const && !a && b == 1;
|
||||
}
|
||||
bool is_gconst() const {
|
||||
return (t == a_const || t == a_custom) && !a && b == 1;
|
||||
return !a && b == 1 && (t == a_const || gconst);
|
||||
}
|
||||
static AsmOp Nop() {
|
||||
return AsmOp(a_none);
|
||||
|
@ -1305,6 +1310,8 @@ struct StackTransform {
|
|||
bool is_const_rot(int* c) const;
|
||||
bool is_const_pop(int c, int i) const;
|
||||
bool is_const_pop(int* c, int* i) const;
|
||||
bool is_push_const(int i, int c) const;
|
||||
bool is_push_const(int* i, int* c) const;
|
||||
|
||||
void show(std::ostream& os, int mode = 0) const;
|
||||
|
||||
|
@ -1363,27 +1370,27 @@ struct Optimizer {
|
|||
void show_left() const;
|
||||
void show_right() const;
|
||||
bool find_const_op(int* op_idx, int cst);
|
||||
bool is_const_push_swap() const;
|
||||
bool rewrite_const_push_swap();
|
||||
bool is_push_const(int* i, int* c) const;
|
||||
bool rewrite_push_const(int i, int c);
|
||||
bool is_const_push_xchgs();
|
||||
bool rewrite_const_push_xchgs();
|
||||
bool is_const_rot(int* c) const;
|
||||
bool rewrite_const_rot(int c);
|
||||
bool is_const_pop(int* c, int* i) const;
|
||||
bool rewrite_const_pop(int c, int i);
|
||||
bool simple_rewrite(int p, AsmOp&& new_op);
|
||||
bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2);
|
||||
bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3);
|
||||
bool simple_rewrite(AsmOp&& new_op) {
|
||||
return simple_rewrite(p_, std::move(new_op));
|
||||
bool rewrite(int p, AsmOp&& new_op);
|
||||
bool rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2);
|
||||
bool rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3);
|
||||
bool rewrite(AsmOp&& new_op) {
|
||||
return rewrite(p_, std::move(new_op));
|
||||
}
|
||||
bool simple_rewrite(AsmOp&& new_op1, AsmOp&& new_op2) {
|
||||
return simple_rewrite(p_, std::move(new_op1), std::move(new_op2));
|
||||
bool rewrite(AsmOp&& new_op1, AsmOp&& new_op2) {
|
||||
return rewrite(p_, std::move(new_op1), std::move(new_op2));
|
||||
}
|
||||
bool simple_rewrite(AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) {
|
||||
return simple_rewrite(p_, std::move(new_op1), std::move(new_op2), std::move(new_op3));
|
||||
bool rewrite(AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) {
|
||||
return rewrite(p_, std::move(new_op1), std::move(new_op2), std::move(new_op3));
|
||||
}
|
||||
bool simple_rewrite_nop();
|
||||
bool rewrite_nop();
|
||||
bool is_pred(const std::function<bool(const StackTransform&)>& pred, int min_p = 2);
|
||||
bool is_same_as(const StackTransform& trans, int min_p = 2);
|
||||
bool is_rot();
|
||||
|
|
|
@ -144,18 +144,22 @@ bool Optimizer::find_const_op(int* op_idx, int cst) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Optimizer::is_const_push_swap() const {
|
||||
return l_ >= 3 && op_[0]->is_gconst() && op_[1]->is_push() && op_[1]->a >= 1 && op_[2]->is_swap();
|
||||
bool Optimizer::is_push_const(int* i, int* c) const {
|
||||
return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_push_const(i, c);
|
||||
}
|
||||
|
||||
// PUSHCONST c ; PUSH s(i+1) ; SWAP -> PUSH s(i) ; PUSHCONST c
|
||||
bool Optimizer::rewrite_const_push_swap() {
|
||||
p_ = 3;
|
||||
bool Optimizer::rewrite_push_const(int i, int c) {
|
||||
p_ = pb_;
|
||||
q_ = 2;
|
||||
int idx = -1;
|
||||
if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) {
|
||||
return false;
|
||||
}
|
||||
show_left();
|
||||
oq_[1] = std::move(op_[0]);
|
||||
oq_[0] = std::move(op_[1]);
|
||||
(oq_[0]->a)--;
|
||||
oq_[1] = std::move(op_[idx]);
|
||||
oq_[0] = std::move(op_[!idx]);
|
||||
*oq_[0] = AsmOp::Push(i);
|
||||
show_right();
|
||||
return true;
|
||||
}
|
||||
|
@ -173,7 +177,7 @@ bool Optimizer::rewrite_const_rot(int c) {
|
|||
}
|
||||
show_left();
|
||||
oq_[0] = std::move(op_[idx]);
|
||||
oq_[1] = std::move(op_[idx ? 0 : 1]);
|
||||
oq_[1] = std::move(op_[!idx]);
|
||||
*oq_[1] = AsmOp::Custom("ROT", 3, 3);
|
||||
show_right();
|
||||
return true;
|
||||
|
@ -192,7 +196,7 @@ bool Optimizer::rewrite_const_pop(int c, int i) {
|
|||
}
|
||||
show_left();
|
||||
oq_[0] = std::move(op_[idx]);
|
||||
oq_[1] = std::move(op_[idx ? 0 : 1]);
|
||||
oq_[1] = std::move(op_[!idx]);
|
||||
*oq_[1] = AsmOp::Pop(i);
|
||||
show_right();
|
||||
return true;
|
||||
|
@ -284,7 +288,7 @@ bool Optimizer::rewrite_const_push_xchgs() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::simple_rewrite(int p, AsmOp&& new_op) {
|
||||
bool Optimizer::rewrite(int p, AsmOp&& new_op) {
|
||||
assert(p > 0 && p <= l_);
|
||||
p_ = p;
|
||||
q_ = 1;
|
||||
|
@ -295,7 +299,7 @@ bool Optimizer::simple_rewrite(int p, AsmOp&& new_op) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) {
|
||||
bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) {
|
||||
assert(p > 1 && p <= l_);
|
||||
p_ = p;
|
||||
q_ = 2;
|
||||
|
@ -308,7 +312,7 @@ bool Optimizer::simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) {
|
||||
bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) {
|
||||
assert(p > 2 && p <= l_);
|
||||
p_ = p;
|
||||
q_ = 3;
|
||||
|
@ -323,7 +327,7 @@ bool Optimizer::simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&&
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::simple_rewrite_nop() {
|
||||
bool Optimizer::rewrite_nop() {
|
||||
assert(p_ > 0 && p_ <= l_);
|
||||
q_ = 0;
|
||||
show_left();
|
||||
|
@ -526,41 +530,36 @@ bool Optimizer::find_at_least(int pb) {
|
|||
pb_ = pb;
|
||||
// show_stack_transforms();
|
||||
int i = -100, j = -100, k = -100, c = 0;
|
||||
return (is_const_push_swap() && 3 >= pb && rewrite_const_push_swap()) || (is_nop() && simple_rewrite_nop()) ||
|
||||
return (is_push_const(&i, &c) && rewrite_push_const(i, c)) || (is_nop() && rewrite_nop()) ||
|
||||
(!(mode_ & 1) && is_const_rot(&c) && rewrite_const_rot(c)) ||
|
||||
(is_const_push_xchgs() && rewrite_const_push_xchgs()) || (is_const_pop(&c, &i) && rewrite_const_pop(c, i)) ||
|
||||
(is_xchg(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && simple_rewrite(AsmOp::Push(i))) ||
|
||||
(is_pop(&i) && simple_rewrite(AsmOp::Pop(i))) ||
|
||||
(is_xchg(&i, &j) && rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && rewrite(AsmOp::Push(i))) ||
|
||||
(is_pop(&i) && rewrite(AsmOp::Pop(i))) ||
|
||||
(!(mode_ & 1) &&
|
||||
((is_rot() && simple_rewrite(AsmOp::Custom("ROT", 3, 3))) ||
|
||||
(is_rotrev() && simple_rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
|
||||
(is_2dup() && simple_rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
|
||||
(is_2swap() && simple_rewrite(AsmOp::Custom("2SWAP", 2, 4))) ||
|
||||
(is_2over() && simple_rewrite(AsmOp::Custom("2OVER", 2, 4))) ||
|
||||
(is_tuck() && simple_rewrite(AsmOp::Custom("TUCK", 2, 3))) ||
|
||||
(is_2drop() && simple_rewrite(AsmOp::Custom("2DROP", 2, 0))) ||
|
||||
(is_xchg2(&i, &j) && simple_rewrite(AsmOp::Xchg2(i, j))) ||
|
||||
(is_xcpu(&i, &j) && simple_rewrite(AsmOp::XcPu(i, j))) ||
|
||||
(is_puxc(&i, &j) && simple_rewrite(AsmOp::PuXc(i, j))) ||
|
||||
(is_push2(&i, &j) && simple_rewrite(AsmOp::Push2(i, j))) ||
|
||||
(is_blkswap(&i, &j) && simple_rewrite(AsmOp::BlkSwap(i, j))) ||
|
||||
(is_blkpush(&i, &j) && simple_rewrite(AsmOp::BlkPush(i, j))) ||
|
||||
(is_blkdrop(&i) && simple_rewrite(AsmOp::BlkDrop(i))) ||
|
||||
(is_reverse(&i, &j) && simple_rewrite(AsmOp::BlkReverse(i, j))) ||
|
||||
(is_nip_seq(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
|
||||
(is_pop_blkdrop(&i, &k) && simple_rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
|
||||
(is_blkdrop2(&i, &j) && simple_rewrite(AsmOp::BlkDrop2(i, j))) ||
|
||||
((is_rot() && rewrite(AsmOp::Custom("ROT", 3, 3))) || (is_rotrev() && rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
|
||||
(is_2dup() && rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
|
||||
(is_2swap() && rewrite(AsmOp::Custom("2SWAP", 2, 4))) ||
|
||||
(is_2over() && rewrite(AsmOp::Custom("2OVER", 2, 4))) ||
|
||||
(is_tuck() && rewrite(AsmOp::Custom("TUCK", 2, 3))) ||
|
||||
(is_2drop() && rewrite(AsmOp::Custom("2DROP", 2, 0))) || (is_xchg2(&i, &j) && rewrite(AsmOp::Xchg2(i, j))) ||
|
||||
(is_xcpu(&i, &j) && rewrite(AsmOp::XcPu(i, j))) || (is_puxc(&i, &j) && rewrite(AsmOp::PuXc(i, j))) ||
|
||||
(is_push2(&i, &j) && rewrite(AsmOp::Push2(i, j))) || (is_blkswap(&i, &j) && rewrite(AsmOp::BlkSwap(i, j))) ||
|
||||
(is_blkpush(&i, &j) && rewrite(AsmOp::BlkPush(i, j))) || (is_blkdrop(&i) && rewrite(AsmOp::BlkDrop(i))) ||
|
||||
(is_reverse(&i, &j) && rewrite(AsmOp::BlkReverse(i, j))) ||
|
||||
(is_nip_seq(&i, &j) && rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
|
||||
(is_pop_blkdrop(&i, &k) && rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
|
||||
(is_blkdrop2(&i, &j) && rewrite(AsmOp::BlkDrop2(i, j))) ||
|
||||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
|
||||
? simple_rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
|
||||
: simple_rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
|
||||
(is_xchg3(&i, &j, &k) && simple_rewrite(AsmOp::Xchg3(i, j, k))) ||
|
||||
(is_xc2pu(&i, &j, &k) && simple_rewrite(AsmOp::Xc2Pu(i, j, k))) ||
|
||||
(is_xcpuxc(&i, &j, &k) && simple_rewrite(AsmOp::XcPuXc(i, j, k))) ||
|
||||
(is_xcpu2(&i, &j, &k) && simple_rewrite(AsmOp::XcPu2(i, j, k))) ||
|
||||
(is_puxc2(&i, &j, &k) && simple_rewrite(AsmOp::PuXc2(i, j, k))) ||
|
||||
(is_puxcpu(&i, &j, &k) && simple_rewrite(AsmOp::PuXcPu(i, j, k))) ||
|
||||
(is_pu2xc(&i, &j, &k) && simple_rewrite(AsmOp::Pu2Xc(i, j, k))) ||
|
||||
(is_push3(&i, &j, &k) && simple_rewrite(AsmOp::Push3(i, j, k)))));
|
||||
? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
|
||||
: rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
|
||||
(is_xchg3(&i, &j, &k) && rewrite(AsmOp::Xchg3(i, j, k))) ||
|
||||
(is_xc2pu(&i, &j, &k) && rewrite(AsmOp::Xc2Pu(i, j, k))) ||
|
||||
(is_xcpuxc(&i, &j, &k) && rewrite(AsmOp::XcPuXc(i, j, k))) ||
|
||||
(is_xcpu2(&i, &j, &k) && rewrite(AsmOp::XcPu2(i, j, k))) ||
|
||||
(is_puxc2(&i, &j, &k) && rewrite(AsmOp::PuXc2(i, j, k))) ||
|
||||
(is_puxcpu(&i, &j, &k) && rewrite(AsmOp::PuXcPu(i, j, k))) ||
|
||||
(is_pu2xc(&i, &j, &k) && rewrite(AsmOp::Pu2Xc(i, j, k))) ||
|
||||
(is_push3(&i, &j, &k) && rewrite(AsmOp::Push3(i, j, k)))));
|
||||
}
|
||||
|
||||
bool Optimizer::find() {
|
||||
|
|
|
@ -891,6 +891,15 @@ bool StackTransform::is_const_pop(int *c, int *i) const {
|
|||
}
|
||||
}
|
||||
|
||||
// PUSH i ; PUSHCONST c == c i 0 1 2 ...
|
||||
bool StackTransform::is_push_const(int i, int c) const {
|
||||
return is_valid() && d == -2 && c <= c_start && i >= 0 && is_trivial_after(2) && get(0) == c && get(1) == i;
|
||||
}
|
||||
|
||||
bool StackTransform::is_push_const(int *i, int *c) const {
|
||||
return is_valid() && d == -2 && n == 2 && is_push_const(*i = get(1), *c = get(0));
|
||||
}
|
||||
|
||||
void StackTransform::show(std::ostream &os, int mode) const {
|
||||
if (!is_valid()) {
|
||||
os << "<invalid>";
|
||||
|
|
|
@ -7,8 +7,14 @@
|
|||
{ dictnew { over null? not } { swap uncons swap rot +dictpair } while nip } : mkdict
|
||||
{ dup null? { ."(null) " drop } { val@ . } cond } : .val
|
||||
{ key-bits { swap . ."-> " .val ."; " true } dictforeach drop cr } : show-dict
|
||||
{ key-bits { swap . ."-> " .val ."; " true } idictforeach drop cr } : show-idict
|
||||
{ key-bits { swap . ."-> " .val ."; " true } dictforeachrev drop cr } : show-rev-dict
|
||||
{ key-bits { swap . ."-> " .val ."; " true } idictforeachrev drop cr } : show-rev-idict
|
||||
{ key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-dict-diff
|
||||
{ key-bits { val@ swap val@ + val, true } dictmerge } : dict-sum
|
||||
{ key-bits { val@ 2* val, true } dictmap } : dict-twice
|
||||
{ key-bits { val@ 2 /mod { 2drop false } { val, true } cond } dictmap } : dict-half
|
||||
{ key-bits { val@ + val, true } dictmapext } : dict-add-x
|
||||
{ null swap key-bits { val@ pair swap cons true } dictforeach drop } : dict>list-rev
|
||||
{ dict>list-rev list-reverse } : dict>list
|
||||
( _( 13 169 ) _( 17 289 ) _( 10 100 ) ) mkdict =: Dict
|
||||
|
@ -22,3 +28,7 @@ Dict2 dict>list .l cr
|
|||
Dict2 <s csr. cr
|
||||
Dict1 Dict2 show-dict-diff
|
||||
Dict2 Dict1 show-dict-diff
|
||||
."Dict1 + Dict2 = " Dict1 Dict2 dict-sum show-dict
|
||||
."Dict2 * 2 = " Dict2 dict-twice show-dict
|
||||
."Dict2 / 2 = " Dict2 dict-half show-dict
|
||||
."Dict2 + x = " Dict2 dict-add-x show-dict
|
||||
|
|
52
crypto/test/fift/testdict2.fif
Normal file
52
crypto/test/fift/testdict2.fif
Normal file
|
@ -0,0 +1,52 @@
|
|||
"Lists.fif" include
|
||||
16 constant key-bits
|
||||
16 constant val-bits
|
||||
{ val-bits u, } : val,
|
||||
{ val-bits u@ } : val@
|
||||
{ swap unpair <b swap val, b> <s swap rot key-bits udict! not abort"cannot add key-value" } : +dictpair
|
||||
{ dictnew { over null? not } { swap uncons swap rot +dictpair } while nip } : mkdict
|
||||
{ dup null? { ."(null) " drop } { val@ . } cond } : .val
|
||||
{ key-bits { swap . ."-> " .val ."; " true } dictforeach drop cr } : show-dict
|
||||
{ key-bits { swap . ."-> " .val ."; " true } idictforeach drop cr } : show-idict
|
||||
{ key-bits { swap . ."-> " .val ."; " true } dictforeachrev drop cr } : show-rev-dict
|
||||
{ key-bits { swap . ."-> " .val ."; " true } idictforeachrev drop cr } : show-rev-idict
|
||||
{ key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-dict-diff
|
||||
{ key-bits { swap . ."-> " .val ."; " true } rot dictforeachfromx drop cr } : show-dict-from
|
||||
{ key-bits { val@ swap val@ + val, true } dictmerge } : dict-sum
|
||||
{ key-bits { val@ 2* val, true } dictmap } : dict-twice
|
||||
{ key-bits { val@ 2 /mod { 2drop false } { val, true } cond } dictmap } : dict-half
|
||||
{ key-bits { val@ + val, true } dictmapext } : dict-add-x
|
||||
{ null swap key-bits { val@ pair swap cons true } dictforeach drop } : dict>list-rev
|
||||
{ dict>list-rev list-reverse } : dict>list
|
||||
( _( 13 169 ) _( 17 289 ) _( 10 100 ) ) mkdict =: Dict
|
||||
_( 4 16 ) _( 9 81 ) Dict +dictpair +dictpair =: Dict1
|
||||
_( 4 20 ) _( 101 10201 ) Dict +dictpair +dictpair =: Dict2
|
||||
_( 65533 9 ) Dict2 +dictpair =: Dict3
|
||||
."Dict1 = " Dict1 show-idict
|
||||
."Dict2 = " Dict2 show-idict
|
||||
."Dict3 = " Dict3 show-idict
|
||||
variable D
|
||||
{ D ! } : D!
|
||||
{ ."D = " D @ show-idict } : show-D
|
||||
{ D @ 2 show-dict-from } : show-D-from
|
||||
{ D @ 6 show-dict-from } : show-D-from+
|
||||
{ D @ 18 show-dict-from } : show-D-from-hint
|
||||
{ D @ 22 show-dict-from } : show-D-from-hint+
|
||||
variable hint hint 0!
|
||||
{ ."D[" dup ._ ."..] = " show-D-from } : test-from
|
||||
{ ."D[" dup ._ ."+..] = " show-D-from+ } : test-from+
|
||||
{ hint @ ."(hint=" dup ._ .") D[" over ._ ."..] = " show-D-from-hint } : test-from-hint
|
||||
{ hint @ ."(hint=" dup ._ .") D[" over ._ ."+..] = " show-D-from-hint+ } : test-from-hint+
|
||||
{ -16 { 2dup swap execute 1+ } 120 times 2drop } : range-run
|
||||
{ hint ! ' test-from-hint range-run ' test-from-hint+ range-run } : range-test-hint
|
||||
|
||||
{ ."------- BIG TEST -------" cr show-D
|
||||
' test-from range-run ' test-from+ range-run
|
||||
0 range-test-hint 13 range-test-hint 7 range-test-hint 100 range-test-hint
|
||||
} : big-test
|
||||
Dict1 D!
|
||||
big-test
|
||||
Dict2 D!
|
||||
big-test
|
||||
Dict3 D!
|
||||
big-test
|
|
@ -1308,6 +1308,294 @@ Ref<Cell> Dictionary::extract_minmax_key_ref(td::BitPtr key_buffer, int key_len,
|
|||
return extract_value_ref(extract_minmax_key(key_buffer, key_len, fetch_max, invert_first));
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ITERATORS (to be moved into a separate file)
|
||||
*
|
||||
*/
|
||||
|
||||
bool DictIterator::prevalidate(int mode) {
|
||||
if (key_bits_ <= 0 || key_bits_ > Dictionary::max_key_bits) {
|
||||
reset();
|
||||
flags_ &= ~f_valid;
|
||||
key_bits_ = 0;
|
||||
return false;
|
||||
} else {
|
||||
if (mode >= 0) {
|
||||
order_ = -(mode & 1) ^ ((mode >> 1) & 1);
|
||||
}
|
||||
flags_ |= f_valid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DictIterator::bind(const DictionaryFixed& dict, int do_rewind) {
|
||||
if (!is_valid() || !is_bound_to(dict)) {
|
||||
return false;
|
||||
}
|
||||
dict_ = &dict;
|
||||
label_mode_ = dict.label_mode();
|
||||
return !do_rewind || rewind(do_rewind < 0);
|
||||
}
|
||||
|
||||
bool DictIterator::rebind_to(const DictionaryFixed& dict, int do_rewind) {
|
||||
reset();
|
||||
dict_ = &dict;
|
||||
label_mode_ = dict.label_mode();
|
||||
root_ = dict.get_root_cell();
|
||||
key_bits_ = dict.get_key_bits();
|
||||
flags_ &= 3;
|
||||
return prevalidate() && (!do_rewind || rewind(do_rewind < 0));
|
||||
}
|
||||
|
||||
int DictIterator::compare_keys(td::ConstBitPtr a, td::ConstBitPtr b) const {
|
||||
if (!key_bits_) {
|
||||
return 0;
|
||||
}
|
||||
int c = (int)*a - (int)*b;
|
||||
if (c) {
|
||||
return (order_ & 1) ? -c : c;
|
||||
}
|
||||
c = a.compare(b, key_bits_);
|
||||
return order_ >= 0 ? c : -c;
|
||||
}
|
||||
|
||||
bool DictIterator::dive(int mode) {
|
||||
int n = key_bits_, m = 0;
|
||||
Ref<Cell> node = path_.empty() ? root_ : path_.back().next;
|
||||
if (!path_.empty()) {
|
||||
m = path_.back().pos + 1;
|
||||
n -= m;
|
||||
mode >>= 1;
|
||||
}
|
||||
// similar to dict_lookup_minmax: create new path down until the leaf
|
||||
while (1) {
|
||||
LabelParser label{std::move(node), n, label_mode_};
|
||||
int l = label.extract_label_to(key(m));
|
||||
assert(l >= 0 && l <= n);
|
||||
m += l;
|
||||
n -= l;
|
||||
if (!n) {
|
||||
leaf_ = std::move(label.remainder);
|
||||
return true;
|
||||
}
|
||||
if (l) {
|
||||
mode >>= 1;
|
||||
}
|
||||
int bit = mode & 1;
|
||||
node = label.remainder->prefetch_ref(bit);
|
||||
auto alt = label.remainder->prefetch_ref(1 - bit);
|
||||
path_.emplace_back(node, std::move(alt), m, bit);
|
||||
*key(m++) = (bool)bit;
|
||||
--n;
|
||||
mode >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool DictIterator::rewind(bool to_end) {
|
||||
if (!is_valid()) {
|
||||
return false;
|
||||
}
|
||||
if (root_.is_null()) {
|
||||
return true;
|
||||
}
|
||||
auto node = root_;
|
||||
int k = 0, mode = order_ ^ -(int)to_end;
|
||||
// NB: can optimize by reusing several first entries of current path_
|
||||
while (k < (int)path_.size()) {
|
||||
auto& pe = path_[k++];
|
||||
assert(pe.pos >= 0 && pe.pos < key_bits_);
|
||||
if (pe.pos) {
|
||||
mode >>= 1;
|
||||
}
|
||||
if (pe.v != (bool)(mode & 1)) {
|
||||
// went different way at this node before, rotate and stop going down
|
||||
pe.rotate(key());
|
||||
leaf_.clear();
|
||||
path_.resize(k); // drop the remainder of the original path after first incorrect branch
|
||||
return dive(mode);
|
||||
}
|
||||
mode >>= 1;
|
||||
}
|
||||
return !eof() || dive(mode);
|
||||
}
|
||||
|
||||
bool DictIterator::next(bool go_back) {
|
||||
if (!is_valid() || root_.is_null() || eof()) {
|
||||
return false;
|
||||
}
|
||||
leaf_.clear();
|
||||
int mode = order_ ^ -(int)go_back;
|
||||
while (!path_.empty()) {
|
||||
auto& pe = path_.back();
|
||||
int bit = (mode >> (pe.pos > 0)) & 1;
|
||||
if (pe.v == bit) {
|
||||
pe.rotate(key());
|
||||
return dive(mode);
|
||||
}
|
||||
path_.pop_back();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DictIterator::lookup(td::ConstBitPtr pos, int pos_bits, bool strict_after, bool backw) {
|
||||
if (!is_valid() || root_.is_null() || pos_bits < 0 || pos_bits > key_bits_) {
|
||||
return false;
|
||||
}
|
||||
int fill_mode = -(strict_after ^ backw) ^ order_;
|
||||
if (!eof()) {
|
||||
// reuse part of current path
|
||||
std::size_t bp0 = 0;
|
||||
int bp;
|
||||
if (!key().compare(pos, pos_bits, &bp0)) {
|
||||
bp = pos_bits;
|
||||
if (bp >= key_bits_) {
|
||||
// already at the desired element
|
||||
return !strict_after || next(backw);
|
||||
}
|
||||
} else {
|
||||
bp = (int)bp0;
|
||||
}
|
||||
int k = 0;
|
||||
while (k < (int)path_.size() && path_[k].pos <= bp) {
|
||||
auto& pe = path_[k];
|
||||
if (pe.pos == bp) {
|
||||
if (bp < pos_bits || pe.v != ((fill_mode >> (bp > 0)) & 1)) {
|
||||
// rotate the last path element if it branched in incorrect direction
|
||||
path_[k++].rotate(key());
|
||||
}
|
||||
break;
|
||||
}
|
||||
++k;
|
||||
}
|
||||
path_.resize(k); // drop the remainder of the path
|
||||
}
|
||||
int m = 0, n = key_bits_;
|
||||
auto node = path_.empty() ? root_ : path_.back().next;
|
||||
if (!path_.empty()) {
|
||||
m = path_.back().pos + 1; // m <= pos_bits + 1
|
||||
n -= m;
|
||||
}
|
||||
int mode = -backw ^ order_, action = 0;
|
||||
while (m < pos_bits && !action) {
|
||||
LabelParser label{std::move(node), n, label_mode_};
|
||||
int pfx_len = label.common_prefix_len(pos + m, pos_bits - m);
|
||||
int l = label.extract_label_to(key() + m);
|
||||
assert(pfx_len >= 0 && pfx_len <= label.l_bits && label.l_bits <= n);
|
||||
if (pfx_len == pos_bits - m) {
|
||||
// end of given position prefix
|
||||
if (strict_after) {
|
||||
// have to backtrace
|
||||
action = 2;
|
||||
break;
|
||||
} else {
|
||||
// label has correct prefix, register and dive down
|
||||
action = 1;
|
||||
}
|
||||
} else if (pfx_len < l) {
|
||||
// all subtree is either smaller or larger than required
|
||||
if (pos[m + pfx_len] != ((mode >> (int)(m + pfx_len > 0)) & 1)) {
|
||||
// label smaller than required, have to backtrace
|
||||
action = 2;
|
||||
break;
|
||||
} else {
|
||||
// label larger than required, register node and dive down
|
||||
action = 1;
|
||||
}
|
||||
}
|
||||
// if we are here, then either action=1 (dive down activated)
|
||||
// ... or l = pfx_len < pos_bits - m
|
||||
// continue going down
|
||||
m += l;
|
||||
n -= l;
|
||||
if (!n) {
|
||||
// key found in a leaf
|
||||
leaf_ = std::move(label.remainder);
|
||||
return true;
|
||||
}
|
||||
bool bit = action ? ((mode >> (m > 0)) & 1) : pos[m];
|
||||
node = label.remainder->prefetch_ref(bit);
|
||||
auto alt = label.remainder->prefetch_ref(1 - bit);
|
||||
path_.emplace_back(node, std::move(alt), m, bit);
|
||||
*key(m++) = (bool)bit;
|
||||
--n;
|
||||
}
|
||||
if (!action) {
|
||||
action = (strict_after ? 2 : 1);
|
||||
}
|
||||
if (action == 2) {
|
||||
// have to backtrace to the "next" larger branch
|
||||
// similar to next()
|
||||
leaf_.clear();
|
||||
while (!path_.empty()) {
|
||||
auto& pe = path_.back();
|
||||
int bit = (mode >> (pe.pos > 0)) & 1;
|
||||
if (pe.v == bit) {
|
||||
pe.rotate(key());
|
||||
return dive(mode);
|
||||
}
|
||||
path_.pop_back();
|
||||
}
|
||||
return false; // eof: no suitable element
|
||||
}
|
||||
// action=1, dive down
|
||||
return dive(mode);
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::null_iterator() {
|
||||
force_validate();
|
||||
return DictIterator{*this};
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::make_iterator(int mode) {
|
||||
force_validate();
|
||||
DictIterator it{*this, mode};
|
||||
it.rewind();
|
||||
return it;
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::init_iterator(bool backw, bool invert_first) {
|
||||
return make_iterator((int)backw + 2 * (int)invert_first);
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::begin() {
|
||||
return init_iterator();
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::end() {
|
||||
return null_iterator();
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::cbegin() {
|
||||
return begin();
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::cend() {
|
||||
return end();
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::rbegin() {
|
||||
return init_iterator(true);
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::rend() {
|
||||
return null_iterator();
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::crbegin() {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
DictIterator DictionaryFixed::crend() {
|
||||
return rend();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* END (ITERATORS)
|
||||
*
|
||||
*/
|
||||
|
||||
std::pair<Ref<Cell>, bool> DictionaryFixed::extract_prefix_subdict_internal(Ref<Cell> dict, td::ConstBitPtr prefix,
|
||||
int prefix_len, bool remove_prefix) const {
|
||||
if (is_empty() || prefix_len <= 0) {
|
||||
|
@ -2309,6 +2597,14 @@ Ref<CellSlice> AugmentedDictionary::get_node_extra(Ref<Cell> cell_ref, int n) co
|
|||
return {};
|
||||
}
|
||||
|
||||
Ref<CellSlice> AugmentedDictionary::extract_leaf_value(Ref<CellSlice> leaf) const {
|
||||
if (leaf.not_null() && aug.skip_extra(leaf.write())) {
|
||||
return std::move(leaf);
|
||||
} else {
|
||||
return Ref<CellSlice>{};
|
||||
}
|
||||
}
|
||||
|
||||
Ref<CellSlice> AugmentedDictionary::get_root_extra() const {
|
||||
return get_node_extra(root_cell, key_bits);
|
||||
}
|
||||
|
|
176
crypto/vm/dict.h
176
crypto/vm/dict.h
|
@ -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 "common/bitstring.h"
|
||||
|
@ -171,6 +171,13 @@ class DictionaryBase {
|
|||
}
|
||||
};
|
||||
|
||||
class DictIterator;
|
||||
|
||||
template <typename T>
|
||||
std::pair<T, int> dict_range(T&& dict, bool rev = false, bool sgnd = false) {
|
||||
return std::pair<T, int>{std::forward<T>(dict), (int)rev + 2 * (int)sgnd};
|
||||
}
|
||||
|
||||
class DictionaryFixed : public DictionaryBase {
|
||||
public:
|
||||
typedef std::function<int(vm::CellSlice&, td::ConstBitPtr, int)> filter_func_t;
|
||||
|
@ -199,6 +206,9 @@ class DictionaryFixed : public DictionaryBase {
|
|||
static BitSlice integer_key(td::RefInt256 x, unsigned n, bool sgnd = true, unsigned char buffer[128] = 0,
|
||||
bool quiet = false);
|
||||
static bool integer_key_simple(td::RefInt256 x, unsigned n, bool sgnd, td::BitPtr buffer, bool quiet = false);
|
||||
td::RefInt256 key_as_integer(td::ConstBitPtr key, bool sgnd = false) const {
|
||||
return td::bits_to_refint(key, key_bits, sgnd);
|
||||
}
|
||||
bool key_exists(td::ConstBitPtr key, int key_len);
|
||||
bool int_key_exists(long long key);
|
||||
bool uint_key_exists(unsigned long long key);
|
||||
|
@ -221,6 +231,17 @@ class DictionaryFixed : public DictionaryBase {
|
|||
bool scan_diff(DictionaryFixed& dict2, const scan_diff_func_t& diff_func, int check_augm = 0);
|
||||
bool validate_check(const foreach_func_t& foreach_func, bool invert_first = false);
|
||||
bool validate_all();
|
||||
DictIterator null_iterator();
|
||||
DictIterator init_iterator(bool backw = false, bool invert_first = false);
|
||||
DictIterator make_iterator(int mode);
|
||||
DictIterator begin();
|
||||
DictIterator end();
|
||||
DictIterator cbegin();
|
||||
DictIterator cend();
|
||||
DictIterator rbegin();
|
||||
DictIterator rend();
|
||||
DictIterator crbegin();
|
||||
DictIterator crend();
|
||||
template <typename T>
|
||||
bool key_exists(const T& key) {
|
||||
return key_exists(key.bits(), key.size());
|
||||
|
@ -247,6 +268,9 @@ class DictionaryFixed : public DictionaryBase {
|
|||
virtual int label_mode() const {
|
||||
return dict::LabelParser::chk_all;
|
||||
}
|
||||
virtual Ref<CellSlice> extract_leaf_value(Ref<CellSlice> leaf) const {
|
||||
return leaf;
|
||||
}
|
||||
virtual Ref<Cell> finish_create_leaf(CellBuilder& cb, const CellSlice& value) const;
|
||||
virtual Ref<Cell> finish_create_fork(CellBuilder& cb, Ref<Cell> c1, Ref<Cell> c2, int n) const;
|
||||
virtual bool check_fork(CellSlice& cs, Ref<Cell> c1, Ref<Cell> c2, int n) const {
|
||||
|
@ -259,6 +283,7 @@ class DictionaryFixed : public DictionaryBase {
|
|||
return check_leaf(cs_ref.write(), key, key_len);
|
||||
}
|
||||
bool check_fork_raw(Ref<CellSlice> cs_ref, int n) const;
|
||||
friend class DictIterator;
|
||||
|
||||
private:
|
||||
std::pair<Ref<CellSlice>, Ref<Cell>> dict_lookup_delete(Ref<Cell> dict, td::ConstBitPtr key, int n) const;
|
||||
|
@ -277,6 +302,148 @@ class DictionaryFixed : public DictionaryBase {
|
|||
const foreach_func_t& foreach_func, bool invert_first = false) const;
|
||||
};
|
||||
|
||||
class DictIterator {
|
||||
const DictionaryFixed* dict_{nullptr};
|
||||
Ref<Cell> root_;
|
||||
int label_mode_{dict::LabelParser::chk_size};
|
||||
int key_bits_;
|
||||
int flags_;
|
||||
int order_;
|
||||
unsigned char key_buffer[DictionaryBase::max_key_bytes];
|
||||
bool prevalidate(int mode = -1);
|
||||
enum { f_valid = 4 };
|
||||
|
||||
protected:
|
||||
struct Fork {
|
||||
Ref<Cell> next, alt;
|
||||
int pos;
|
||||
bool v;
|
||||
Fork() : pos(-1) {
|
||||
}
|
||||
Fork(Ref<Cell> _next, Ref<Cell> _alt, int _pos, bool _v)
|
||||
: next(std::move(_next)), alt(std::move(_alt)), pos(_pos), v(_v) {
|
||||
}
|
||||
void rotate(td::BitPtr key) {
|
||||
std::swap(next, alt);
|
||||
key[pos] = (v ^= true);
|
||||
}
|
||||
};
|
||||
std::vector<Fork> path_;
|
||||
Ref<CellSlice> leaf_;
|
||||
|
||||
td::BitPtr key(int offs = 0) {
|
||||
return td::BitPtr{key_buffer, offs};
|
||||
}
|
||||
td::ConstBitPtr key(int offs = 0) const {
|
||||
return td::ConstBitPtr{key_buffer, offs};
|
||||
}
|
||||
td::ConstBitPtr ckey(int offs = 0) const {
|
||||
return td::ConstBitPtr{key_buffer, offs};
|
||||
}
|
||||
|
||||
public:
|
||||
DictIterator() : key_bits_(0), flags_(0), order_(0) {
|
||||
}
|
||||
// mode: 0 = bidir, +4 = fwd only, +8 = back only; +1 = reverse directions, +2 = signed int keys
|
||||
enum { it_reverse = 1, it_signed = 2 };
|
||||
DictIterator(Ref<Cell> root_cell, int key_bits, int mode = 0)
|
||||
: root_(std::move(root_cell)), key_bits_(key_bits), flags_(mode >> 2) {
|
||||
prevalidate(mode & 3);
|
||||
}
|
||||
DictIterator(const DictionaryFixed& dict, int mode = 0)
|
||||
: DictIterator(dict.get_root_cell(), dict.get_key_bits(), mode) {
|
||||
dict_ = &dict;
|
||||
label_mode_ = dict.label_mode();
|
||||
}
|
||||
bool is_valid() const {
|
||||
return flags_ & f_valid;
|
||||
}
|
||||
bool eof() const {
|
||||
return leaf_.is_null();
|
||||
}
|
||||
bool reset() {
|
||||
dict_ = nullptr;
|
||||
root_.clear();
|
||||
path_.clear();
|
||||
leaf_.clear();
|
||||
return true;
|
||||
}
|
||||
td::ConstBitPtr cur_pos() const {
|
||||
return eof() ? td::ConstBitPtr{nullptr} : key();
|
||||
}
|
||||
Ref<Cell> get_root_cell() const {
|
||||
return root_;
|
||||
}
|
||||
int get_key_bits() const {
|
||||
return key_bits_;
|
||||
}
|
||||
bool is_bound() const {
|
||||
return dict_;
|
||||
}
|
||||
bool is_bound_to(const DictionaryFixed& dict) const {
|
||||
return root_.not_null() == dict.get_root_cell().not_null() &&
|
||||
(root_.not_null() ? root_.get() == dict.get_root_cell().get() : key_bits_ == dict.get_key_bits());
|
||||
}
|
||||
bool bind(const DictionaryFixed& dict, int do_rewind = 0);
|
||||
bool rebind_to(const DictionaryFixed& dict, int do_rewind = 0);
|
||||
bool rewind(bool to_end = false);
|
||||
bool next(bool backw = false);
|
||||
bool prev() {
|
||||
return next(true);
|
||||
}
|
||||
bool lookup(td::ConstBitPtr pos, int pos_bits, bool strict_after = false, bool backw = false);
|
||||
template <typename T>
|
||||
bool lookup(const T& key, bool strict_after = false, bool backw = false) {
|
||||
return lookup(key.bits(), key.size(), strict_after, backw);
|
||||
}
|
||||
Ref<CellSlice> cur_value() const {
|
||||
return dict_ ? dict_->extract_leaf_value(leaf_) : Ref<CellSlice>{};
|
||||
}
|
||||
Ref<CellSlice> cur_value_raw() const {
|
||||
return leaf_;
|
||||
}
|
||||
std::pair<td::ConstBitPtr, Ref<CellSlice>> operator*() const {
|
||||
return std::make_pair(cur_pos(), cur_value());
|
||||
}
|
||||
bool bound_to_same(const DictIterator& other) const {
|
||||
return dict_ && dict_ == other.dict_;
|
||||
}
|
||||
bool operator==(const DictIterator& other) const {
|
||||
return bound_to_same(other) && eof() == other.eof() && (eof() || key().equals(other.key(), key_bits_));
|
||||
}
|
||||
int compare_keys(td::ConstBitPtr a, td::ConstBitPtr b) const;
|
||||
bool operator<(const DictIterator& other) const {
|
||||
return bound_to_same(other) && !eof() && (other.eof() || compare_keys(key(), other.key()) < 0);
|
||||
}
|
||||
bool operator!=(const DictIterator& other) const {
|
||||
return !(operator==(other));
|
||||
}
|
||||
bool operator>(const DictIterator& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
DictIterator& operator++() {
|
||||
next();
|
||||
return *this;
|
||||
}
|
||||
DictIterator& operator--() {
|
||||
next(true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool dive(int mode);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
DictIterator begin(std::pair<T, int> dictm) {
|
||||
return dictm.first.make_iterator(dictm.second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DictIterator end(std::pair<T, int> dictm) {
|
||||
return dictm.first.null_iterator();
|
||||
}
|
||||
|
||||
class Dictionary final : public DictionaryFixed {
|
||||
public:
|
||||
typedef std::function<bool(CellBuilder&, Ref<CellSlice>)> simple_map_func_t;
|
||||
|
@ -356,6 +523,9 @@ class Dictionary final : public DictionaryFixed {
|
|||
Ref<CellSlice> lookup_set_builder(const T& key, Ref<vm::CellBuilder> val_ref, SetMode mode = SetMode::Set) {
|
||||
return lookup_set_builder(key.bits(), key.size(), std::move(val_ref), mode);
|
||||
}
|
||||
auto range(bool rev = false, bool sgnd = false) {
|
||||
return dict_range(*this, rev, sgnd);
|
||||
}
|
||||
|
||||
private:
|
||||
bool check_fork(CellSlice& cs, Ref<Cell> c1, Ref<Cell> c2, int n) const override {
|
||||
|
@ -454,6 +624,9 @@ class AugmentedDictionary final : public DictionaryFixed {
|
|||
Ref<Cell> lookup_delete_ref(const T& key) {
|
||||
return lookup_delete_ref(key.bits(), key.size());
|
||||
}
|
||||
auto range(bool rev = false, bool sgnd = false) {
|
||||
return dict_range(*this, rev, sgnd);
|
||||
}
|
||||
|
||||
Ref<CellSlice> extract_value(Ref<CellSlice> value_extra) const;
|
||||
Ref<Cell> extract_value_ref(Ref<CellSlice> value_extra) const;
|
||||
|
@ -463,6 +636,7 @@ class AugmentedDictionary final : public DictionaryFixed {
|
|||
private:
|
||||
bool compute_root() const;
|
||||
Ref<CellSlice> get_node_extra(Ref<Cell> cell_ref, int n) const;
|
||||
Ref<CellSlice> extract_leaf_value(Ref<CellSlice> leaf) const override;
|
||||
bool check_leaf(CellSlice& cs, td::ConstBitPtr key, int key_len) const override;
|
||||
bool check_fork(CellSlice& cs, Ref<Cell> c1, Ref<Cell> c2, int n) const override;
|
||||
Ref<Cell> finish_create_leaf(CellBuilder& cb, const CellSlice& value) const override;
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
namespace td {
|
||||
|
||||
void TerminalLogInterface::append(CSlice slice, int log_level) {
|
||||
auto instance_ = TerminalIOImpl::instance();
|
||||
if (!instance_) {
|
||||
auto instance = TerminalIOImpl::instance();
|
||||
if (!instance) {
|
||||
default_log_interface->append(slice, log_level);
|
||||
} else {
|
||||
instance_->deactivate_readline();
|
||||
instance->deactivate_readline();
|
||||
std::string color;
|
||||
if (log_level == 0 || log_level == 1) {
|
||||
color = TC_RED;
|
||||
|
@ -42,8 +42,8 @@ void TerminalLogInterface::append(CSlice slice, int log_level) {
|
|||
} else {
|
||||
color = TC_GREEN;
|
||||
}
|
||||
std::cerr << color << slice.c_str() << TC_EMPTY;
|
||||
instance_->reactivate_readline();
|
||||
td::TsCerr() << color << slice << TC_EMPTY;
|
||||
instance->reactivate_readline();
|
||||
if (log_level == VERBOSITY_NAME(FATAL)) {
|
||||
process_fatal_error(slice);
|
||||
}
|
||||
|
@ -216,17 +216,17 @@ void TerminalIOImpl::s_line(char *line) {
|
|||
LOG(FATAL) << "Closed";
|
||||
return;
|
||||
}
|
||||
CHECK(instance_);
|
||||
CHECK(instance);
|
||||
if (*line) {
|
||||
add_history(line);
|
||||
}
|
||||
instance_->line_cb(line);
|
||||
instance()->line_cb(line);
|
||||
rl_free(line);
|
||||
#endif
|
||||
}
|
||||
|
||||
int TerminalIOImpl::s_stdin_getc(FILE *) {
|
||||
return instance_->stdin_getc();
|
||||
return instance()->stdin_getc();
|
||||
}
|
||||
|
||||
void TerminalIOImpl::set_log_interface() {
|
||||
|
@ -250,55 +250,60 @@ void TerminalIOImpl::line_cb(std::string cmd) {
|
|||
cmd_queue_.push(td::BufferSlice{std::move(cmd)});
|
||||
}
|
||||
|
||||
void TerminalIO::output(std::string line) {
|
||||
auto instance_ = TerminalIOImpl::instance();
|
||||
if (!instance_) {
|
||||
std::cout << line;
|
||||
} else {
|
||||
instance_->deactivate_readline();
|
||||
std::cout << line;
|
||||
instance_->reactivate_readline();
|
||||
void TerminalIO::output_stdout(td::Slice slice) {
|
||||
auto &fd = td::Stdout();
|
||||
if (fd.empty()) {
|
||||
return;
|
||||
}
|
||||
double end_time = 0;
|
||||
while (!slice.empty()) {
|
||||
auto res = fd.write(slice);
|
||||
if (res.is_error()) {
|
||||
if (res.error().code() == EPIPE) {
|
||||
break;
|
||||
}
|
||||
// Resource temporary unavailable
|
||||
if (end_time == 0) {
|
||||
end_time = Time::now() + 0.01;
|
||||
} else if (Time::now() > end_time) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
slice.remove_prefix(res.ok());
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalIO::output(std::string line) {
|
||||
output(td::Slice(line));
|
||||
}
|
||||
|
||||
void TerminalIO::output(td::Slice line) {
|
||||
auto instance_ = TerminalIOImpl::instance();
|
||||
if (!instance_) {
|
||||
std::cout.write(line.begin(), line.size());
|
||||
auto instance = TerminalIOImpl::instance();
|
||||
if (!instance) {
|
||||
output_stdout(line);
|
||||
} else {
|
||||
instance_->deactivate_readline();
|
||||
std::cout.write(line.begin(), line.size());
|
||||
instance_->reactivate_readline();
|
||||
instance->deactivate_readline();
|
||||
output_stdout(line);
|
||||
instance->reactivate_readline();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalIO::output_stderr(std::string line) {
|
||||
auto instance_ = TerminalIOImpl::instance();
|
||||
if (!instance_) {
|
||||
std::cout << line;
|
||||
} else {
|
||||
instance_->deactivate_readline();
|
||||
if (instance_->readline_used()) {
|
||||
std::cout << line;
|
||||
} else {
|
||||
std::cerr << line;
|
||||
}
|
||||
instance_->reactivate_readline();
|
||||
}
|
||||
output_stderr(td::Slice(line));
|
||||
}
|
||||
|
||||
void TerminalIO::output_stderr(td::Slice line) {
|
||||
auto instance_ = TerminalIOImpl::instance();
|
||||
if (!instance_) {
|
||||
std::cerr.write(line.begin(), line.size());
|
||||
auto instance = TerminalIOImpl::instance();
|
||||
if (!instance) {
|
||||
td::TsCerr() << line;
|
||||
} else {
|
||||
instance_->deactivate_readline();
|
||||
if (instance_->readline_used()) {
|
||||
std::cout.write(line.begin(), line.size());
|
||||
instance->deactivate_readline();
|
||||
if (instance->readline_used()) {
|
||||
output_stdout(line);
|
||||
} else {
|
||||
std::cerr.write(line.begin(), line.size());
|
||||
td::TsCerr() << line;
|
||||
}
|
||||
instance_->reactivate_readline();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ class TerminalIO : public actor::Actor {
|
|||
static void output(td::Slice slice);
|
||||
static void output_stderr(std::string line);
|
||||
static void output_stderr(td::Slice slice);
|
||||
static void output_stdout(td::Slice line);
|
||||
static TerminalIOOutputter out() {
|
||||
return TerminalIOOutputter{false};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ Test_Fift_bug_newlize_default e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca4
|
|||
Test_Fift_bug_ufits_default 51bf5a9f1ed7633a193f6fdd17a7a3af8e032dfe72a9669c85e8639aa8a7c195
|
||||
Test_Fift_contfrac_default 09ebce5c91bcb70696c6fb6981d82dc3b9e3444dab608a7a1b044c0ddd778a96
|
||||
Test_Fift_test_default 4e44b3382963ec89f7b5c8f2ebd85da3bc8aebad5b49f5b11b14075061477b4d
|
||||
Test_Fift_test_dict_default 85b2ed797bab084f391179ff9c8c83f0ed9b5f4c53180c72e37379fdf95356b8
|
||||
Test_Fift_test_dict_default a9c8cbcfdece5573185022cea07f59f1bc404e5d879e5157a5745757f8ee0525
|
||||
Test_Fift_test_fixed_default 278a19d56b773102caf5c1fe2997ea6c8d0d9e720eff8503feede6398a197eec
|
||||
Test_Fift_test_sort2_default 9b57d47e6a10e7d1bbb565db35400debf2f963031f434742a702ec76555a5d3a
|
||||
Test_Fift_test_sort_default 9b57d47e6a10e7d1bbb565db35400debf2f963031f434742a702ec76555a5d3a
|
||||
|
|
|
@ -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 "tl_writer_java.h"
|
||||
|
||||
|
|
|
@ -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 "tl_writer_jni_cpp.h"
|
||||
|
||||
|
|
|
@ -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 "tl_writer_jni_h.h"
|
||||
|
||||
|
|
|
@ -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 "tl_writer_td.h"
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ void LiteQuery::perform_getMasterchainInfo(int mode) {
|
|||
}
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||
[ Self = actor_id(this), mode ](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
|
||||
[Self = actor_id(this), mode](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -242,7 +242,7 @@ void LiteQuery::perform_getBlock(BlockIdExt blkid) {
|
|||
return;
|
||||
}
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::BlockData>> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -268,7 +268,7 @@ void LiteQuery::perform_getBlockHeader(BlockIdExt blkid, int mode) {
|
|||
return;
|
||||
}
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<ton::validator::BlockData>> res) {
|
||||
[Self = actor_id(this), blkid, mode](td::Result<Ref<ton::validator::BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -383,7 +383,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
|
|||
}
|
||||
if (blkid.id.seqno) {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::ShardState>> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -393,7 +393,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
|
|||
});
|
||||
} else {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -452,7 +452,7 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
|
|||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
||||
|
@ -476,15 +476,25 @@ bool LiteQuery::request_mc_proof(BlockIdExt blkid, int mode) {
|
|||
base_blk_id_ = blkid;
|
||||
}
|
||||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_proof_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<Proof>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_proof, blkid, mode, res.move_as_ok());
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::get_key_block_proof, blkid,
|
||||
[Self = actor_id(this), manager = manager_, blkid, mode](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_ok()) {
|
||||
auto proof = create_proof(blkid, R.move_as_ok());
|
||||
proof.ensure();
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_proof, blkid, mode, proof.move_as_ok());
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::get_block_proof_from_db_short, blkid,
|
||||
[Self, blkid, mode](td::Result<Ref<Proof>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_proof, blkid, mode, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -500,7 +510,7 @@ bool LiteQuery::request_mc_block_state(BlockIdExt blkid) {
|
|||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
||||
|
@ -531,7 +541,7 @@ bool LiteQuery::request_block_state(BlockIdExt blkid) {
|
|||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
||||
|
@ -553,7 +563,7 @@ bool LiteQuery::request_block_data(BlockIdExt blkid) {
|
|||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
||||
|
@ -573,16 +583,40 @@ bool LiteQuery::request_proof_link(BlockIdExt blkid) {
|
|||
}
|
||||
blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ProofLink>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_proof_link, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
if (blkid.is_masterchain()) {
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::get_key_block_proof_link, blkid,
|
||||
[Self = actor_id(this), manager = manager_, blkid](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_ok()) {
|
||||
auto proof = create_proof(blkid, R.move_as_ok());
|
||||
proof.ensure();
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_proof_link, blkid, proof.move_as_ok());
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure_later(
|
||||
manager, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
|
||||
[Self, blkid](td::Result<Ref<ProofLink>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(
|
||||
Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_proof_link, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
|
||||
[Self = actor_id(this), blkid](td::Result<Ref<ProofLink>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_proof_link, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -600,7 +634,7 @@ bool LiteQuery::request_zero_state(BlockIdExt blkid) {
|
|||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_zero_state, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
|
||||
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : "));
|
||||
|
@ -645,7 +679,7 @@ void LiteQuery::perform_getAccountState(BlockIdExt blkid, WorkchainId workchain,
|
|||
LOG(INFO) << "sending a get_top_masterchain_state_block query to manager";
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res)->void {
|
||||
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) -> void {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -1237,14 +1271,14 @@ void LiteQuery::continue_getTransactions(unsigned remaining, bool exact) {
|
|||
<< " " << trans_lt_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_by_lt_from_db, ton::extract_addr_prefix(acc_workchain_, acc_addr_),
|
||||
trans_lt_, [ Self = actor_id(this), remaining, manager = manager_ ](td::Result<ConstBlockHandle> res) {
|
||||
trans_lt_, [Self = actor_id(this), remaining, manager = manager_](td::Result<ConstBlockHandle> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{});
|
||||
} else {
|
||||
auto handle = res.move_as_ok();
|
||||
LOG(DEBUG) << "requesting data for block " << handle->id().to_str();
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db, handle,
|
||||
[ Self, blkid = handle->id(), remaining ](td::Result<Ref<BlockData>> res) {
|
||||
[Self, blkid = handle->id(), remaining](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions,
|
||||
res.move_as_error(), blkid);
|
||||
|
@ -1311,7 +1345,7 @@ void LiteQuery::perform_getShardInfo(BlockIdExt blkid, ShardIdFull shard, bool e
|
|||
void LiteQuery::perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list) {
|
||||
LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", <list of " << param_list.size()
|
||||
<< " parameters>) liteserver query";
|
||||
set_continuation([ this, mode, param_list = std::move(param_list) ]() mutable {
|
||||
set_continuation([this, mode, param_list = std::move(param_list)]() mutable {
|
||||
continue_getConfigParams(mode, std::move(param_list));
|
||||
});
|
||||
request_mc_block_data_state(blkid);
|
||||
|
@ -1464,14 +1498,14 @@ void LiteQuery::perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, Uni
|
|||
LOG(INFO) << "performing a lookupBlock(" << blkid.to_str() << ", " << mode << ", " << lt << ", " << utime
|
||||
<< ") query";
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[ Self = actor_id(this), manager = manager_, mode = (mode >> 4) ](td::Result<ConstBlockHandle> res) {
|
||||
[Self = actor_id(this), manager = manager_, mode = (mode >> 4)](td::Result<ConstBlockHandle> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
auto handle = res.move_as_ok();
|
||||
LOG(DEBUG) << "requesting data for block " << handle->id().to_str();
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_block_data_from_db, handle,
|
||||
[ Self, blkid = handle->id(), mode ](td::Result<Ref<BlockData>> res) {
|
||||
[Self, blkid = handle->id(), mode](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -1619,7 +1653,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
if (mode & 0x1000) {
|
||||
BlockIdExt bblk = (from.seqno() > to.seqno()) ? from : to;
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, bblk,
|
||||
[ Self = actor_id(this), from, to, bblk, mode ](td::Result<Ref<ShardState>> res) {
|
||||
[Self = actor_id(this), from, to, bblk, mode](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -1631,7 +1665,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
} else {
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||
[ Self = actor_id(this), from, to, mode ](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||
[Self = actor_id(this), from, to, mode](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -1644,7 +1678,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
} else if (mode & 2) {
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||
[ Self = actor_id(this), from, mode ](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||
[Self = actor_id(this), from, mode](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
@ -1655,7 +1689,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
});
|
||||
} else {
|
||||
td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_shard_client_state, false,
|
||||
[ Self = actor_id(this), from, mode ](td::Result<BlockIdExt> res) {
|
||||
[Self = actor_id(this), from, mode](td::Result<BlockIdExt> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue