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

liteserver: bugfix

liteserver/liteclient: fixed bug in proof
validator: added stats
smartcontracts: updates
This commit is contained in:
ton 2019-09-30 16:49:45 +04:00
parent ecb3e06a06
commit 2845f9a2cc
30 changed files with 280 additions and 124 deletions

View file

@ -25,7 +25,7 @@
{ bl word 1 { -rot 2 'nop does swap 0 (create) } { bl word 1 { -rot 2 'nop does swap 0 (create) }
} :: 2=: } :: 2=:
{ <b swap s, b> } : s>c { <b swap s, b> } : s>c
{ s>c hash } : shash { s>c hashB } : shash
// to be more efficiently re-implemented in C++ in the future // to be more efficiently re-implemented in C++ in the future
{ dup 0< ' negate if } : abs { dup 0< ' negate if } : abs
{ 2dup > ' swap if } : minmax { 2dup > ' swap if } : minmax

View file

@ -764,13 +764,17 @@ void interpret_string_to_bytes(vm::Stack& stack) {
stack.push_bytes(stack.pop_string()); stack.push_bytes(stack.pop_string());
} }
void interpret_bytes_hash(vm::Stack& stack) { void interpret_bytes_hash(vm::Stack& stack, bool as_uint) {
std::string str = stack.pop_bytes(); std::string str = stack.pop_bytes();
unsigned char buffer[32]; unsigned char buffer[32];
digest::hash_str<digest::SHA256>(buffer, str.c_str(), str.size()); digest::hash_str<digest::SHA256>(buffer, str.c_str(), str.size());
if (as_uint) {
td::RefInt256 x{true}; td::RefInt256 x{true};
x.write().import_bytes(buffer, 32, false); x.write().import_bytes(buffer, 32, false);
stack.push_int(std::move(x)); stack.push_int(std::move(x));
} else {
stack.push_bytes(std::string{(char*)buffer, 32});
}
} }
void interpret_empty(vm::Stack& stack) { void interpret_empty(vm::Stack& stack) {
@ -892,11 +896,15 @@ void interpret_builder_remaining_bitrefs(vm::Stack& stack, int mode) {
} }
} }
void interpret_cell_hash(vm::Stack& stack) { void interpret_cell_hash(vm::Stack& stack, bool as_uint) {
auto cell = stack.pop_cell(); auto cell = stack.pop_cell();
if (as_uint) {
td::RefInt256 hash{true}; td::RefInt256 hash{true};
hash.write().import_bytes(cell->get_hash().as_slice().ubegin(), 32, false); hash.write().import_bytes(cell->get_hash().as_slice().ubegin(), 32, false);
stack.push_int(std::move(hash)); stack.push_int(std::move(hash));
} else {
stack.push_bytes(cell->get_hash().as_slice().str());
}
} }
void interpret_store_ref(vm::Stack& stack) { void interpret_store_ref(vm::Stack& stack) {
@ -959,7 +967,9 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) {
unsigned n = stack.pop_smallint_range(127); unsigned n = stack.pop_smallint_range(127);
auto cs = stack.pop_cellslice(); auto cs = stack.pop_cellslice();
if (!cs->have(n * 8)) { if (!cs->have(n * 8)) {
if (mode & 2) {
stack.push(std::move(cs)); stack.push(std::move(cs));
}
stack.push_bool(false); stack.push_bool(false);
if (!(mode & 4)) { if (!(mode & 4)) {
throw IntError{"end of data while reading byte string from cell"}; throw IntError{"end of data while reading byte string from cell"};
@ -970,7 +980,7 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) {
if (mode & 2) { if (mode & 2) {
cs.write().fetch_bytes(tmp, n); cs.write().fetch_bytes(tmp, n);
} else { } else {
cs.write().prefetch_bytes(tmp, n); cs->prefetch_bytes(tmp, n);
} }
std::string s{tmp, tmp + n}; std::string s{tmp, tmp + n};
if (mode & 1) { if (mode & 1) {
@ -978,7 +988,9 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) {
} else { } else {
stack.push_string(std::move(s)); stack.push_string(std::move(s));
} }
if (mode & 2) {
stack.push(std::move(cs)); stack.push(std::move(cs));
}
if (mode & 4) { if (mode & 4) {
stack.push_bool(true); stack.push_bool(true);
} }
@ -1009,13 +1021,15 @@ void interpret_cell_remaining(vm::Stack& stack) {
void interpret_fetch_ref(vm::Stack& stack, int mode) { void interpret_fetch_ref(vm::Stack& stack, int mode) {
auto cs = stack.pop_cellslice(); auto cs = stack.pop_cellslice();
if (!cs->have_refs(1)) { if (!cs->have_refs(1)) {
if (mode & 2) {
stack.push(std::move(cs)); stack.push(std::move(cs));
}
stack.push_bool(false); stack.push_bool(false);
if (!(mode & 4)) { if (!(mode & 4)) {
throw IntError{"end of data while reading reference from cell"}; throw IntError{"end of data while reading reference from cell"};
} }
} else { } else {
auto cell = (mode & 2) ? cs.write().fetch_ref() : cs.write().prefetch_ref(); auto cell = (mode & 2) ? cs.write().fetch_ref() : cs->prefetch_ref();
if (mode & 2) { if (mode & 2) {
stack.push(std::move(cs)); stack.push(std::move(cs));
} }
@ -2474,7 +2488,9 @@ void init_words_common(Dictionary& d) {
d.def_stack_word("B>Lu@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x12)); d.def_stack_word("B>Lu@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x12));
d.def_stack_word("B>Li@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x13)); d.def_stack_word("B>Li@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x13));
d.def_stack_word("$>B ", interpret_string_to_bytes); d.def_stack_word("$>B ", interpret_string_to_bytes);
d.def_stack_word("Bhash ", interpret_bytes_hash); d.def_stack_word("Bhash ", std::bind(interpret_bytes_hash, _1, true));
d.def_stack_word("Bhashu ", std::bind(interpret_bytes_hash, _1, true));
d.def_stack_word("BhashB ", std::bind(interpret_bytes_hash, _1, false));
// cell manipulation (create, write and modify cells) // cell manipulation (create, write and modify cells)
d.def_stack_word("<b ", interpret_empty); d.def_stack_word("<b ", interpret_empty);
d.def_stack_word("i, ", std::bind(interpret_store, _1, true)); d.def_stack_word("i, ", std::bind(interpret_store, _1, true));
@ -2496,7 +2512,9 @@ void init_words_common(Dictionary& d) {
d.def_stack_word("brembits ", std::bind(interpret_builder_remaining_bitrefs, _1, 1)); d.def_stack_word("brembits ", std::bind(interpret_builder_remaining_bitrefs, _1, 1));
d.def_stack_word("bremrefs ", std::bind(interpret_builder_remaining_bitrefs, _1, 2)); d.def_stack_word("bremrefs ", std::bind(interpret_builder_remaining_bitrefs, _1, 2));
d.def_stack_word("brembitrefs ", std::bind(interpret_builder_remaining_bitrefs, _1, 3)); d.def_stack_word("brembitrefs ", std::bind(interpret_builder_remaining_bitrefs, _1, 3));
d.def_stack_word("hash ", interpret_cell_hash); d.def_stack_word("hash ", std::bind(interpret_cell_hash, _1, true));
d.def_stack_word("hashu ", std::bind(interpret_cell_hash, _1, true));
d.def_stack_word("hashB ", std::bind(interpret_cell_hash, _1, false));
// cellslice manipulation (read from cells) // cellslice manipulation (read from cells)
d.def_stack_word("<s ", interpret_from_cell); d.def_stack_word("<s ", interpret_from_cell);
d.def_stack_word("i@ ", std::bind(interpret_fetch, _1, 1)); d.def_stack_word("i@ ", std::bind(interpret_fetch, _1, 1));

View file

@ -15,10 +15,10 @@ cr ."initial basechain state is:" cr dup <s csr. cr
dup dup 31 boc+>B dup Bx. cr dup dup 31 boc+>B dup Bx. cr
dup "basestate0" +suffix +".boc" tuck B>file dup "basestate0" +suffix +".boc" tuck B>file
."(Initial basechain state saved to file " type .")" cr ."(Initial basechain state saved to file " type .")" cr
Bhash dup =: basestate0_fhash Bhashu dup =: basestate0_fhash
."file hash=" dup x. space 256 u>B dup B>base64url type cr ."file hash=" dup x. space 256 u>B dup B>base64url type cr
"basestate0" +suffix +".fhash" B>file "basestate0" +suffix +".fhash" B>file
hash dup =: basestate0_rhash hashu dup =: basestate0_rhash
."root hash=" dup x. space 256 u>B dup B>base64url type cr ."root hash=" dup x. space 256 u>B dup B>base64url type cr
"basestate0" +suffix +".rhash" B>file "basestate0" +suffix +".rhash" B>file
@ -227,10 +227,10 @@ cr cr ."new state is:" cr dup <s csr. cr
dup 31 boc+>B dup Bx. cr dup 31 boc+>B dup Bx. cr
dup "zerostate" +suffix +".boc" tuck B>file dup "zerostate" +suffix +".boc" tuck B>file
."(Initial masterchain state saved to file " type .")" cr ."(Initial masterchain state saved to file " type .")" cr
Bhash dup =: zerostate_fhash Bhashu dup =: zerostate_fhash
."file hash=" dup x. space 256 u>B dup B>base64url type cr ."file hash=" dup x. space 256 u>B dup B>base64url type cr
"zerostate" +suffix +".fhash" B>file "zerostate" +suffix +".fhash" B>file
hash dup =: zerostate_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr hashu dup =: zerostate_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr
"zerostate" +suffix +".rhash" B>file "zerostate" +suffix +".rhash" B>file
basestate0_rhash ."Basestate0 root hash=" dup x. space 256 u>B B>base64url type cr basestate0_rhash ."Basestate0 root hash=" dup x. space 256 u>B B>base64url type cr
basestate0_fhash ."Basestate0 file hash=" dup x. space 256 u>B B>base64url type cr basestate0_fhash ."Basestate0 file hash=" dup x. space 256 u>B B>base64url type cr

View file

@ -15,10 +15,10 @@ cr ."initial basechain state is:" cr dup <s csr. cr
dup dup 31 boc+>B dup Bx. cr dup dup 31 boc+>B dup Bx. cr
dup "basestate0" +suffix +".boc" tuck B>file dup "basestate0" +suffix +".boc" tuck B>file
."(Initial basechain state saved to file " type .")" cr ."(Initial basechain state saved to file " type .")" cr
Bhash dup =: basestate0_fhash Bhashu dup =: basestate0_fhash
."file hash=" dup x. space 256 u>B dup B>base64url type cr ."file hash=" dup x. space 256 u>B dup B>base64url type cr
"basestate0" +suffix +".fhash" B>file "basestate0" +suffix +".fhash" B>file
hash dup =: basestate0_rhash hashu dup =: basestate0_rhash
."root hash=" dup x. space 256 u>B dup B>base64url type cr ."root hash=" dup x. space 256 u>B dup B>base64url type cr
"basestate0" +suffix +".rhash" B>file "basestate0" +suffix +".rhash" B>file
@ -231,10 +231,10 @@ cr cr ."new state is:" cr dup <s csr. cr
dup 31 boc+>B dup Bx. cr dup 31 boc+>B dup Bx. cr
dup "zerostate" +suffix +".boc" tuck B>file dup "zerostate" +suffix +".boc" tuck B>file
."(Initial masterchain state saved to file " type .")" cr ."(Initial masterchain state saved to file " type .")" cr
Bhash dup =: zerostate_fhash Bhashu dup =: zerostate_fhash
."file hash= " dup X. space 256 u>B dup B>base64url type cr ."file hash= " dup X. space 256 u>B dup B>base64url type cr
"zerostate" +suffix +".fhash" B>file "zerostate" +suffix +".fhash" B>file
hash dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr hashu dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr
"zerostate" +suffix +".rhash" B>file "zerostate" +suffix +".rhash" B>file
basestate0_rhash ."Basestate0 root hash= " dup X. space 256 u>B B>base64url type cr basestate0_rhash ."Basestate0 root hash= " dup X. space 256 u>B B>base64url type cr
basestate0_fhash ."Basestate0 file hash= " dup X. space 256 u>B B>base64url type cr basestate0_fhash ."Basestate0 file hash= " dup X. space 256 u>B B>base64url type cr

View file

@ -59,7 +59,7 @@ order-file include
// create external message // create external message
<b subwallet-id 32 i, now timeout + 32 u, seqno 32 u, orders @ dict, b> <b subwallet-id 32 i, now timeout + 32 u, seqno 32 u, orders @ dict, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint dup hashu wallet_pk ed25519_sign_uint
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s, <b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b> swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr dup ."resulting external message: " <s csr. cr

View file

@ -29,14 +29,14 @@ b> // data
null // no libraries null // no libraries
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit <b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
dup ."StateInit: " <s csr. cr dup ."StateInit: " <s csr. cr
dup hash wc swap 2dup 2constant wallet_addr dup hashu wc swap 2dup 2constant wallet_addr
."new wallet address = " 2dup .addr cr ."new wallet address = " 2dup .addr cr
2dup file-base +subwallet +".addr" save-address-verbose 2dup file-base +subwallet +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr ."Non-bounceable address (for init): " 2dup 7 .Addr cr
."Bounceable address (for later access): " 6 .Addr cr ."Bounceable address (for later access): " 6 .Addr cr
<b subwallet-id 32 i, -1 32 i, 0 32 u, false 1 i, b> <b subwallet-id 32 i, -1 32 i, 0 32 u, false 1 i, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint rot dup hashu wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b> <b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
dup ."External message for initialization is " <s csr. cr dup ."External message for initialization is " <s csr. cr
2 boc+>B dup Bx. cr 2 boc+>B dup Bx. cr

View file

@ -41,7 +41,7 @@ def? $3 { @' $3 } { "new-pinger" } cond constant file-base
// no libraries // no libraries
<b b{00110} s, rot ref, swap ref, b> // create StateInit <b b{00110} s, rot ref, swap ref, b> // create StateInit
dup ."StateInit: " <s csr. cr dup ."StateInit: " <s csr. cr
dup hash wc swap 2dup 2constant pinger_addr dup hashu wc swap 2dup 2constant pinger_addr
."new pinger address = " 2dup .addr cr ."new pinger address = " 2dup .addr cr
2dup file-base +".addr" save-address-verbose 2dup file-base +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr ."Non-bounceable address (for init): " 2dup 7 .Addr cr

View file

@ -37,7 +37,7 @@ def? $2 { @' $2 } { "new-testgiver" } cond constant file-base
null // no libraries null // no libraries
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit <b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
dup ."StateInit: " <s csr. cr dup ."StateInit: " <s csr. cr
dup hash wc swap 2dup 2constant wallet_addr dup hashu wc swap 2dup 2constant wallet_addr
."new money giver address = " 2dup .addr cr ."new money giver address = " 2dup .addr cr
2dup file-base +".addr" save-address-verbose 2dup file-base +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr ."Non-bounceable address (for init): " 2dup 7 .Addr cr

View file

@ -47,14 +47,14 @@ b> // data
null // no libraries null // no libraries
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit <b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
dup ."StateInit: " <s csr. cr dup ."StateInit: " <s csr. cr
dup hash wc swap 2dup 2constant wallet_addr dup hashu wc swap 2dup 2constant wallet_addr
."new wallet address = " 2dup .addr cr ."new wallet address = " 2dup .addr cr
2dup file-base +".addr" save-address-verbose 2dup file-base +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr ."Non-bounceable address (for init): " 2dup 7 .Addr cr
."Bounceable address (for later access): " 6 .Addr cr ."Bounceable address (for later access): " 6 .Addr cr
<b 0 32 u, -1 32 i, b> <b 0 32 u, -1 32 i, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint rot dup hashu wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b> <b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
dup ."External message for initialization is " <s csr. cr dup ."External message for initialization is " <s csr. cr
2 boc+>B dup Bx. cr 2 boc+>B dup Bx. cr

View file

@ -47,14 +47,14 @@ null // no libraries
// Libs{ x{ABACABADABACABA} drop x{AAAA} s>c public_lib x{1234} x{5678} |_ s>c public_lib }Libs // Libs{ x{ABACABADABACABA} drop x{AAAA} s>c public_lib x{1234} x{5678} |_ s>c public_lib }Libs
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit <b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
dup ."StateInit: " <s csr. cr dup ."StateInit: " <s csr. cr
dup hash wc swap 2dup 2constant wallet_addr dup hashu wc swap 2dup 2constant wallet_addr
."new wallet address = " 2dup .addr cr ."new wallet address = " 2dup .addr cr
2dup file-base +".addr" save-address-verbose 2dup file-base +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr ."Non-bounceable address (for init): " 2dup 7 .Addr cr
."Bounceable address (for later access): " 6 .Addr cr ."Bounceable address (for later access): " 6 .Addr cr
<b 0 32 u, b> <b 0 32 u, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint rot dup hashu wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b> <b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
dup ."External message for initialization is " <s csr. cr dup ."External message for initialization is " <s csr. cr
2 boc+>B dup Bx. cr 2 boc+>B dup Bx. cr

View file

@ -6,7 +6,7 @@
."with private key loaded from file <filename-base>.pk, " ."with private key loaded from file <filename-base>.pk, "
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt ."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
} : usage } : usage
def? $# { @' $# dup 2 < swap 3 > or ' usage if } if $# dup 2 < swap 3 > or ' usage if
"config-master" constant file-base "config-master" constant file-base
0 constant seqno 0 constant seqno
@ -15,18 +15,16 @@ true constant bounce
"config-code.fif" constant config-source "config-code.fif" constant config-source
100 constant interval // valid for 100 seconds 100 constant interval // valid for 100 seconds
def? $2 { $1 =: file-base
@' $1 =: file-base $2 parse-int =: seqno
@' $2 parse-int =: seqno def? $3 { @' $3 } { "config-query" } cond constant savefile
} if
def? $5 { @' $5 } { "config-query" } cond constant savefile
file-base +".addr" load-address file-base +".addr" load-address
2dup 2constant config_addr 2dup 2constant config_addr
."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr ."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr
file-base +".pk" load-keypair nip constant config_pk file-base +".pk" load-keypair nip constant config_pk
."Loading new configuration smart contract code from file file " config-source type cr ."Loading new configuration smart contract code from file " config-source type cr
"Asm.fif" include "Asm.fif" include
config-source include config-source include
dup <s csr. cr dup <s csr. cr
@ -34,7 +32,7 @@ dup <s csr. cr
// create a message // create a message
<b x{4e436f64} s, seqno 32 u, now interval + 32 u, swap ref, b> <b x{4e436f64} s, seqno 32 u, now interval + 32 u, swap ref, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash config_pk ed25519_sign_uint dup hashu config_pk ed25519_sign_uint
<b b{1000100} s, config_addr addr, 0 Gram, b{00} s, <b b{1000100} s, config_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b> swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr dup ."resulting external message: " <s csr. cr

View file

@ -6,7 +6,7 @@
."with private key loaded from file <filename-base>.pk, " ."with private key loaded from file <filename-base>.pk, "
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt ."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
} : usage } : usage
def? $# { @' $# dup 4 < swap 5 > or ' usage if } if $# dup 4 < swap 5 > or ' usage if
"config-master" constant file-base "config-master" constant file-base
0 constant seqno 0 constant seqno
@ -15,12 +15,10 @@ true constant bounce
"new-value.boc" constant boc-filename "new-value.boc" constant boc-filename
100 constant interval // valid for 100 seconds 100 constant interval // valid for 100 seconds
def? $4 { $1 =: file-base
@' $1 =: file-base $2 parse-int =: seqno
@' $2 parse-int =: seqno $3 parse-int =: idx
@' $3 parse-int =: idx $4 =: boc-filename
@' $4 =: boc-filename
} if
def? $5 { @' $5 } { "config-query" } cond constant savefile def? $5 { @' $5 } { "config-query" } cond constant savefile
file-base +".addr" load-address file-base +".addr" load-address
@ -39,7 +37,7 @@ dup idx is-valid-config? not abort"not a valid value for chosen configuration pa
// create a message // create a message
<b x{43665021} s, seqno 32 u, now interval + 32 u, idx 32 i, swap ref, b> <b x{43665021} s, seqno 32 u, now interval + 32 u, idx 32 i, swap ref, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash config_pk ed25519_sign_uint dup hashu config_pk ed25519_sign_uint
<b b{1000100} s, config_addr addr, 0 Gram, b{00} s, <b b{1000100} s, config_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b> swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr dup ."resulting external message: " <s csr. cr

View file

@ -6,7 +6,7 @@
."with private key loaded from file <filename-base>.pk, " ."with private key loaded from file <filename-base>.pk, "
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt ."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
} : usage } : usage
def? $# { @' $# dup 2 < swap 3 > or ' usage if } if $# dup 2 < swap 3 > or ' usage if
"config-master" constant file-base "config-master" constant file-base
0 constant seqno 0 constant seqno
@ -15,18 +15,16 @@ true constant bounce
"elector-code.fif" constant elector-source "elector-code.fif" constant elector-source
100 constant interval // valid for 100 seconds 100 constant interval // valid for 100 seconds
def? $2 { $1 =: file-base
@' $1 =: file-base $2 parse-int =: seqno
@' $2 parse-int =: seqno def? $3 { @' $3 } { "config-query" } cond constant savefile
} if
def? $5 { @' $5 } { "config-query" } cond constant savefile
file-base +".addr" load-address file-base +".addr" load-address
2dup 2constant config_addr 2dup 2constant config_addr
."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr ."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr
file-base +".pk" load-keypair nip constant config_pk file-base +".pk" load-keypair nip constant config_pk
."Loading new elector smart contract code from file file " elector-source type cr ."Loading new elector smart contract code from file " elector-source type cr
"Asm.fif" include "Asm.fif" include
elector-source include elector-source include
dup <s csr. cr dup <s csr. cr
@ -34,7 +32,7 @@ dup <s csr. cr
// create a message // create a message
<b x{4e43ef05} s, seqno 32 u, now interval + 32 u, swap ref, b> <b x{4e43ef05} s, seqno 32 u, now interval + 32 u, swap ref, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash config_pk ed25519_sign_uint dup hashu config_pk ed25519_sign_uint
<b b{1000100} s, config_addr addr, 0 Gram, b{00} s, <b b{1000100} s, config_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b> swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr dup ."resulting external message: " <s csr. cr

View file

@ -38,7 +38,7 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
b> b>
<b seqno 32 u, now timeout + 32 u, send-mode 8 u, swap ref, b> <b seqno 32 u, now timeout + 32 u, send-mode 8 u, swap ref, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint dup hashu wallet_pk ed25519_sign_uint
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s, <b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b> swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr dup ."resulting external message: " <s csr. cr

View file

@ -37,7 +37,7 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
b> b>
<b seqno 32 u, send-mode 8 u, swap ref, b> <b seqno 32 u, send-mode 8 u, swap ref, b>
dup ."signing message: " <s csr. cr dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint dup hashu wallet_pk ed25519_sign_uint
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s, <b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b> swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr dup ."resulting external message: " <s csr. cr

View file

@ -267,16 +267,18 @@ MerkleProofBuilder::MerkleProofBuilder(Ref<Cell> root)
usage_root = UsageCell::create(orig_root, usage_tree->root_ptr()); usage_root = UsageCell::create(orig_root, usage_tree->root_ptr());
} }
void MerkleProofBuilder::reset(Ref<Cell> root) { Ref<Cell> MerkleProofBuilder::init(Ref<Cell> root) {
usage_tree = std::make_shared<CellUsageTree>(); usage_tree = std::make_shared<CellUsageTree>();
orig_root = std::move(root); orig_root = std::move(root);
usage_root = UsageCell::create(orig_root, usage_tree->root_ptr()); usage_root = UsageCell::create(orig_root, usage_tree->root_ptr());
return usage_root;
} }
void MerkleProofBuilder::clear() { bool MerkleProofBuilder::clear() {
usage_tree.reset(); usage_tree.reset();
orig_root.clear(); orig_root.clear();
usage_root.clear(); usage_root.clear();
return true;
} }
Ref<Cell> MerkleProofBuilder::extract_proof() const { Ref<Cell> MerkleProofBuilder::extract_proof() const {

View file

@ -51,9 +51,10 @@ class MerkleProofBuilder {
Ref<vm::Cell> orig_root, usage_root; Ref<vm::Cell> orig_root, usage_root;
public: public:
MerkleProofBuilder() = default;
MerkleProofBuilder(Ref<Cell> root); MerkleProofBuilder(Ref<Cell> root);
void reset(Ref<Cell> root); Ref<Cell> init(Ref<Cell> root);
void clear(); bool clear();
Ref<Cell> root() const { Ref<Cell> root() const {
return usage_root; return usage_root;
} }

View file

@ -107,7 +107,7 @@ Replace it with the following:
} }
], ],
`control.0.id` is set to the base64 identifier of the server's public key, and `control.0.allowed.0.id` is the base64 identifier of the client's public key. <CONSOLE-PORT> is the UDP port the server will listen to for console commands. `control.0.id` is set to the base64 identifier of the server's public key, and `control.0.allowed.0.id` is the base64 identifier of the client's public key. <CONSOLE-PORT> is the TCP port the server will listen to for console commands.
7. Running the Full Node 7. Running the Full Node
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -1233,8 +1233,9 @@ first outputs ``{\tt x\{F55AA\}}'', and then throws an exception with the messag
\mysubsection{Cell hash operations}\label{p:hash.ops} \mysubsection{Cell hash operations}\label{p:hash.ops}
There are few words that operate on {\em Cell\/}s directly. The most important of them computes the {\em ($\Sha$-based) representation hash\/} of a given cell (cf.~\cite[3.1]{TVM}), which can be roughly described as the $\Sha$ hash of the cell's data bits concatenated with recursively computed hashes of the cells referred to by this cell: There are few words that operate on {\em Cell\/}s directly. The most important of them computes the {\em ($\Sha$-based) representation hash\/} of a given cell (cf.~\cite[3.1]{TVM}), which can be roughly described as the $\Sha$ hash of the cell's data bits concatenated with recursively computed hashes of the cells referred to by this cell:
\begin{itemize} \begin{itemize}
\item {\tt hash} ($c$ -- $B$), computes the $\Sha$-based representation hash of {\em Cell\/}~$c$ (cf.~\cite[3.1]{TVM}), which unambiguously defines $c$ and all its descendants (provided there are no collisions for $\Sha$). The result is returned as a {\em Bytes\/} value consisting of exactly 32 bytes. \item {\tt hashB} ($c$ -- $B$), computes the $\Sha$-based representation hash of {\em Cell\/}~$c$ (cf.~\cite[3.1]{TVM}), which unambiguously defines $c$ and all its descendants (provided there are no collisions for $\Sha$). The result is returned as a {\em Bytes\/} value consisting of exactly 32 bytes.
\item {\tt shash} ($s$ -- $B$), computes the $\Sha$-based representation hash of a {\em Slice\/} by first transforming it into a cell. Equivalent to {\tt s>c hash}. \item {\tt hashu} ($c$ -- $x$), computes the $\Sha$-based representation hash of $c$ as above, but returns the result as a big-endian unsigned 256-bit {\em Integer}.
\item {\tt shash} ($s$ -- $B$), computes the $\Sha$-based representation hash of a {\em Slice\/} by first transforming it into a cell. Equivalent to {\tt s>c hashB}.
\end{itemize} \end{itemize}
\mysubsection{Bag-of-cells operations}\label{p:boc.ops} \mysubsection{Bag-of-cells operations}\label{p:boc.ops}
@ -1286,7 +1287,8 @@ prints ``{\tt 17239 -1000000001 ok}''.
Additionally, there are several words for directly packing (serializing) data into {\em Bytes\/} values, and unpacking (deserializing) them afterwards. They can be combined with {\tt B>file} and {\tt file>B} to save data directly into binary files, and load them afterwards. Additionally, there are several words for directly packing (serializing) data into {\em Bytes\/} values, and unpacking (deserializing) them afterwards. They can be combined with {\tt B>file} and {\tt file>B} to save data directly into binary files, and load them afterwards.
\begin{itemize} \begin{itemize}
\item {\tt Blen} ($B$ -- $x$), returns the length of a {\em Bytes\/} value~$B$ in bytes. \item {\tt Blen} ($B$ -- $x$), returns the length of a {\em Bytes\/} value~$B$ in bytes.
\item {\tt Bhash} ($B$ -- $B'$), computes the $\Sha$ hash of a {\em Bytes\/} value. The hash is returned as a 32-byte {\em Bytes\/} value. \item {\tt BhashB} ($B$ -- $B'$), computes the $\Sha$ hash of a {\em Bytes\/} value. The hash is returned as a 32-byte {\em Bytes\/} value.
\item {\tt Bhashu} ($B$ -- $x$), computes the $\Sha$ hash of a {\em Bytes\/} value and returns the hash as an unsigned 256-bit big-endian integer.
\item {\tt B=} ($B$ $B'$ -- $?$), checks whether two {\em Bytes\/} sequences are equal. \item {\tt B=} ($B$ $B'$ -- $?$), checks whether two {\em Bytes\/} sequences are equal.
\item {\tt Bcmp} ($B$ $B'$ -- $x$), lexicographically compares two {\em Bytes\/} sequences, and returns $-1$, $0$, or $1$, depending on the comparison result. \item {\tt Bcmp} ($B$ $B'$ -- $x$), lexicographically compares two {\em Bytes\/} sequences, and returns $-1$, $0$, or $1$, depending on the comparison result.
\item {\tt B>i@} ($B$ $x$ -- $y$), deserializes the first $x/8$ bytes of a {\em Bytes} value~$B$ as a signed big-endian $x$-bit {\em Integer}~$y$. \item {\tt B>i@} ($B$ $x$ -- $y$), deserializes the first $x/8$ bytes of a {\em Bytes} value~$B$ as a signed big-endian $x$-bit {\em Integer}~$y$.
@ -1970,7 +1972,9 @@ For example, the active prefix word {\tt B\{}, used for defining {\em Bytes\/} l
\item {\tt B@?} ($s$ $x$ -- $B$ $-1$ or $0$), similar to {\tt B@}, but uses a flag to indicate failure instead of throwing an exception, cf.~\ptref{p:slice.ops}. \item {\tt B@?} ($s$ $x$ -- $B$ $-1$ or $0$), similar to {\tt B@}, but uses a flag to indicate failure instead of throwing an exception, cf.~\ptref{p:slice.ops}.
\item {\tt B@?+} ($s$ $x$ -- $B$ $s'$ $-1$ or $s$ $0$), similar to {\tt B@+}, but uses a flag to indicate failure instead of throwing an exception, cf.~\ptref{p:slice.ops}. \item {\tt B@?+} ($s$ $x$ -- $B$ $s'$ $-1$ or $s$ $0$), similar to {\tt B@+}, but uses a flag to indicate failure instead of throwing an exception, cf.~\ptref{p:slice.ops}.
\item {\tt Bcmp} ($B$ $B'$ -- $x$), lexicographically compares two {\em Bytes\/} sequences, and returns $-1$, $0$, or $1$, depending on the comparison result, cf.~\ptref{p:bytes.ops}. \item {\tt Bcmp} ($B$ $B'$ -- $x$), lexicographically compares two {\em Bytes\/} sequences, and returns $-1$, $0$, or $1$, depending on the comparison result, cf.~\ptref{p:bytes.ops}.
\item {\tt Bhash} ($B$ -- $B'$), computes the $\Sha$ hash of a {\em Bytes\/} value, cf.~\ptref{p:bytes.ops}. The hash is returned as a 32-byte {\em Bytes\/} value. \item {\tt Bhash} ($B$ -- $x$), deprecated version of {\tt Bhashu}. Use {\tt Bhashu} or {\tt BhashB} instead.
\item {\tt BhashB} ($B$ -- $B'$), computes the $\Sha$ hash of a {\em Bytes\/} value, cf.~\ptref{p:bytes.ops}. The hash is returned as a 32-byte {\em Bytes\/} value.
\item {\tt Bhashu} ($B$ -- $x$), computes the $\Sha$ hash of a {\em Bytes\/} value, cf.~\ptref{p:bytes.ops}. The hash is returned as a big-endian unsigned 256-bit {\em Integer\/} value.
\item {\tt Blen} ($B$ -- $x$), returns the length of a {\em Bytes\/} value~$B$ in bytes, cf.~\ptref{p:bytes.ops}. \item {\tt Blen} ($B$ -- $x$), returns the length of a {\em Bytes\/} value~$B$ in bytes, cf.~\ptref{p:bytes.ops}.
\item {\tt Bx.} ($B$ -- ), prints the hexadecimal representation of a {\em Bytes\/} value, cf.~\ptref{p:bytes.ops}. Each byte is represented by exactly two uppercase hexadecimal digits. \item {\tt Bx.} ($B$ -- ), prints the hexadecimal representation of a {\em Bytes\/} value, cf.~\ptref{p:bytes.ops}. Each byte is represented by exactly two uppercase hexadecimal digits.
\item {\tt \underline{B\{}$\langle{\textit{hex-digits}}\rangle$\}} ( -- $B$), pushes a {\em Bytes\/} literal containing data represented by an even number of hexadecimal digits, cf.~\ptref{p:bytes.ops}. \item {\tt \underline{B\{}$\langle{\textit{hex-digits}}\rangle$\}} ( -- $B$), pushes a {\em Bytes\/} literal containing data represented by an even number of hexadecimal digits, cf.~\ptref{p:bytes.ops}.
@ -2062,7 +2066,9 @@ Typical values of $x$ are $x=0$ or $x=2$ for very small bags of cells (e.g., TON
\item {\tt gasrunvmcode} (\dots $s$ $z$ -- \dots $x$ $z'$), a gas-aware version of {\tt runvmcode}, cf.~\ptref{p:tvm.ops}: invokes a new instance of TVM with the current continuation {\tt cc} initialized from {\em Slice\/} $s$ and with the gas limit set to $z$, thus executing code~$s$ in TVM. The original Fift stack (without $s$) is passed in its entirety as the initial stack of the new TVM instance. When TVM terminates, its resulting stack is used as the new Fift stack, with the exit code $x$ and the actually consumed gas $z'$ pushed at its top. If $x$ is non-zero, indicating that TVM has been terminated by an unhandled exception, the next stack entry from the top contains the parameter of this exception, and $x$ is the exception code. All other entries are removed from the stack in this case. \item {\tt gasrunvmcode} (\dots $s$ $z$ -- \dots $x$ $z'$), a gas-aware version of {\tt runvmcode}, cf.~\ptref{p:tvm.ops}: invokes a new instance of TVM with the current continuation {\tt cc} initialized from {\em Slice\/} $s$ and with the gas limit set to $z$, thus executing code~$s$ in TVM. The original Fift stack (without $s$) is passed in its entirety as the initial stack of the new TVM instance. When TVM terminates, its resulting stack is used as the new Fift stack, with the exit code $x$ and the actually consumed gas $z'$ pushed at its top. If $x$ is non-zero, indicating that TVM has been terminated by an unhandled exception, the next stack entry from the top contains the parameter of this exception, and $x$ is the exception code. All other entries are removed from the stack in this case.
\item {\tt gasrunvmdict} (\dots $s$ $z$ -- \dots $x$ $z'$), a gas-aware version of {\tt runvmdict}, cf.~\ptref{p:tvm.ops}: invokes a new instance of TVM with the current continuation {\tt cc} initialized from {\em Slice\/} $s$ and sets the gas limit to $z$ similarly to {\tt gasrunvmcode}, but also initializes the special register {\tt c3} with the same value, and pushes a zero into the initial TVM stack before the TVM execution begins. The actually consumed gas is returned as an {\em Integer\/} $z'$. In a typical application {\em Slice\/}~$s$ consists of a subroutine selection code that uses the top-of-stack {\em Integer\/} to select the subroutine to be executed, thus enabling the definition and execution of several mutually-recursive subroutines (cf.~\cite[4.6]{TVM} and~\ptref{p:asm.prog}). The selector equal to zero corresponds to the {\tt main()} subroutine in a large TVM program. \item {\tt gasrunvmdict} (\dots $s$ $z$ -- \dots $x$ $z'$), a gas-aware version of {\tt runvmdict}, cf.~\ptref{p:tvm.ops}: invokes a new instance of TVM with the current continuation {\tt cc} initialized from {\em Slice\/} $s$ and sets the gas limit to $z$ similarly to {\tt gasrunvmcode}, but also initializes the special register {\tt c3} with the same value, and pushes a zero into the initial TVM stack before the TVM execution begins. The actually consumed gas is returned as an {\em Integer\/} $z'$. In a typical application {\em Slice\/}~$s$ consists of a subroutine selection code that uses the top-of-stack {\em Integer\/} to select the subroutine to be executed, thus enabling the definition and execution of several mutually-recursive subroutines (cf.~\cite[4.6]{TVM} and~\ptref{p:asm.prog}). The selector equal to zero corresponds to the {\tt main()} subroutine in a large TVM program.
\item {\tt halt} ($x$ -- ), quits to the operating system similarly to {\tt bye}, but uses {\em Integer\/} $x$ as the exit code, cf.~\ptref{p:exit.fift}. \item {\tt halt} ($x$ -- ), quits to the operating system similarly to {\tt bye}, but uses {\em Integer\/} $x$ as the exit code, cf.~\ptref{p:exit.fift}.
\item {\tt hash} ($c$ -- $B$), computes the $\Sha$-based representation hash of {\em Cell\/}~$c$ (cf.~\cite[3.1]{TVM}), which unambiguously defines $c$ and all its descendants (provided there are no collisions for $\Sha$), cf.~\ptref{p:hash.ops}. The result is returned as a {\em Bytes\/} value consisting of exactly 32 bytes. \item {\tt hash} ($c$ -- $x$), a deprecated version of {\tt hashu}. Use {\tt hashu} or {\tt hashB} instead.
\item {\tt hashB} ($c$ -- $B$), computes the $\Sha$-based representation hash of {\em Cell\/}~$c$ (cf.~\cite[3.1]{TVM}), which unambiguously defines $c$ and all its descendants (provided there are no collisions for $\Sha$), cf.~\ptref{p:hash.ops}. The result is returned as a {\em Bytes\/} value consisting of exactly 32 bytes.
\item {\tt hashu} ($c$ -- $x$), computes the $\Sha$-based representation hash of {\em Cell\/}~$c$ similarly to {\tt hashB}, but returns the result as a big-endian unsigned 256-bit {\em Integer}.
\item {\tt hold} ($S$ $x$ -- $S'$), appends to {\em String\/}~$S$ one UTF-8 encoded character with Unicode codepoint~$x$. Equivalent to {\tt chr \$+}. \item {\tt hold} ($S$ $x$ -- $S'$), appends to {\em String\/}~$S$ one UTF-8 encoded character with Unicode codepoint~$x$. Equivalent to {\tt chr \$+}.
\item {\tt hole} ( -- $p$), creates a new {\em Box\/}~$p$ that does not hold any value, cf.~\ptref{p:variables}. Equivalent to {\tt null box}. \item {\tt hole} ( -- $p$), creates a new {\em Box\/}~$p$ that does not hold any value, cf.~\ptref{p:variables}. Equivalent to {\tt null box}.
\item {\tt i,} ($b$ $x$ $y$ -- $b'$), appends the big-endian binary representation of a signed $y$-bit integer~$x$ to {\em Builder\/}~$b$, where $0\leq y\leq 257$, cf.~\ptref{p:builder.ops}. If there is not enough room in $b$ (i.e., if $b$ already contains more than $1023-y$ data bits), or if {\em Integer\/}~$x$ does not fit into $y$ bits, an exception is thrown. \item {\tt i,} ($b$ $x$ $y$ -- $b'$), appends the big-endian binary representation of a signed $y$-bit integer~$x$ to {\em Builder\/}~$b$, where $0\leq y\leq 257$, cf.~\ptref{p:builder.ops}. If there is not enough room in $b$ (i.e., if $b$ already contains more than $1023-y$ data bits), or if {\em Integer\/}~$x$ does not fit into $y$ bits, an exception is thrown.
@ -2120,7 +2126,7 @@ Typical values of $x$ are $x=0$ or $x=2$ for very small bags of cells (e.g., TON
\item {\tt sbits} ($s$ -- $x$), returns the number of data bits $x$ remaining in {\em Slice}~$s$, cf.~\ptref{p:slice.ops}. \item {\tt sbits} ($s$ -- $x$), returns the number of data bits $x$ remaining in {\em Slice}~$s$, cf.~\ptref{p:slice.ops}.
\item {\tt second} ($t$ -- $x$), returns the second component of a {\em Tuple}, cf.~\ptref{p:tuples}. Equivalent to {\tt 1 []}. \item {\tt second} ($t$ -- $x$), returns the second component of a {\em Tuple}, cf.~\ptref{p:tuples}. Equivalent to {\tt 1 []}.
\item {\tt sgn} ($x$ -- $y$), computes the sign of an {\em Integer\/} $x$ (i.e., pushes $1$ if $x>0$, $-1$ if $x<0$, and $0$ if $x=0$), cf.~\ptref{p:int.comp}. Equivalent to {\tt 0 cmp}. \item {\tt sgn} ($x$ -- $y$), computes the sign of an {\em Integer\/} $x$ (i.e., pushes $1$ if $x>0$, $-1$ if $x<0$, and $0$ if $x=0$), cf.~\ptref{p:int.comp}. Equivalent to {\tt 0 cmp}.
\item {\tt shash} ($s$ -- $B$), computes the $\Sha$-based representation hash of a {\em Slice\/} by first transforming it into a cell, cf.~\ptref{p:hash.ops}. Equivalent to {\tt s>c hash}. \item {\tt shash} ($s$ -- $B$), computes the $\Sha$-based representation hash of a {\em Slice\/} by first transforming it into a cell, cf.~\ptref{p:hash.ops}. Equivalent to {\tt s>c hashB}.
\item {\tt sign} ($S$ $x$ -- $S'$), appends a minus sign ``{\tt -}'' to {\em String\/}~$S$ if {\em Integer\/}~$x$ is negative. Otherwise leaves $S$ intact. \item {\tt sign} ($S$ $x$ -- $S'$), appends a minus sign ``{\tt -}'' to {\em String\/}~$S$ if {\em Integer\/}~$x$ is negative. Otherwise leaves $S$ intact.
\item {\tt single} ($x$ -- $t$), creates new singleton $t=(x)$, i.e., a one-element {\em Tuple}. Equivalent to {\tt 1 tuple}. \item {\tt single} ($x$ -- $t$), creates new singleton $t=(x)$, i.e., a one-element {\em Tuple}. Equivalent to {\tt 1 tuple}.
\item {\tt skipspc} ( -- ), skips blank characters from the current input line until a non-blank or an end-of-line character is found. \item {\tt skipspc} ( -- ), skips blank characters from the current input line until a non-blank or an end-of-line character is found.

View file

@ -914,8 +914,10 @@ bool TestNode::do_parse_line() {
return parse_block_id_ext(blkid) && parse_account_addr(workchain, addr) && parse_lt(lt) && seekeoln() && return parse_block_id_ext(blkid) && parse_account_addr(workchain, addr) && parse_lt(lt) && seekeoln() &&
get_one_transaction(blkid, workchain, addr, lt, true); get_one_transaction(blkid, workchain, addr, lt, true);
} else if (word == "lasttrans" || word == "lasttransdump") { } else if (word == "lasttrans" || word == "lasttransdump") {
return parse_account_addr(workchain, addr) && parse_lt(lt) && parse_hash(hash) && seekeoln() && count = 10;
get_last_transactions(workchain, addr, lt, hash, 10, word == "lasttransdump"); return parse_account_addr(workchain, addr) && parse_lt(lt) && parse_hash(hash) &&
(seekeoln() || parse_uint32(count)) && seekeoln() &&
get_last_transactions(workchain, addr, lt, hash, count, word == "lasttransdump");
} else if (word == "listblocktrans" || word == "listblocktransrev") { } else if (word == "listblocktrans" || word == "listblocktransrev") {
lt = 0; lt = 0;
int mode = (word == "listblocktrans" ? 7 : 0x47); int mode = (word == "listblocktrans" ? 7 : 0x47);

View file

@ -353,6 +353,45 @@ FileDb::DbEntry::DbEntry(tl_object_ptr<ton_api::db_filedb_value> entry)
, file_hash(entry->file_hash_) { , file_hash(entry->file_hash_) {
} }
void FileDb::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) {
std::vector<std::pair<std::string, std::string>> rocksdb_stats;
auto stats = kv_->stats();
if (stats.size() == 0) {
promise.set_value(std::move(rocksdb_stats));
return;
}
size_t pos = 0;
while (pos < stats.size()) {
while (pos < stats.size() &&
(stats[pos] == ' ' || stats[pos] == '\n' || stats[pos] == '\r' || stats[pos] == '\t')) {
pos++;
}
auto p = pos;
if (pos == stats.size()) {
break;
}
while (stats[pos] != '\n' && stats[pos] != '\r' && stats[pos] != ' ' && stats[pos] != '\t' && pos < stats.size()) {
pos++;
}
auto name = stats.substr(p, pos - p);
if (stats[pos] == '\n' || pos == stats.size()) {
rocksdb_stats.emplace_back(name, "");
continue;
}
while (pos < stats.size() &&
(stats[pos] == ' ' || stats[pos] == '\n' || stats[pos] == '\r' || stats[pos] == '\t')) {
pos++;
}
p = pos;
while (stats[pos] != '\n' && stats[pos] != '\r' && pos < stats.size()) {
pos++;
}
auto value = stats.substr(p, pos - p);
rocksdb_stats.emplace_back(name, value);
}
promise.set_value(std::move(rocksdb_stats));
}
} // namespace validator } // namespace validator
} // namespace ton } // namespace ton

View file

@ -147,6 +147,8 @@ class FileDb : public td::actor::Actor {
void load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise); void load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise);
void check_file(RefId ref_id, td::Promise<bool> promise); void check_file(RefId ref_id, td::Promise<bool> promise);
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise);
void start_up() override; void start_up() override;
void alarm() override; void alarm() override;

View file

@ -24,6 +24,7 @@
#include "ton/ton-tl.hpp" #include "ton/ton-tl.hpp"
#include "td/utils/overloaded.h" #include "td/utils/overloaded.h"
#include "common/checksum.h" #include "common/checksum.h"
#include "validator/stats-merger.h"
namespace ton { namespace ton {
@ -473,6 +474,13 @@ void RootDb::allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> p
})); }));
} }
void RootDb::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) {
auto merger = StatsMerger::create(std::move(promise));
td::actor::send_closure(file_db_, &FileDb::prepare_stats, merger.make_promise("filedb."));
td::actor::send_closure(archive_db_, &FileDb::prepare_stats, merger.make_promise("archivedb."));
}
} // namespace validator } // namespace validator
} // namespace ton } // namespace ton

View file

@ -110,6 +110,8 @@ class RootDb : public Db {
void allow_block_gc(BlockIdExt block_id, td::Promise<bool> promise); void allow_block_gc(BlockIdExt block_id, td::Promise<bool> promise);
void allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> promise); void allow_gc(FileDb::RefId ref_id, bool is_archive, td::Promise<bool> promise);
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
private: private:
td::actor::ActorId<ValidatorManager> validator_manager_; td::actor::ActorId<ValidatorManager> validator_manager_;

View file

@ -780,11 +780,10 @@ bool LiteQuery::make_state_root_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_
CHECK(block_root.not_null() && state_root.not_null()); CHECK(block_root.not_null() && state_root.not_null());
RootHash rhash{block_root->get_hash().bits()}; RootHash rhash{block_root->get_hash().bits()};
CHECK(rhash == blkid.root_hash); CHECK(rhash == blkid.root_hash);
auto usage_tree = std::make_shared<vm::CellUsageTree>(); vm::MerkleProofBuilder pb{std::move(block_root)};
auto usage_cell = vm::UsageCell::create(block_root, usage_tree->root_ptr());
block::gen::Block::Record blk; block::gen::Block::Record blk;
block::gen::BlockInfo::Record info; block::gen::BlockInfo::Record info;
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(blk.info, info))) { if (!(tlb::unpack_cell(pb.root(), blk) && tlb::unpack_cell(blk.info, info))) {
return fatal_error("cannot unpack block header"); return fatal_error("cannot unpack block header");
} }
vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update}; vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update};
@ -797,8 +796,7 @@ bool LiteQuery::make_state_root_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_
if (upd_hash.compare(state_hash, 256)) { if (upd_hash.compare(state_hash, 256)) {
return fatal_error("cannot construct Merkle proof for given masterchain state because of hash mismatch"); return fatal_error("cannot construct Merkle proof for given masterchain state because of hash mismatch");
} }
proof = vm::MerkleProof::generate(block_root, usage_tree.get()); if (!pb.extract_proof_to(proof)) {
if (proof.is_null()) {
return fatal_error("unknown error creating Merkle proof"); return fatal_error("unknown error creating Merkle proof");
} }
return true; return true;
@ -806,20 +804,17 @@ bool LiteQuery::make_state_root_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_
bool LiteQuery::make_shard_info_proof(Ref<vm::Cell>& proof, vm::CellSlice& cs, ShardIdFull shard, bool LiteQuery::make_shard_info_proof(Ref<vm::Cell>& proof, vm::CellSlice& cs, ShardIdFull shard,
ShardIdFull& true_shard, Ref<vm::Cell>& leaf, bool& found, bool exact) { ShardIdFull& true_shard, Ref<vm::Cell>& leaf, bool& found, bool exact) {
auto state_root = mc_state_->root_cell(); vm::MerkleProofBuilder pb{mc_state_->root_cell()};
auto usage_tree = std::make_shared<vm::CellUsageTree>();
auto usage_cell = vm::UsageCell::create(state_root, usage_tree->root_ptr());
block::gen::ShardStateUnsplit::Record sstate; block::gen::ShardStateUnsplit::Record sstate;
if (!(tlb::unpack_cell(usage_cell, sstate))) { if (!(tlb::unpack_cell(pb.root(), sstate))) {
return fatal_error("cannot unpack state header"); return fatal_error("cannot unpack state header");
} }
auto shards_dict = block::ShardConfig::extract_shard_hashes_dict(usage_cell); auto shards_dict = block::ShardConfig::extract_shard_hashes_dict(pb.root());
if (!shards_dict) { if (!shards_dict) {
return fatal_error("cannot extract ShardHashes from last mc state"); return fatal_error("cannot extract ShardHashes from last mc state");
} }
found = block::ShardConfig::get_shard_hash_raw_from(*shards_dict, cs, shard, true_shard, exact, &leaf); found = block::ShardConfig::get_shard_hash_raw_from(*shards_dict, cs, shard, true_shard, exact, &leaf);
proof = vm::MerkleProof::generate(state_root, usage_tree.get()); if (!pb.extract_proof_to(proof)) {
if (proof.is_null()) {
return fatal_error("unknown error creating Merkle proof"); return fatal_error("unknown error creating Merkle proof");
} }
return true; return true;
@ -921,11 +916,9 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
if (!make_state_root_proof(proof1)) { if (!make_state_root_proof(proof1)) {
return; return;
} }
auto state_root = state_->root_cell(); vm::MerkleProofBuilder pb{state_->root_cell()};
auto usage_tree = std::make_shared<vm::CellUsageTree>();
auto usage_cell = vm::UsageCell::create(state_root, usage_tree->root_ptr());
block::gen::ShardStateUnsplit::Record sstate; block::gen::ShardStateUnsplit::Record sstate;
if (!(tlb::unpack_cell(usage_cell, sstate))) { if (!tlb::unpack_cell(pb.root(), sstate)) {
fatal_error("cannot unpack state header"); fatal_error("cannot unpack state header");
return; return;
} }
@ -935,10 +928,7 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
if (acc_csr.not_null()) { if (acc_csr.not_null()) {
acc_root = acc_csr->prefetch_ref(); acc_root = acc_csr->prefetch_ref();
} }
auto proof2 = vm::MerkleProof::generate(state_root, usage_tree.get()); auto proof = vm::std_boc_serialize_multi({std::move(proof1), pb.extract_proof()});
usage_tree.reset();
usage_cell.clear();
auto proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
if (proof.is_error()) { if (proof.is_error()) {
fatal_error(proof.move_as_error()); fatal_error(proof.move_as_error());
return; return;
@ -962,23 +952,18 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
void LiteQuery::continue_getOneTransaction() { void LiteQuery::continue_getOneTransaction() {
LOG(INFO) << "completing getOneTransaction() query"; LOG(INFO) << "completing getOneTransaction() query";
CHECK(block_.not_null()); CHECK(block_.not_null());
auto block_root = block_->root_cell(); vm::MerkleProofBuilder pb{block_->root_cell()};
auto usage_tree = std::make_shared<vm::CellUsageTree>(); auto trans_res = block::get_block_transaction(pb.root(), acc_workchain_, acc_addr_, trans_lt_);
auto usage_cell = vm::UsageCell::create(block_root, usage_tree->root_ptr());
auto trans_res = block::get_block_transaction(block_root, acc_workchain_, acc_addr_, trans_lt_);
if (trans_res.is_error()) { if (trans_res.is_error()) {
fatal_error(trans_res.move_as_error()); fatal_error(trans_res.move_as_error());
return; return;
} }
auto trans_root = trans_res.move_as_ok(); auto trans_root = trans_res.move_as_ok();
auto proof = vm::MerkleProof::generate(block_root, usage_tree.get()); auto proof_boc = pb.extract_proof_boc();
auto proof_boc = vm::std_boc_serialize(std::move(proof));
if (proof_boc.is_error()) { if (proof_boc.is_error()) {
fatal_error(proof_boc.move_as_error()); fatal_error(proof_boc.move_as_error());
return; return;
} }
usage_tree.reset();
usage_cell.clear();
td::BufferSlice data; td::BufferSlice data;
if (trans_root.not_null()) { if (trans_root.not_null()) {
auto res = vm::std_boc_serialize(std::move(trans_root)); auto res = vm::std_boc_serialize(std::move(trans_root));
@ -999,10 +984,13 @@ void LiteQuery::perform_getTransactions(WorkchainId workchain, StdSmcAddress add
unsigned count) { unsigned count) {
LOG(INFO) << "started a getTransactions(" << workchain << ", " << addr.to_hex() << ", " << lt << ", " << hash.to_hex() LOG(INFO) << "started a getTransactions(" << workchain << ", " << addr.to_hex() << ", " << lt << ", " << hash.to_hex()
<< ", " << count << ") liteserver query"; << ", " << count << ") liteserver query";
if (count > 10) { count = std::min(count, (unsigned)max_transaction_count);
/*
if (count > max_transaction_count) {
fatal_error("cannot fetch more than 10 preceding transactions at one time"); fatal_error("cannot fetch more than 10 preceding transactions at one time");
return; return;
} }
*/
if (workchain == ton::workchainInvalid) { if (workchain == ton::workchainInvalid) {
fatal_error("invalid workchain specified"); fatal_error("invalid workchain specified");
return; return;
@ -1355,14 +1343,11 @@ void LiteQuery::finish_listBlockTransactions(int mode, int req_count) {
CHECK(block_root.not_null()); CHECK(block_root.not_null());
RootHash rhash{block_root->get_hash().bits()}; RootHash rhash{block_root->get_hash().bits()};
CHECK(rhash == base_blk_id_.root_hash); CHECK(rhash == base_blk_id_.root_hash);
Ref<vm::Cell> usage_cell; vm::MerkleProofBuilder pb;
std::shared_ptr<vm::CellUsageTree> usage_tree; auto virt_root = block_root;
if (mode & 32) { if (mode & 32) {
// proof requested // proof requested
usage_tree = std::make_shared<vm::CellUsageTree>(); virt_root = pb.init(std::move(virt_root));
usage_cell = vm::UsageCell::create(block_root, usage_tree->root_ptr());
} else {
usage_cell = block_root;
} }
if ((mode & 192) == 64) { // reverse order, no starting point if ((mode & 192) == 64) { // reverse order, no starting point
acc_addr_.set_ones(); acc_addr_.set_ones();
@ -1374,7 +1359,7 @@ void LiteQuery::finish_listBlockTransactions(int mode, int req_count) {
try { try {
block::gen::Block::Record blk; block::gen::Block::Record blk;
block::gen::BlockExtra::Record extra; block::gen::BlockExtra::Record extra;
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(std::move(blk.extra), extra))) { if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(std::move(blk.extra), extra))) {
fatal_error("cannot find account transaction data in block "s + base_blk_id_.to_str()); fatal_error("cannot find account transaction data in block "s + base_blk_id_.to_str());
return; return;
} }
@ -1433,8 +1418,7 @@ void LiteQuery::finish_listBlockTransactions(int mode, int req_count) {
td::BufferSlice proof_data; td::BufferSlice proof_data;
if (mode & 32) { if (mode & 32) {
// create proof // create proof
auto proof = vm::MerkleProof::generate(block_root, usage_tree.get()); auto proof_boc = pb.extract_proof_boc();
auto proof_boc = vm::std_boc_serialize(std::move(proof));
if (proof_boc.is_error()) { if (proof_boc.is_error()) {
fatal_error(proof_boc.move_as_error()); fatal_error(proof_boc.move_as_error());
return; return;

View file

@ -57,7 +57,10 @@ class LiteQuery : public td::actor::Actor {
std::unique_ptr<block::BlockProofChain> chain_; std::unique_ptr<block::BlockProofChain> chain_;
public: public:
enum { default_timeout_msec = 4500 }; // 4.5 seconds enum {
default_timeout_msec = 4500, // 4.5 seconds
max_transaction_count = 16 // fetch at most 16 transactions in one query
};
enum { enum {
ls_version = 0x101, ls_version = 0x101,
ls_capabilities = 3 ls_capabilities = 3

View file

@ -93,6 +93,8 @@ class Db : public td::actor::Actor {
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0; virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;
virtual void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) = 0; virtual void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) = 0;
virtual void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) = 0;
}; };
} // namespace validator } // namespace validator

View file

@ -38,6 +38,8 @@
#include "common/delay.h" #include "common/delay.h"
#include "validator/stats-merger.h"
namespace ton { namespace ton {
namespace validator { namespace validator {
@ -1811,6 +1813,7 @@ void ValidatorManagerImpl::advance_gc(BlockHandle handle, td::Ref<MasterchainSta
gc_advancing_ = false; gc_advancing_ = false;
gc_masterchain_handle_ = std::move(handle); gc_masterchain_handle_ = std::move(handle);
gc_masterchain_state_ = std::move(state); gc_masterchain_state_ = std::move(state);
try_advance_gc_masterchain_block();
} }
void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) { void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) {
@ -1970,21 +1973,37 @@ void ValidatorManagerImpl::send_peek_key_block_request() {
} }
void ValidatorManagerImpl::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) { void ValidatorManagerImpl::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) {
auto merger = StatsMerger::create(std::move(promise));
td::actor::send_closure(db_, &Db::prepare_stats, merger.make_promise("db."));
std::vector<std::pair<std::string, std::string>> vec; std::vector<std::pair<std::string, std::string>> vec;
vec.emplace_back("unixtime", td::to_string(static_cast<UnixTime>(td::Clocks::system()))); vec.emplace_back("unixtime", td::to_string(static_cast<UnixTime>(td::Clocks::system())));
if (!last_masterchain_block_handle_) { if (last_masterchain_block_handle_) {
promise.set_value(std::move(vec));
return;
}
vec.emplace_back("masterchainblock", last_masterchain_block_id_.to_str()); vec.emplace_back("masterchainblock", last_masterchain_block_id_.to_str());
vec.emplace_back("masterchainblocktime", td::to_string(last_masterchain_block_handle_->unix_time())); vec.emplace_back("masterchainblocktime", td::to_string(last_masterchain_block_handle_->unix_time()));
vec.emplace_back("gcmasterchainblock", gc_masterchain_handle_->id().to_str()); vec.emplace_back("gcmasterchainblock", gc_masterchain_handle_->id().to_str());
vec.emplace_back("keymasterchainblock", last_key_block_handle_->id().to_str()); vec.emplace_back("keymasterchainblock", last_key_block_handle_->id().to_str());
vec.emplace_back("knownkeymasterchainblock", last_known_key_block_handle_->id().to_str()); vec.emplace_back("knownkeymasterchainblock", last_known_key_block_handle_->id().to_str());
vec.emplace_back("rotatemasterchainblock", last_rotate_block_id_.to_str()); vec.emplace_back("rotatemasterchainblock", last_rotate_block_id_.to_str());
vec.emplace_back("shardclientmasterchainseqno", td::to_string(min_confirmed_masterchain_seqno_)); //vec.emplace_back("shardclientmasterchainseqno", td::to_string(min_confirmed_masterchain_seqno_));
vec.emplace_back("stateserializermasterchainseqno", td::to_string(state_serializer_masterchain_seqno_)); vec.emplace_back("stateserializermasterchainseqno", td::to_string(state_serializer_masterchain_seqno_));
}
if (!shard_client_.empty()) {
auto P = td::PromiseCreator::lambda([promise = merger.make_promise("")](td::Result<BlockSeqno> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
return;
}
std::vector<std::pair<std::string, std::string>> vec;
vec.emplace_back("shardclientmasterchainseqno", td::to_string(R.move_as_ok()));
promise.set_value(std::move(vec)); promise.set_value(std::move(vec));
});
td::actor::send_closure(shard_client_, &ShardClient::get_processed_masterchain_block, std::move(P));
}
merger.make_promise("").set_value(std::move(vec));
} }
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create( td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(

74
validator/stats-merger.h Normal file
View file

@ -0,0 +1,74 @@
#pragma once
#include "td/utils/int_types.h"
#include "td/actor/actor.h"
namespace ton {
namespace validator {
class StatsMerger : public td::actor::Actor {
public:
StatsMerger(td::Promise<std::vector<std::pair<std::string, std::string>>> promise)
: promise_(std::move(promise)) {
}
void start_up() override {
if (!pending_) {
finish();
}
}
void finish_subjob(td::Result<std::vector<std::pair<std::string, std::string>>> R, std::string prefix) {
if (R.is_ok()) {
auto v = R.move_as_ok();
for (auto &el : v) {
cur_.emplace_back(prefix + el.first, std::move(el.second));
}
}
if (--pending_ == 0) {
finish();
}
}
void inc() {
++pending_;
}
void dec() {
if (--pending_ == 0) {
finish();
}
}
void finish() {
promise_.set_value(std::move(cur_));
stop();
}
struct InitGuard {
td::actor::ActorId<StatsMerger> merger;
~InitGuard() {
td::actor::send_closure(merger, &StatsMerger::dec);
}
auto make_promise(std::string prefix) {
merger.get_actor_unsafe().inc();
return td::PromiseCreator::lambda(
[merger = merger, prefix](td::Result<std::vector<std::pair<std::string, std::string>>> R) {
td::actor::send_closure(merger, &StatsMerger::finish_subjob, std::move(R), std::move(prefix));
});
}
};
static InitGuard create(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) {
InitGuard ig;
ig.merger = td::actor::create_actor<StatsMerger>("m", std::move(promise)).release();
return ig;
}
private:
std::vector<std::pair<std::string, std::string>> cur_;
std::atomic<td::uint32> pending_{1};
td::Promise<std::vector<std::pair<std::string, std::string>>> promise_;
};
} // namespace validator
} // namespace ton

View file

@ -125,7 +125,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id, ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init, std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl, td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
td::ClocksBase::Duration archive_ttl, td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl,
td::ClocksBase::Duration key_proof_ttl, bool initial_sync_disabled) td::ClocksBase::Duration key_proof_ttl, bool initial_sync_disabled)
: zero_block_id_(zero_block_id) : zero_block_id_(zero_block_id)
, init_block_id_(init_block_id) , init_block_id_(init_block_id)