mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated fift + bugfixes
This commit is contained in:
parent
090e0c16eb
commit
ceaed40ac4
28 changed files with 530 additions and 108 deletions
|
@ -683,3 +683,47 @@ top_block_descr#d5 proof_for:BlockIdExt signatures:(Maybe ^BlockSignatures)
|
|||
// COLLATED DATA
|
||||
//
|
||||
top_block_descr_set#4ac789f3 collection:(HashmapE 96 ^TopBlockDescr) = TopBlockDescrSet;
|
||||
|
||||
//
|
||||
// TVM REFLECTION
|
||||
//
|
||||
vm_stk_null#00 = VmStackValue;
|
||||
vm_stk_tinyint#01 value:int64 = VmStackValue;
|
||||
vm_stk_int#0201_ value:int257 = VmStackValue;
|
||||
vm_stk_nan#02ff = VmStackValue;
|
||||
vm_stk_cell#03 cell:^Cell = VmStackValue;
|
||||
_ cell:^Cell st_bits:(## 10) end_bits:(## 10) { st_bits <= end_bits }
|
||||
st_ref:(#<= 4) end_ref:(#<= 4) { st_ref <= end_ref } = VmCellSlice;
|
||||
vm_stk_slice#04 _:VmCellSlice = VmStackValue;
|
||||
vm_stk_builder#05 cell:^Cell = VmStackValue;
|
||||
vm_stk_cont#06 cont:VmCont = VmStackValue;
|
||||
vm_tupref_nil$_ = VmTupleRef 0;
|
||||
vm_tupref_single$_ entry:^VmStackValue = VmTupleRef 1;
|
||||
vm_tupref_any$_ {n:#} ref:^(VmTuple (n + 2)) = VmTupleRef (n + 2);
|
||||
vm_tuple_nil$_ = VmTuple 0;
|
||||
vm_tuple_tcons$_ {n:#} head:(VmTupleRef n) tail:^VmStackValue = VmTuple (n + 1);
|
||||
vm_stk_tuple#07 len:(## 16) data:(VmTuple len) = VmStackValue;
|
||||
|
||||
vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack;
|
||||
vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1);
|
||||
vm_stk_nil#_ = VmStackList 0;
|
||||
|
||||
_ cregs:(HashmapE 4 VmStackValue) = VmSaveList;
|
||||
gas_limits#_ remaining:int64 _:^[ max_limit:int64 cur_limit:int64 credit:int64 ]
|
||||
= VmGasLimits;
|
||||
_ libraries:(HashmapE 256 ^Cell) = VmLibraries;
|
||||
|
||||
vm_ctl_data$_ nargs:int14 stack:(Maybe VmStack) save:VmSaveList
|
||||
cp:int16 = VmControlData;
|
||||
vmc_std$00 cdata:VmControlData code:VmCellSlice = VmCont;
|
||||
vmc_envelope$01 cdata:VmControlData next:^VmCont = VmCont;
|
||||
vmc_quit$1000 exit_code:int32 = VmCont;
|
||||
vmc_quit_exc$1001 = VmCont;
|
||||
vmc_repeat$10100 count:uint63 body:^VmCont after:^VmCont = VmCont;
|
||||
vmc_until$110000 body:^VmCont after:^VmCont = VmCont;
|
||||
vmc_again$110001 body:^VmCont = VmCont;
|
||||
vmc_while_cond$110010 cond:^VmCont body:^VmCont
|
||||
after:^VmCont = VmCont;
|
||||
vmc_while_body$110011 cond:^VmCont body:^VmCont
|
||||
after:^VmCont = VmCont;
|
||||
vmc_pushint$1111 value:int32 next:^VmCont = VmCont;
|
||||
|
|
|
@ -71,6 +71,7 @@ IntCtx::Savepoint::Savepoint(IntCtx& _ctx, std::string new_filename, std::string
|
|||
std::istream* new_input_stream)
|
||||
: ctx(_ctx)
|
||||
, old_line_no(_ctx.line_no)
|
||||
, old_need_line(_ctx.need_line)
|
||||
, old_filename(_ctx.filename)
|
||||
, old_current_dir(_ctx.currentd_dir)
|
||||
, old_input_stream(_ctx.input_stream)
|
||||
|
@ -87,6 +88,7 @@ IntCtx::Savepoint::Savepoint(IntCtx& _ctx, std::string new_filename, std::string
|
|||
|
||||
IntCtx::Savepoint::~Savepoint() {
|
||||
ctx.line_no = old_line_no;
|
||||
ctx.need_line = old_need_line;
|
||||
ctx.filename = old_filename;
|
||||
ctx.currentd_dir = old_current_dir;
|
||||
ctx.input_stream = old_input_stream;
|
||||
|
@ -99,6 +101,7 @@ bool IntCtx::load_next_line() {
|
|||
if (!std::getline(*input_stream, str)) {
|
||||
return false;
|
||||
}
|
||||
need_line = false;
|
||||
if (!str.empty() && str.back() == '\r') {
|
||||
str.pop_back();
|
||||
}
|
||||
|
@ -111,6 +114,7 @@ bool IntCtx::is_sb() const {
|
|||
}
|
||||
|
||||
td::Slice IntCtx::scan_word_to(char delim, bool err_endl) {
|
||||
load_next_line_ifreq();
|
||||
auto ptr = input_ptr;
|
||||
while (*ptr && *ptr != delim) {
|
||||
ptr++;
|
||||
|
@ -121,6 +125,7 @@ td::Slice IntCtx::scan_word_to(char delim, bool err_endl) {
|
|||
} else if (err_endl && delim) {
|
||||
throw IntError{std::string{"end delimiter `"} + delim + "` not found"};
|
||||
} else {
|
||||
need_line = true;
|
||||
std::swap(ptr, input_ptr);
|
||||
return td::Slice{ptr, input_ptr};
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ struct IntCtx {
|
|||
int state{0};
|
||||
int include_depth{0};
|
||||
int line_no{0};
|
||||
bool need_line{true};
|
||||
std::string filename;
|
||||
std::string currentd_dir;
|
||||
std::istream* input_stream{nullptr};
|
||||
|
@ -116,6 +117,9 @@ struct IntCtx {
|
|||
}
|
||||
|
||||
bool load_next_line();
|
||||
bool load_next_line_ifreq() {
|
||||
return need_line && load_next_line();
|
||||
}
|
||||
|
||||
bool is_sb() const;
|
||||
|
||||
|
@ -126,6 +130,7 @@ struct IntCtx {
|
|||
class Savepoint {
|
||||
IntCtx& ctx;
|
||||
int old_line_no;
|
||||
bool old_need_line;
|
||||
std::string old_filename;
|
||||
std::string old_current_dir;
|
||||
std::istream* old_input_stream;
|
||||
|
|
|
@ -112,3 +112,7 @@ variable base
|
|||
{ bl word atom 1 'nop } ::_ `
|
||||
{ hole dup 1 { @ execute } does create } : recursive
|
||||
{ 0 { 1+ dup 1 ' $() does over (.) "$" swap $+ 0 (create) } rot times drop } : :$1..n
|
||||
{ 10 hold } : +cr
|
||||
{ 9 hold } : +tab
|
||||
{ "" swap { 0 word 2dup $cmp } { rot swap $+ +cr swap } while 2drop } : scan-until-word
|
||||
{ 0 word -trailing scan-until-word 1 'nop } ::_ $<<
|
||||
|
|
|
@ -33,12 +33,16 @@ recursive list-delete-range {
|
|||
} : list-find-opt
|
||||
// ( -- s i or 0 ) finds first option in cmdline args
|
||||
{ $* @ list-find-opt } : first-opt
|
||||
// ( s t -- ? ) checks whether short/long option s matches description t
|
||||
{ third $= } : short-option-matches
|
||||
' second : get-opt-flags
|
||||
' first : get-opt-exec
|
||||
// ( s t -- ? ) checks whether short/long option s matches description t
|
||||
{ third $= } : short-option-matches
|
||||
{ dup get-opt-flags 4 and 0= 3 + [] $=
|
||||
} : long-option-matches
|
||||
// ( t -- s -1 or 0 ) extracts help message from description
|
||||
{ dup get-opt-flags 4 and 0= 4 + over count over >
|
||||
{ [] true } { 2drop false } cond
|
||||
} : get-opt-help
|
||||
// ( s l -- t -1 or 0 ) finds short/long option s in list l
|
||||
{ swap 1 { swap short-option-matches } does assoc-gen
|
||||
} : lookup-short-option
|
||||
|
@ -47,37 +51,57 @@ recursive list-delete-range {
|
|||
// ( s -- s' null or s' s'' ) Splits long option --opt=arg at '='
|
||||
{ dup "=" $pos 1+ ?dup { tuck $| swap rot 1- $| drop swap } { null } cond
|
||||
} : split-longopt
|
||||
variable options-list
|
||||
// ( l -- i or 0 )
|
||||
// parses command line arguments according to option description list l
|
||||
// and returns index i of first incorrect option
|
||||
{ { first-opt dup 0= { true } {
|
||||
swap dup "--" $pfx? { // l i s
|
||||
{ options-list !
|
||||
{ first-opt dup 0= { true } {
|
||||
swap dup "--" $pfx? { // i s
|
||||
dup $len 2 = { drop dup 1 $*del.. 0 true } {
|
||||
split-longopt swap 3 pick
|
||||
lookup-long-option not { drop true } { // l i s' t f
|
||||
dup get-opt-exec swap get-opt-flags 3 and // l i s' e f'
|
||||
2 pick null? { dup 1 = } { dup 0= negate } cond // l i s' e f' f''
|
||||
split-longopt swap options-list @
|
||||
lookup-long-option not { drop true } { // i s' t f
|
||||
dup get-opt-exec swap get-opt-flags 3 and // i s' e f'
|
||||
2 pick null? { dup 1 = } { dup 0= negate } cond // i s' e f' f''
|
||||
dup 1 = { 2drop 2drop true } {
|
||||
{ drop nip over 1+ $() swap execute 2 $*del.. false } {
|
||||
' nip ifnot execute 1 $*del.. false
|
||||
} cond } cond } cond } cond } { // l i s
|
||||
} cond } cond } cond } cond } { // i s
|
||||
1 $| nip {
|
||||
dup $len 0= { drop 1 $*del.. false true } {
|
||||
1 $| swap 3 pick // l i s' s l
|
||||
lookup-short-option not { drop true true } { // l i s' t
|
||||
dup get-opt-exec swap get-opt-flags 3 and // l i s' e f'
|
||||
1 $| swap options-list @ // i s' s l
|
||||
lookup-short-option not { drop true true } { // i s' t
|
||||
dup get-opt-exec swap get-opt-flags 3 and // i s' e f'
|
||||
?dup 0= { execute false } {
|
||||
2 pick $len { drop execute "" false } {
|
||||
2 = { nip null swap execute "" false } { // l i e
|
||||
2 = { nip null swap execute "" false } { // i e
|
||||
nip over 1+ $() swap execute 2 $*del.. false true
|
||||
} cond } cond } cond } cond } cond } until
|
||||
} cond
|
||||
} cond } until nip
|
||||
} cond } until
|
||||
} : getopt
|
||||
// ( t -- ) Displays help message for one option
|
||||
{ dup get-opt-flags dup 4 and 2 pick third swap {
|
||||
."-" type ."/" over 3 [] type } {
|
||||
dup $len { dup "--" $pfx? { ."-" } ifnot type } {
|
||||
drop ."usage: " $0 type
|
||||
} cond } cond
|
||||
dup 3 and ?dup {
|
||||
2 = { ."[=<optarg>]" } { ."=<optarg>" } cond
|
||||
} if
|
||||
8 and { 9 emit } ifnot
|
||||
get-opt-help { type } { ."No help available" } cond cr
|
||||
} : show-opt-help
|
||||
// ( -- ) Displays options help message according to options-list
|
||||
{ options-list @ { dup null? not } {
|
||||
uncons swap show-opt-help
|
||||
} while drop
|
||||
} : show-options-help
|
||||
// ( l -- ) Parses options and throws an error on failure
|
||||
{ getopt ?dup { $() "cannot parse command line options near `" swap $+ +"`" abort } if
|
||||
{ getopt ?dup {
|
||||
$() "cannot parse command line options near `" swap $+ +"`"
|
||||
show-options-help abort } if
|
||||
} : run-getopt
|
||||
|
||||
anon constant opt-list-marker
|
||||
' opt-list-marker : begin-options
|
||||
{ opt-list-marker list-until-marker } : end-options
|
||||
|
@ -90,3 +114,7 @@ anon constant opt-list-marker
|
|||
{ 2 rot triple } dup : short-option-?arg : long-option-?arg
|
||||
{ 5 2swap 4 tuple } : short-long-option-arg
|
||||
{ 6 2swap 4 tuple } : short-long-option-?arg
|
||||
// ( o s -- s' ) Adds help message to option
|
||||
' , : option-help
|
||||
// ( s -- o ) Creates a generic help message
|
||||
{ 'nop 8 "" 3 roll 4 tuple } : generic-help
|
||||
|
|
|
@ -12,6 +12,8 @@ library TonUtil // TON Blockchain Fift Library
|
|||
|
||||
{ (number) 1- abort"integer expected" } : parse-int
|
||||
|
||||
{ over null? ' swap if drop } : replace-if-null
|
||||
|
||||
// Private key load/generate
|
||||
// ( fname -- pubkey privkey )
|
||||
{ dup ."Loading private key from file " type cr
|
||||
|
|
|
@ -137,16 +137,21 @@ _ perform_action(cfg_dict, public_key, action, cs) {
|
|||
}
|
||||
}
|
||||
|
||||
slice get_validator_descr(int idx) inline_ref {
|
||||
(slice, int) get_validator_descr(int idx) inline_ref {
|
||||
var vset = config_param(34);
|
||||
if (vset.null?()) {
|
||||
return null();
|
||||
return (null(), 0);
|
||||
}
|
||||
var cs = begin_parse(vset);
|
||||
cs~skip_bits(8 + 32 + 32 + 16 + 16);
|
||||
;; validators_ext#12 utime_since:uint32 utime_until:uint32
|
||||
;; total:(## 16) main:(## 16) { main <= total } { main >= 1 }
|
||||
;; total_weight:uint64
|
||||
throw_unless(40, cs~load_uint(8) == 0x12);
|
||||
cs~skip_bits(32 + 32 + 16 + 16);
|
||||
int total_weight = cs~load_uint(64);
|
||||
var dict = begin_cell().store_slice(cs).end_cell();
|
||||
var (value, _) = dict.udict_get?(16, idx);
|
||||
return value;
|
||||
return (value, total_weight);
|
||||
}
|
||||
|
||||
(int, int) unpack_validator_descr(slice cs) inline {
|
||||
|
@ -158,33 +163,51 @@ slice get_validator_descr(int idx) inline_ref {
|
|||
return (cs~load_uint(256), cs~load_uint(64));
|
||||
}
|
||||
|
||||
slice create_new_entry(cs) inline {
|
||||
return begin_cell().store_int(false, 1).store_uint(0, 64).store_uint(0, 256).store_slice(cs).end_cell().begin_parse();
|
||||
(cell, int, int, slice) new_proposal(cs) inline {
|
||||
return (null(), 0, 0, cs);
|
||||
}
|
||||
|
||||
(cell, int, int, slice) unpack_suggestion(slice cs) inline {
|
||||
(cell, int, int, slice) unpack_proposal(slice cs) inline {
|
||||
return (cs~load_dict(), cs~load_uint(64), cs~load_uint(256), cs);
|
||||
}
|
||||
|
||||
builder pack_suggestion(cell voters, int sum_weight, int vset_id, slice body) inline {
|
||||
builder pack_proposal(cell voters, int sum_weight, int vset_id, slice body) inline {
|
||||
return begin_cell().store_dict(voters).store_uint(sum_weight, 64).store_uint(vset_id, 256).store_slice(body);
|
||||
}
|
||||
|
||||
cell register_vote(vote_dict, action, cs, idx, weight) {
|
||||
(cell, slice) register_vote(vote_dict, action, cs, idx, weight, total_weight, cur_vset_id) {
|
||||
int hash = 0;
|
||||
int found? = 0;
|
||||
var entry = null();
|
||||
if (action & 1) {
|
||||
hash = slice_hash(cs);
|
||||
(entry, var found?) = vote_dict.udict_get?(256, hash);
|
||||
ifnot (found?) {
|
||||
entry = create_new_entry(cs);
|
||||
}
|
||||
(entry, found?) = vote_dict.udict_get?(256, hash);
|
||||
} else {
|
||||
hash = cs.preload_uint(256);
|
||||
(entry, var found?) = vote_dict.udict_get?(256, hash);
|
||||
(entry, found?) = vote_dict.udict_get?(256, hash);
|
||||
throw_unless(42, found?);
|
||||
}
|
||||
return vote_dict;
|
||||
var (voters, sum_weight, vset_id, body) = found? ? unpack_proposal(entry) : (null(), 0, cur_vset_id, cs);
|
||||
if (vset_id != cur_vset_id) {
|
||||
voters = null();
|
||||
sum_weight = 0;
|
||||
vset_id = cur_vset_id;
|
||||
}
|
||||
var (_, found?) = voters.udict_get?(16, idx);
|
||||
ifnot (found?) {
|
||||
voters~udict_set_builder(16, idx, begin_cell().store_uint(32, now()));
|
||||
sum_weight += weight;
|
||||
if (sum_weight * 3 > total_weight * 2) {
|
||||
;; proposal accepted
|
||||
vote_dict~udict_delete?(256, hash);
|
||||
return (vote_dict, body);
|
||||
} else {
|
||||
vote_dict~udict_set_builder(256, hash, pack_proposal(voters, sum_weight, cur_vset_id, body));
|
||||
return (vote_dict, null());
|
||||
}
|
||||
} else {
|
||||
return (vote_dict, null());
|
||||
}
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
|
@ -198,15 +221,19 @@ cell register_vote(vote_dict, action, cs, idx, weight) {
|
|||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
ifnot ((action - 0x566f7465) & -2) {
|
||||
var idx = cs~load_uint(16);
|
||||
var vdescr = get_validator_descr(idx);
|
||||
var (vdescr, total_weight) = get_validator_descr(idx);
|
||||
var (val_pubkey, weight) = unpack_validator_descr(vdescr);
|
||||
throw_unless(34, check_signature(slice_hash(in_msg), signature, val_pubkey));
|
||||
accept_message();
|
||||
stored_seqno += 1;
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
commit();
|
||||
vote_dict = register_vote(vote_dict, action, cs, idx, weight);
|
||||
(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?()) {
|
||||
(cfg_dict, public_key) = perform_action(cfg_dict, public_key, accepted~load_uint(32), accepted);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
}
|
||||
return ();
|
||||
}
|
||||
throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
|
|
|
@ -1,20 +1,41 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ show-options-help 1 halt } : usage
|
||||
|
||||
true =: allow-bounce
|
||||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 =: timeout // external message expires in 60 seconds
|
||||
|
||||
begin-options
|
||||
" <filename-base> <subwallet-id> <order-file> [-n|-b] [-t<timeout>] [<savefile>]" +cr +tab
|
||||
+"Creates a request with up to 254 orders loaded from <order-file> to high-load (sub)wallet created by new-highload-v2-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" +cr
|
||||
+"<order-file> is a text file with lines `SEND <dest-addr> <amount>`"
|
||||
generic-help
|
||||
"n" "--no-bounce" { false =: allow-bounce } short-long-option
|
||||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
|
||||
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
|
||||
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
|
||||
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
|
||||
option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <subwallet-id> <order-file> [<savefile>]" cr
|
||||
."Creates a request with up to 254 orders loaded from <order-file> to high-load v2 (sub)wallet created by new-highload-v2-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr
|
||||
."<order-file> is a text file with lines `SEND <dest-addr> <amount>`" cr 1 halt
|
||||
} : usage
|
||||
$# dup 3 < swap 4 > or ' usage if
|
||||
4 :$1..n
|
||||
|
||||
$1 =: file-base
|
||||
$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id
|
||||
{ subwallet-id (.) $+ } : +subwallet
|
||||
$3 =: order-file
|
||||
def? $4 { @' $4 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
$4 "wallet-query" replace-if-null =: savefile
|
||||
|
||||
file-base +subwallet +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
|
@ -41,7 +62,7 @@ variable order# order# 0!
|
|||
-rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr
|
||||
} : .transfer
|
||||
// addr$ ng -- c
|
||||
{ swap parse-smc-addr // ng wc addr bnc
|
||||
{ swap parse-smc-addr force-bounce or allow-bounce and // ng wc addr bnc
|
||||
2over 2over .transfer
|
||||
<b 0 32 u, b> create-int-msg
|
||||
} : create-simple-transfer
|
||||
|
|
|
@ -1,21 +1,42 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ show-options-help 1 halt } : usage
|
||||
|
||||
true =: allow-bounce
|
||||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 =: timeout // external message expires in 60 seconds
|
||||
|
||||
begin-options
|
||||
" <filename-base> <subwallet-id> <seqno> <order-file> [-n|-b] [-t<timeout>] [<savefile>]" +cr +tab
|
||||
+"Creates a request with up to 254 orders loaded from <order-file> to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" +cr
|
||||
+"<order-file> is a text file with lines `SEND <dest-addr> <amount>`"
|
||||
generic-help
|
||||
"n" "--no-bounce" { false =: allow-bounce } short-long-option
|
||||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
|
||||
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
|
||||
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
|
||||
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
|
||||
option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <subwallet-id> <seqno> <order-file> [<savefile>]" cr
|
||||
."Creates a request with up to 254 orders loaded from <order-file> to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr
|
||||
."<order-file> is a text file with lines `SEND <dest-addr> <amount>`" cr 1 halt
|
||||
} : usage
|
||||
$# dup 4 < swap 5 > or ' usage if
|
||||
5 :$1..n
|
||||
|
||||
$1 =: file-base
|
||||
$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id
|
||||
{ subwallet-id (.) $+ } : +subwallet
|
||||
$3 parse-int =: seqno
|
||||
$4 =: order-file
|
||||
def? $5 { @' $5 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
$5 "wallet-query" replace-if-null =: savefile
|
||||
|
||||
file-base +subwallet +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
|
@ -42,7 +63,7 @@ variable order# order# 0!
|
|||
-rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr
|
||||
} : .transfer
|
||||
// addr$ ng -- c
|
||||
{ swap parse-smc-addr // ng wc addr bnc
|
||||
{ swap parse-smc-addr force-bounce or allow-bounce and // ng wc addr bnc
|
||||
2over 2over .transfer
|
||||
<b 0 32 u, b> create-int-msg
|
||||
} : create-simple-transfer
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <workchain-id> <wallet-id> [<filename-base>]" cr
|
||||
{ ."usage: " $0 type ." <workchain-id> <wallet-id> [<filename-base>]" cr
|
||||
."Creates a new advanced wallet with unique 32-bit identifier <wallet-id> in specified workchain, with private key saved to or loaded from <filename-base>.pk" cr
|
||||
."('new-wallet.pk' by default)" cr 1 halt
|
||||
} : usage
|
||||
$# 2- -2 and ' usage if
|
||||
|
||||
3 :$1..n
|
||||
$1 parse-workchain-id =: wc // set workchain id from command line argument
|
||||
$2 parse-int =: subwallet-id
|
||||
def? $3 { @' $3 } { "new-wallet" } cond constant file-base
|
||||
$3 "new-wallet" replace-if-null =: file-base
|
||||
|
||||
."Creating new advanced v3 wallet in workchain " wc . cr
|
||||
."with unique wallet id " subwallet-id . cr
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
} : usage
|
||||
$# 1 > ' usage if
|
||||
1 :$1..n
|
||||
$1 dup null? { drop "new-wallet" } if =: file-base
|
||||
$1 "new-wallet" replace-if-null =: file-base
|
||||
|
||||
file-base +".addr" dup ."Loading wallet address from " type cr file>B 32 B|
|
||||
dup Blen { 32 B>i@ } { drop Basechain } cond constant wallet_wc
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <seqno> [<savefile>]" cr
|
||||
{ ."usage: " $0 type ." <filename-base> <seqno> [<savefile>]" cr
|
||||
."Creates a request to simple configuration smart contract requesting to change configuration smart contract code to the one currently stored in auto/config-code.fif, "
|
||||
."with private key loaded from file <filename-base>.pk, "
|
||||
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
|
||||
|
@ -15,9 +15,10 @@ true constant bounce
|
|||
"auto/config-code.fif" constant config-source
|
||||
100 constant interval // valid for 100 seconds
|
||||
|
||||
3 :$1..n
|
||||
$1 =: file-base
|
||||
$2 parse-int =: qseqno
|
||||
def? $3 { @' $3 } { "config-query" } cond constant savefile
|
||||
$3 "config-query" replace-if-null constant savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
2dup 2constant config_addr
|
||||
|
|
|
@ -1,30 +1,52 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ show-options-help 1 halt } : usage
|
||||
|
||||
"" =: comment // comment for simple transfers
|
||||
true =: allow-bounce
|
||||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 =: timeout // external message expires in 60 seconds
|
||||
|
||||
begin-options
|
||||
" <filename-base> <dest-addr> <seqno> <amount> [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
+"Creates a request to advanced wallet created by new-wallet-v2.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
|
||||
generic-help
|
||||
"n" "--no-bounce" { false =: allow-bounce } short-long-option
|
||||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
|
||||
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
|
||||
"B" "--body" { =: body-boc-file } short-long-option-arg
|
||||
"Sets the payload of the transfer message" option-help
|
||||
"C" "--comment" { =: comment } short-long-option-arg
|
||||
"Sets the comment to be sent in the transfer message" option-help
|
||||
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
|
||||
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
|
||||
option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <dest-addr> <seqno> <amount> [-B <body-boc>] [<savefile>]" cr
|
||||
."Creates a request to advanced wallet created by new-wallet-v2.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr 1 halt
|
||||
} : usage
|
||||
def? $6 { @' $5 "-B" $= { @' $6 =: body-boc-file [forget] $6 def? $7 { @' $7 =: $5 [forget] $7 } { [forget] $5 } cond
|
||||
@' $# 2- =: $# } if } if
|
||||
$# dup 4 < swap 5 > or ' usage if
|
||||
|
||||
5 :$1..n
|
||||
true constant bounce
|
||||
|
||||
$1 =: file-base
|
||||
$2 bounce parse-load-address =: bounce 2=: dest_addr
|
||||
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
|
||||
$3 parse-int =: seqno
|
||||
$4 $>GR =: amount
|
||||
def? $5 { @' $5 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
$5 "wallet-query" replace-if-null =: savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
."Source wallet address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant wallet_pk
|
||||
|
||||
def? body-boc-file { @' body-boc-file file>B B>boc } { <b 0 32 u, "TESTv2" $, b> } cond
|
||||
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
|
||||
constant body-cell
|
||||
|
||||
."Transferring " amount .GR ."to account "
|
||||
|
|
|
@ -1,31 +1,54 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ show-options-help 1 halt } : usage
|
||||
|
||||
"" =: comment // comment for simple transfers
|
||||
true =: allow-bounce
|
||||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 =: timeout // external message expires in 60 seconds
|
||||
|
||||
begin-options
|
||||
" <filename-base> <dest-addr> <subwallet-id> <seqno> <amount> [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
+"Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
|
||||
generic-help
|
||||
"n" "--no-bounce" { false =: allow-bounce } short-long-option
|
||||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
|
||||
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
|
||||
"B" "--body" { =: body-boc-file } short-long-option-arg
|
||||
"Sets the payload of the transfer message" option-help
|
||||
"C" "--comment" { =: comment } short-long-option-arg
|
||||
"Sets the comment to be sent in the transfer message" option-help
|
||||
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
|
||||
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
|
||||
option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <dest-addr> <subwallet_id> <seqno> <amount> [-B <body-boc>] [<savefile>]" cr
|
||||
."Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr 1 halt
|
||||
} : usage
|
||||
def? $7 { @' $6 "-B" $= { @' $7 =: body-boc-file [forget] $7 def? $8 { @' $8 =: $6 [forget] $8 } { [forget] $6 } cond
|
||||
@' $# 2- =: $# } if } if
|
||||
$# dup 5 < swap 6 > or ' usage if
|
||||
6 :$1..n
|
||||
|
||||
true constant bounce
|
||||
|
||||
$1 =: file-base
|
||||
$2 bounce parse-load-address =: bounce 2=: dest_addr
|
||||
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
|
||||
$3 parse-int =: subwallet_id
|
||||
$4 parse-int =: seqno
|
||||
$5 $>GR =: amount
|
||||
def? $6 { @' $6 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
$6 "wallet-query" replace-if-null =: savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
."Source wallet address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant wallet_pk
|
||||
|
||||
def? body-boc-file { @' body-boc-file file>B B>boc } { <b 0 32 u, "TESTv3" $, b> } cond
|
||||
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
|
||||
constant body-cell
|
||||
|
||||
."Transferring " amount .GR ."to account "
|
||||
|
|
|
@ -2,31 +2,42 @@
|
|||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <dest-addr> <seqno> <amount> [-n] [-B <body-boc>] [-C <transfer-comment>] [<savefile>]" cr
|
||||
."Creates a request to simple wallet created by new-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr 1 halt
|
||||
} : usage
|
||||
{ show-options-help 1 halt } : usage
|
||||
|
||||
"" =: comment // comment for simple transfers
|
||||
true =: allow-bounce
|
||||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
|
||||
begin-options
|
||||
" <filename-base> <dest-addr> <seqno> <amount> [-n|-b] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
+"Creates a request to simple wallet created by new-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
|
||||
generic-help
|
||||
"n" "--no-bounce" { false =: allow-bounce } short-long-option
|
||||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"B" "--body" { =: body-boc-file } short-long-option-arg
|
||||
"Sets the payload of the transfer message" option-help
|
||||
"C" "--comment" { =: comment } short-long-option-arg
|
||||
"Sets the comment to be sent in the transfer message" option-help
|
||||
"m" "--mode" { parse-int =: send-mode } short-long-option-arg
|
||||
"Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)"
|
||||
option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
$# dup 4 < swap 5 > or ' usage if
|
||||
5 :$1..n
|
||||
true =: bounce
|
||||
$1 =: file-base
|
||||
$2 bounce parse-load-address allow-bounce and =: bounce 2=: dest_addr
|
||||
$2 bounce parse-load-address allow-bounce and force-bounce or =: bounce 2=: dest_addr
|
||||
$3 parse-int =: seqno
|
||||
$4 $>GR =: amount
|
||||
$5 dup null? { drop "wallet-query" } if =: savefile
|
||||
$5 "wallet-query" replace-if-null =: savefile
|
||||
allow-bounce not force-bounce and abort"cannot have bounce flag both set and cleared"
|
||||
// "" 1 { 69091 * 1+ 65535 and tuck 2521 / 65 + hold swap } 1000 times drop =: comment
|
||||
|
||||
file-base +".addr" load-address
|
||||
|
|
|
@ -226,7 +226,7 @@ TEST(Tonlib, Wallet) {
|
|||
auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
|
||||
fift_output =
|
||||
fift::mem_run_fift(std::move(fift_output.source_lookup),
|
||||
{"aba", "new-wallet", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "123", "321"})
|
||||
{"aba", "new-wallet", "-C", "TESTv2", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "123", "321"})
|
||||
.move_as_ok();
|
||||
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
|
||||
auto gift_message = ton::GenericAccount::create_ext_message(
|
||||
|
@ -275,7 +275,7 @@ TEST(Tonlib, WalletV3) {
|
|||
auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
|
||||
fift_output =
|
||||
fift::mem_run_fift(std::move(fift_output.source_lookup),
|
||||
{"aba", "new-wallet", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "239", "123", "321"})
|
||||
{"aba", "new-wallet", "-C", "TESTv3", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "239", "123", "321"})
|
||||
.move_as_ok();
|
||||
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
|
||||
auto gift_message = ton::GenericAccount::create_ext_message(
|
||||
|
|
|
@ -922,7 +922,7 @@ void CppTypeCode::generate_get_tag_param1(std::ostream& os, std::string nl, cons
|
|||
match_param_pattern(os, nl, A, 8, "# > 1 && (# & 1)", param_names[0])) {
|
||||
return;
|
||||
}
|
||||
os << nl << "static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }";
|
||||
os << nl << "// static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }";
|
||||
os << nl << "static signed char ctab[4] = { ";
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i > 0) {
|
||||
|
@ -941,7 +941,7 @@ void CppTypeCode::generate_get_tag_param2(std::ostream& os, std::string nl, cons
|
|||
os << ' ' << (int)A[i][j];
|
||||
}
|
||||
}
|
||||
os << nl << "static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }";
|
||||
os << nl << "// static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }";
|
||||
os << nl << "static signed char ctab[4][4] = { ";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i > 0) {
|
||||
|
@ -964,7 +964,7 @@ void CppTypeCode::generate_get_tag_param3(std::ostream& os, std::string nl, cons
|
|||
}
|
||||
}
|
||||
}
|
||||
os << nl << "static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }";
|
||||
os << nl << "// static inline size_t nat_abs(int x) { return (x > 1) * 2 + (x & 1); }";
|
||||
os << nl << "static signed char ctab[4][4][4] = { ";
|
||||
for (int i = 0; i < 64; i++) {
|
||||
if (i > 0) {
|
||||
|
|
|
@ -218,6 +218,9 @@ class TLB {
|
|||
return cs_ref.not_null() ? as_string(*cs_ref, indent) : "<null>";
|
||||
}
|
||||
std::string as_string_ref(Ref<vm::Cell> cell_ref, int indent = 0) const;
|
||||
static inline size_t nat_abs(int x) {
|
||||
return (x > 1) * 2 + (x & 1);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool validate_ref_internal(Ref<vm::Cell> cell_ref, bool weak = false) const;
|
||||
|
|
|
@ -85,6 +85,10 @@ class CellBuilder : public td::CntObject {
|
|||
return idx < refs_cnt ? refs[idx] : Ref<Cell>{};
|
||||
}
|
||||
void reset();
|
||||
bool reset_bool() {
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
CellBuilder& operator=(const CellBuilder&);
|
||||
CellBuilder& operator=(CellBuilder&&);
|
||||
CellBuilder& store_bytes(const char* str, std::size_t len);
|
||||
|
|
|
@ -218,6 +218,17 @@ unsigned CellSlice::get_level() const {
|
|||
return l;
|
||||
}
|
||||
|
||||
Ref<Cell> CellSlice::get_base_cell() const {
|
||||
if (cell.is_null()) {
|
||||
return {};
|
||||
}
|
||||
auto res = cell->virtualize(virt);
|
||||
if (!tree_node.empty()) {
|
||||
res = UsageCell::create(std::move(res), tree_node);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellSlice::advance(unsigned bits) {
|
||||
if (have(bits)) {
|
||||
bits_st += bits;
|
||||
|
|
|
@ -137,6 +137,7 @@ class CellSlice : public td::CntObject {
|
|||
}
|
||||
unsigned get_cell_level() const;
|
||||
unsigned get_level() const;
|
||||
Ref<Cell> get_base_cell() const; // be careful with this one!
|
||||
int fetch_octet();
|
||||
int prefetch_octet() const;
|
||||
unsigned long long prefetch_ulong_top(unsigned& bits) const;
|
||||
|
|
|
@ -107,6 +107,47 @@ ControlRegs& ControlRegs::operator&=(const ControlRegs& save) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool ControlRegs::serialize(CellBuilder& cb) const {
|
||||
Dictionary dict{4};
|
||||
CellBuilder cb2;
|
||||
for (int i = 0; i < creg_num; i++) {
|
||||
if (c[i].not_null() &&
|
||||
!(StackEntry{c[i]}.serialize(cb2) && dict.set_builder(td::BitArray<4>(i), cb2) && cb2.reset_bool())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dreg_num; i++) {
|
||||
if (d[i].not_null() && !(StackEntry{d[i]}.serialize(cb2) && dict.set_builder(td::BitArray<4>(dreg_idx + i), cb2) &&
|
||||
cb2.reset_bool())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (c7.is_null() || (StackEntry{c7}.serialize(cb2) && dict.set_builder(td::BitArray<4>(7), cb2))) &&
|
||||
std::move(dict).append_dict_to_bool(cb);
|
||||
}
|
||||
|
||||
bool ControlData::serialize(CellBuilder& cb) const {
|
||||
// vm_ctl_data$_ nargs:(Maybe int13) stack:(Maybe VmStack) save:VmSaveList
|
||||
// cp:(Maybe int16) = VmControlData;
|
||||
return cb.store_bool_bool(nargs >= 0) // vm_ctl_data$_ nargs:(Maybe ...
|
||||
&& (nargs < 0 || cb.store_long_bool(nargs, 13)) // ... int13)
|
||||
&& cb.store_bool_bool(stack.not_null()) // stack:(Maybe ...
|
||||
&& (stack.is_null() || stack->serialize(cb)) // ... VmStack)
|
||||
&& save.serialize(cb) // save:VmSaveList
|
||||
&& cb.store_bool_bool(cp != -1) // cp:(Maybe ...
|
||||
&& (cp == -1 || cb.store_long_bool(cp, 16)); // ... int16)
|
||||
}
|
||||
|
||||
bool Continuation::serialize_ref(CellBuilder& cb) const {
|
||||
vm::CellBuilder cb2;
|
||||
return serialize(cb2) && cb.store_ref_bool(cb2.finalize());
|
||||
}
|
||||
|
||||
bool QuitCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_quit$1000 exit_code:int32 = VmCont;
|
||||
return cb.store_long_bool(8, 4) && cb.store_long_bool(exit_code, 32);
|
||||
}
|
||||
|
||||
int ExcQuitCont::jump(VmState* st) const & {
|
||||
int n = 0;
|
||||
try {
|
||||
|
@ -118,6 +159,11 @@ int ExcQuitCont::jump(VmState* st) const & {
|
|||
return ~n;
|
||||
}
|
||||
|
||||
bool ExcQuitCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_quit_exc$1001 = VmCont;
|
||||
return cb.store_long_bool(9, 4);
|
||||
}
|
||||
|
||||
int PushIntCont::jump(VmState* st) const & {
|
||||
VM_LOG(st) << "execute implicit PUSH " << push_val << " (slow)";
|
||||
st->get_stack().push_smallint(push_val);
|
||||
|
@ -130,6 +176,11 @@ int PushIntCont::jump_w(VmState* st) & {
|
|||
return st->jump(std::move(next));
|
||||
}
|
||||
|
||||
bool PushIntCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_pushint$1111 value:int32 next:^VmCont = VmCont;
|
||||
return cb.store_long_bool(15, 4) && cb.store_long_bool(push_val, 32) && next->serialize_ref(cb);
|
||||
}
|
||||
|
||||
int ArgContExt::jump(VmState* st) const & {
|
||||
st->adjust_cr(data.save);
|
||||
if (data.cp != -1) {
|
||||
|
@ -146,6 +197,11 @@ int ArgContExt::jump_w(VmState* st) & {
|
|||
return st->jump_to(std::move(ext));
|
||||
}
|
||||
|
||||
bool ArgContExt::serialize(CellBuilder& cb) const {
|
||||
// vmc_envelope$01 cdata:VmControlData next:^VmCont = VmCont;
|
||||
return cb.store_long_bool(1, 2) && data.serialize(cb) && ext->serialize_ref(cb);
|
||||
}
|
||||
|
||||
int RepeatCont::jump(VmState* st) const & {
|
||||
VM_LOG(st) << "repeat " << count << " more times (slow)\n";
|
||||
if (count <= 0) {
|
||||
|
@ -174,6 +230,12 @@ int RepeatCont::jump_w(VmState* st) & {
|
|||
return st->jump(body);
|
||||
}
|
||||
|
||||
bool RepeatCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_repeat$10100 count:uint63 body:^VmCont after:^VmCont = VmCont;
|
||||
return cb.store_long_bool(0x14, 5) && cb.store_long_bool(count, 63) && body->serialize_ref(cb) &&
|
||||
after->serialize_ref(cb);
|
||||
}
|
||||
|
||||
int VmState::repeat(Ref<Continuation> body, Ref<Continuation> after, long long count) {
|
||||
if (count <= 0) {
|
||||
body.clear();
|
||||
|
@ -201,6 +263,11 @@ int AgainCont::jump_w(VmState* st) & {
|
|||
}
|
||||
}
|
||||
|
||||
bool AgainCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_again$110001 body:^VmCont = VmCont;
|
||||
return cb.store_long_bool(0x31, 6) && body->serialize_ref(cb);
|
||||
}
|
||||
|
||||
int VmState::again(Ref<Continuation> body) {
|
||||
return jump(Ref<AgainCont>{true, std::move(body)});
|
||||
}
|
||||
|
@ -233,6 +300,11 @@ int UntilCont::jump_w(VmState* st) & {
|
|||
}
|
||||
}
|
||||
|
||||
bool UntilCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_until$110000 body:^VmCont after:^VmCont = VmCont;
|
||||
return cb.store_long_bool(0x30, 6) && body->serialize_ref(cb) && after->serialize_ref(cb);
|
||||
}
|
||||
|
||||
int VmState::until(Ref<Continuation> body, Ref<Continuation> after) {
|
||||
if (!body->has_c0()) {
|
||||
set_c0(Ref<UntilCont>{true, body, std::move(after)});
|
||||
|
@ -292,6 +364,13 @@ int WhileCont::jump_w(VmState* st) & {
|
|||
}
|
||||
}
|
||||
|
||||
bool WhileCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_while_cond$110010 cond:^VmCont body:^VmCont after:^VmCont = VmCont;
|
||||
// vmc_while_body$110011 cond:^VmCont body:^VmCont after:^VmCont = VmCont;
|
||||
return cb.store_long_bool(0x19, 5) && cb.store_bool_bool(!chkcond) && cond->serialize_ref(cb) &&
|
||||
body->serialize_ref(cb) && after->serialize_ref(cb);
|
||||
}
|
||||
|
||||
int VmState::loop_while(Ref<Continuation> cond, Ref<Continuation> body, Ref<Continuation> after) {
|
||||
if (!cond->has_c0()) {
|
||||
set_c0(Ref<WhileCont>{true, cond, std::move(body), std::move(after), true});
|
||||
|
@ -311,6 +390,11 @@ int OrdCont::jump_w(VmState* st) & {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool OrdCont::serialize(CellBuilder& cb) const {
|
||||
// vmc_std$00 cdata:VmControlData code:VmCellSlice = VmCont;
|
||||
return cb.store_long_bool(1, 2) && data.serialize(cb) && StackEntry{code}.serialize(cb);
|
||||
}
|
||||
|
||||
void VmState::init_cregs(bool same_c3, bool push_0) {
|
||||
cr.set_c0(quit0);
|
||||
cr.set_c1(quit1);
|
||||
|
|
|
@ -135,6 +135,7 @@ struct ControlRegs {
|
|||
ControlRegs& operator&=(const ControlRegs& save); // clears all c[i]'s which are present in save
|
||||
ControlRegs& operator^=(const ControlRegs& save); // sets c[i]=save.c[i] for all save.c[i] != 0
|
||||
ControlRegs& operator^=(ControlRegs&& save);
|
||||
bool serialize(CellBuilder& cb) const;
|
||||
};
|
||||
|
||||
struct ControlData {
|
||||
|
@ -150,11 +151,12 @@ struct ControlData {
|
|||
}
|
||||
ControlData(int _cp, Ref<Stack> _stack, int _nargs = -1) : stack(std::move(_stack)), nargs(_nargs), cp(_cp) {
|
||||
}
|
||||
bool serialize(CellBuilder& cb) const;
|
||||
};
|
||||
|
||||
class Continuation : public td::CntObject {
|
||||
public:
|
||||
virtual int jump(VmState* st) const& = 0;
|
||||
virtual int jump(VmState* st) const & = 0;
|
||||
virtual int jump_w(VmState* st) &;
|
||||
virtual ControlData* get_cdata() {
|
||||
return 0;
|
||||
|
@ -162,6 +164,10 @@ class Continuation : public td::CntObject {
|
|||
virtual const ControlData* get_cdata() const {
|
||||
return 0;
|
||||
}
|
||||
virtual bool serialize(CellBuilder& cb) const {
|
||||
return false;
|
||||
}
|
||||
bool serialize_ref(CellBuilder& cb) const;
|
||||
bool has_c0() const;
|
||||
Continuation() {
|
||||
}
|
||||
|
@ -184,16 +190,18 @@ class QuitCont : public Continuation {
|
|||
QuitCont(int _code = 0) : exit_code(_code) {
|
||||
}
|
||||
~QuitCont() override = default;
|
||||
int jump(VmState* st) const& override {
|
||||
int jump(VmState* st) const & override {
|
||||
return ~exit_code;
|
||||
}
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class ExcQuitCont : public Continuation {
|
||||
public:
|
||||
ExcQuitCont() = default;
|
||||
~ExcQuitCont() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class PushIntCont : public Continuation {
|
||||
|
@ -204,8 +212,9 @@ class PushIntCont : public Continuation {
|
|||
PushIntCont(int val, Ref<Continuation> _next) : push_val(val), next(_next) {
|
||||
}
|
||||
~PushIntCont() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class RepeatCont : public Continuation {
|
||||
|
@ -217,8 +226,9 @@ class RepeatCont : public Continuation {
|
|||
: body(std::move(_body)), after(std::move(_after)), count(_count) {
|
||||
}
|
||||
~RepeatCont() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class AgainCont : public Continuation {
|
||||
|
@ -228,8 +238,9 @@ class AgainCont : public Continuation {
|
|||
AgainCont(Ref<Continuation> _body) : body(std::move(_body)) {
|
||||
}
|
||||
~AgainCont() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class UntilCont : public Continuation {
|
||||
|
@ -239,8 +250,9 @@ class UntilCont : public Continuation {
|
|||
UntilCont(Ref<Continuation> _body, Ref<Continuation> _after) : body(std::move(_body)), after(std::move(_after)) {
|
||||
}
|
||||
~UntilCont() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class WhileCont : public Continuation {
|
||||
|
@ -252,8 +264,9 @@ class WhileCont : public Continuation {
|
|||
: cond(std::move(_cond)), body(std::move(_body)), after(std::move(_after)), chkcond(_chk) {
|
||||
}
|
||||
~WhileCont() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class ArgContExt : public Continuation {
|
||||
|
@ -268,7 +281,7 @@ class ArgContExt : public Continuation {
|
|||
ArgContExt(const ArgContExt&) = default;
|
||||
ArgContExt(ArgContExt&&) = default;
|
||||
~ArgContExt() override = default;
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
ControlData* get_cdata() override {
|
||||
return &data;
|
||||
|
@ -279,6 +292,7 @@ class ArgContExt : public Continuation {
|
|||
td::CntObject* make_copy() const override {
|
||||
return new ArgContExt{*this};
|
||||
}
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
class OrdCont : public Continuation {
|
||||
|
@ -303,7 +317,7 @@ class OrdCont : public Continuation {
|
|||
td::CntObject* make_copy() const override {
|
||||
return new OrdCont{*this};
|
||||
}
|
||||
int jump(VmState* st) const& override;
|
||||
int jump(VmState* st) const & override;
|
||||
int jump_w(VmState* st) & override;
|
||||
|
||||
ControlData* get_cdata() override {
|
||||
|
@ -321,12 +335,13 @@ class OrdCont : public Continuation {
|
|||
Ref<Stack> get_stack_ref() const {
|
||||
return data.stack;
|
||||
}
|
||||
Ref<OrdCont> copy_ord() const& {
|
||||
Ref<OrdCont> copy_ord() const & {
|
||||
return Ref<OrdCont>{true, *this};
|
||||
}
|
||||
Ref<OrdCont> copy_ord() && {
|
||||
return Ref<OrdCont>{true, *this};
|
||||
}
|
||||
bool serialize(CellBuilder& cb) const override;
|
||||
};
|
||||
|
||||
struct GasLimits {
|
||||
|
|
|
@ -671,4 +671,91 @@ void Stack::push_maybe_cellslice(Ref<CellSlice> cs) {
|
|||
push_maybe(std::move(cs));
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* SERIALIZE/DESERIALIZE STACK VALUES
|
||||
*
|
||||
*/
|
||||
|
||||
bool StackEntry::serialize(vm::CellBuilder& cb, int mode) const {
|
||||
switch (tp) {
|
||||
case t_null:
|
||||
return cb.store_long_bool(0, 8); // vm_stk_null#00 = VmStackValue;
|
||||
case t_int: {
|
||||
auto val = as_int();
|
||||
if (!val->is_valid()) {
|
||||
// vm_stk_nan#02ff = VmStackValue;
|
||||
return cb.store_long_bool(0x02ff, 16);
|
||||
} else if (!(mode & 1) && val->signed_fits_bits(64)) {
|
||||
// vm_stk_tinyint#01 value:int64 = VmStackValue;
|
||||
return cb.store_long_bool(1, 8) && cb.store_int256_bool(std::move(val), 256);
|
||||
} else {
|
||||
// vm_stk_int#0201_ value:int257 = VmStackValue;
|
||||
return cb.store_long_bool(0x0200 / 2, 15) && cb.store_int256_bool(std::move(val), 257);
|
||||
}
|
||||
}
|
||||
case t_cell:
|
||||
// vm_stk_cell#03 cell:^Cell = VmStackValue;
|
||||
return cb.store_long_bool(3, 8) && cb.store_ref_bool(as_cell());
|
||||
case t_slice: {
|
||||
// _ cell:^Cell st_bits:(## 10) end_bits:(## 10) { st_bits <= end_bits }
|
||||
// st_ref:(#<= 4) end_ref:(#<= 4) { st_ref <= end_ref } = VmCellSlice;
|
||||
const auto& cs = *static_cast<Ref<CellSlice>>(ref);
|
||||
return cb.store_long_bool(4, 8) // vm_stk_slice#04 _:VmCellSlice = VmStackValue;
|
||||
&& cb.store_ref_bool(cs.get_base_cell()) // _ cell:^Cell
|
||||
&& cb.store_long_bool(cs.cur_pos(), 10) // st_bits:(## 10)
|
||||
&& cb.store_long_bool(cs.cur_pos() + cs.size(), 10) // end_bits:(## 10)
|
||||
&& cb.store_long_bool(cs.cur_ref(), 3) // st_ref:(#<= 4)
|
||||
&& cb.store_long_bool(cs.cur_ref() + cs.size_refs(), 3); // end_ref:(#<= 4)
|
||||
}
|
||||
case t_builder:
|
||||
// vm_stk_builder#05 cell:^Cell = VmStackValue;
|
||||
return cb.store_long_bool(5, 8) && cb.store_ref_bool(as_builder()->finalize_copy());
|
||||
case t_vmcont:
|
||||
// vm_stk_cont#06 cont:VmCont = VmStackValue;
|
||||
return !(mode & 2) && cb.store_long_bool(6, 8) && as_cont()->serialize(cb);
|
||||
case t_tuple: {
|
||||
const auto& tuple = *static_cast<Ref<Tuple>>(ref);
|
||||
auto n = tuple.size();
|
||||
// vm_stk_tuple#07 len:(## 16) data:(VmTuple len) = VmStackValue;
|
||||
Ref<Cell> head, tail;
|
||||
vm::CellBuilder cb2;
|
||||
for (std::size_t i = 0; i < n; i++) {
|
||||
std::swap(head, tail);
|
||||
if (i > 1 &&
|
||||
!(cb2.store_ref_bool(std::move(tail)) && cb2.store_ref_bool(std::move(head)) && cb2.finalize_to(head))) {
|
||||
return false;
|
||||
}
|
||||
if (!(tuple[i].serialize(cb2, mode) && cb2.finalize_to(tail))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return cb.store_long_bool(7, 8) && cb.store_long_bool(n, 16) && (head.is_null() || cb.store_ref_bool(head)) &&
|
||||
(tail.is_null() || cb.store_ref_bool(tail));
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Stack::serialize(vm::CellBuilder& cb, int mode) const {
|
||||
// vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack;
|
||||
unsigned n = depth();
|
||||
if (!cb.store_ulong_rchk_bool(n, 24)) { // vm_stack#_ depth:(## 24)
|
||||
return false;
|
||||
}
|
||||
if (!n) {
|
||||
return true;
|
||||
}
|
||||
vm::CellBuilder cb2;
|
||||
Ref<vm::Cell> rest = cb2.finalize(); // vm_stk_nil#_ = VmStackList 0;
|
||||
for (unsigned i = 0; i < n - 1; i++) {
|
||||
// vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1);
|
||||
if (!(cb2.store_ref_bool(std::move(rest)) && stack[i].serialize(cb2, mode) && cb2.finalize_to(rest))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return cb.store_ref_bool(std::move(rest)) && stack[n - 1].serialize(cb, mode);
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -166,6 +166,8 @@ class StackEntry {
|
|||
Type type() const {
|
||||
return tp;
|
||||
}
|
||||
// mode: +1 = disable short ints, +2 = disable continuations
|
||||
bool serialize(vm::CellBuilder& cb, int mode = 0) const;
|
||||
|
||||
private:
|
||||
static bool is_list(const StackEntry* se);
|
||||
|
@ -508,6 +510,7 @@ class Stack : public td::CntObject {
|
|||
}
|
||||
// mode: +1 = add eoln, +2 = Lisp-style lists
|
||||
void dump(std::ostream& os, int mode = 1) const;
|
||||
bool serialize(vm::CellBuilder& cb, int mode = 0) const;
|
||||
};
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -284,7 +284,7 @@ struct BlockIdExt {
|
|||
BlockIdExt v;
|
||||
char rh[65];
|
||||
char fh[65];
|
||||
auto r = sscanf(s.begin(), "(%d,%" SCNu64 ",%u):%64s:%64s", &v.id.workchain, &v.id.shard, &v.id.seqno, rh, fh);
|
||||
auto r = sscanf(s.begin(), "(%d,%" SCNx64 ",%u):%64s:%64s", &v.id.workchain, &v.id.shard, &v.id.seqno, rh, fh);
|
||||
if (r < 5) {
|
||||
return td::Status::Error("failed to parse block id");
|
||||
}
|
||||
|
|
|
@ -927,7 +927,6 @@ void ValidatorEngine::alarm() {
|
|||
auto config = configR.move_as_ok();
|
||||
auto cur_t = config->get_validator_set_start_stop(0);
|
||||
CHECK(cur_t.first > 0);
|
||||
LOG(ERROR) << "curt: " << cur_t.first << " " << cur_t.second;
|
||||
|
||||
auto val_set = state_->get_total_validator_set(0);
|
||||
auto e = val_set->export_vector();
|
||||
|
|
|
@ -162,13 +162,13 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
virtual void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
static bool is_persistent_state(UnixTime ts, UnixTime prev_ts) {
|
||||
return ts / 1024 != prev_ts / 1024;
|
||||
return ts / (1 << 17) != prev_ts / (1 << 17);
|
||||
}
|
||||
static UnixTime persistent_state_ttl(UnixTime ts) {
|
||||
auto x = ts / 1024;
|
||||
auto x = ts / (1 << 17);
|
||||
CHECK(x > 0);
|
||||
auto b = td::count_trailing_zeroes32(x);
|
||||
return ts + (2048 << b);
|
||||
return ts + ((1 << 18) << b);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue