1
0
Fork 0
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:
ton 2019-12-05 16:51:51 +04:00
parent 090e0c16eb
commit ceaed40ac4
28 changed files with 530 additions and 108 deletions

View file

@ -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;

View file

@ -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};
}

View file

@ -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;

View file

@ -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 } ::_ $<<

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 "

View file

@ -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 "

View file

@ -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

View file

@ -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(

View file

@ -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) {

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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");
}

View file

@ -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();

View file

@ -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);
}
};