mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-14 12:12:21 +00:00
minor improvements and bugfixes
This commit is contained in:
parent
eecf05ca59
commit
040df63c98
24 changed files with 665 additions and 344 deletions
|
@ -94,41 +94,41 @@ WordList& WordList::append(const std::vector<Ref<WordDef>>& other) {
|
|||
}
|
||||
|
||||
//
|
||||
// WordRef
|
||||
// DictEntry
|
||||
//
|
||||
|
||||
WordRef::WordRef(Ref<WordDef> _def, bool _act) : def(std::move(_def)), active(_act) {
|
||||
DictEntry::DictEntry(Ref<WordDef> _def, bool _act) : def(std::move(_def)), active(_act) {
|
||||
}
|
||||
|
||||
WordRef::WordRef(StackWordFunc func) : def(Ref<StackWord>{true, std::move(func)}), active(false) {
|
||||
DictEntry::DictEntry(StackWordFunc func) : def(Ref<StackWord>{true, std::move(func)}), active(false) {
|
||||
}
|
||||
|
||||
WordRef::WordRef(CtxWordFunc func, bool _act) : def(Ref<CtxWord>{true, std::move(func)}), active(_act) {
|
||||
DictEntry::DictEntry(CtxWordFunc func, bool _act) : def(Ref<CtxWord>{true, std::move(func)}), active(_act) {
|
||||
}
|
||||
|
||||
WordRef::WordRef(CtxTailWordFunc func, bool _act) : def(Ref<CtxTailWord>{true, std::move(func)}), active(_act) {
|
||||
DictEntry::DictEntry(CtxTailWordFunc func, bool _act) : def(Ref<CtxTailWord>{true, std::move(func)}), active(_act) {
|
||||
}
|
||||
|
||||
Ref<WordDef> WordRef::get_def() const & {
|
||||
Ref<WordDef> DictEntry::get_def() const& {
|
||||
return def;
|
||||
}
|
||||
|
||||
Ref<WordDef> WordRef::get_def() && {
|
||||
Ref<WordDef> DictEntry::get_def() && {
|
||||
return std::move(def);
|
||||
}
|
||||
|
||||
void WordRef::operator()(IntCtx& ctx) const {
|
||||
void DictEntry::operator()(IntCtx& ctx) const {
|
||||
def->run(ctx);
|
||||
}
|
||||
|
||||
bool WordRef::is_active() const {
|
||||
bool DictEntry::is_active() const {
|
||||
return active;
|
||||
}
|
||||
|
||||
//
|
||||
// Dictionary
|
||||
//
|
||||
WordRef* Dictionary::lookup(td::Slice name) {
|
||||
DictEntry* Dictionary::lookup(td::Slice name) {
|
||||
auto it = words_.find(name);
|
||||
if (it == words_.end()) {
|
||||
return nullptr;
|
||||
|
@ -153,7 +153,7 @@ void Dictionary::def_ctx_tail_word(std::string name, CtxTailWordFunc func) {
|
|||
def_word(std::move(name), std::move(func));
|
||||
}
|
||||
|
||||
void Dictionary::def_word(std::string name, WordRef word) {
|
||||
void Dictionary::def_word(std::string name, DictEntry word) {
|
||||
auto res = words_.emplace(name, std::move(word));
|
||||
LOG_IF(FATAL, !res.second) << "Cannot redefine word: " << name;
|
||||
}
|
||||
|
|
|
@ -110,34 +110,34 @@ class WordList : public WordDef {
|
|||
}
|
||||
};
|
||||
|
||||
class WordRef {
|
||||
class DictEntry {
|
||||
Ref<WordDef> def;
|
||||
bool active;
|
||||
|
||||
public:
|
||||
WordRef() = delete;
|
||||
WordRef(const WordRef& ref) = default;
|
||||
WordRef(WordRef&& ref) = default;
|
||||
WordRef(Ref<WordDef> _def, bool _act = false);
|
||||
WordRef(StackWordFunc func);
|
||||
WordRef(CtxWordFunc func, bool _act = false);
|
||||
WordRef(CtxTailWordFunc func, bool _act = false);
|
||||
//WordRef(const std::vector<Ref<WordDef>>& word_list);
|
||||
//WordRef(std::vector<Ref<WordDef>>&& word_list);
|
||||
WordRef& operator=(const WordRef&) = default;
|
||||
WordRef& operator=(WordRef&&) = default;
|
||||
Ref<WordDef> get_def() const &;
|
||||
DictEntry() = delete;
|
||||
DictEntry(const DictEntry& ref) = default;
|
||||
DictEntry(DictEntry&& ref) = default;
|
||||
DictEntry(Ref<WordDef> _def, bool _act = false);
|
||||
DictEntry(StackWordFunc func);
|
||||
DictEntry(CtxWordFunc func, bool _act = false);
|
||||
DictEntry(CtxTailWordFunc func, bool _act = false);
|
||||
//DictEntry(const std::vector<Ref<WordDef>>& word_list);
|
||||
//DictEntry(std::vector<Ref<WordDef>>&& word_list);
|
||||
DictEntry& operator=(const DictEntry&) = default;
|
||||
DictEntry& operator=(DictEntry&&) = default;
|
||||
Ref<WordDef> get_def() const&;
|
||||
Ref<WordDef> get_def() &&;
|
||||
void operator()(IntCtx& ctx) const;
|
||||
bool is_active() const;
|
||||
~WordRef() = default;
|
||||
~DictEntry() = default;
|
||||
};
|
||||
|
||||
/*
|
||||
WordRef::WordRef(const std::vector<Ref<WordDef>>& word_list) : def(Ref<WordList>{true, word_list}) {
|
||||
DictEntry::DictEntry(const std::vector<Ref<WordDef>>& word_list) : def(Ref<WordList>{true, word_list}) {
|
||||
}
|
||||
|
||||
WordRef::WordRef(std::vector<Ref<WordDef>>&& word_list) : def(Ref<WordList>{true, std::move(word_list)}) {
|
||||
DictEntry::DictEntry(std::vector<Ref<WordDef>>&& word_list) : def(Ref<WordList>{true, std::move(word_list)}) {
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -149,12 +149,12 @@ WordRef::WordRef(std::vector<Ref<WordDef>>&& word_list) : def(Ref<WordList>{true
|
|||
|
||||
class Dictionary {
|
||||
public:
|
||||
WordRef* lookup(td::Slice name);
|
||||
DictEntry* lookup(td::Slice name);
|
||||
void def_ctx_word(std::string name, CtxWordFunc func);
|
||||
void def_ctx_tail_word(std::string name, CtxTailWordFunc func);
|
||||
void def_active_word(std::string name, CtxWordFunc func);
|
||||
void def_stack_word(std::string name, StackWordFunc func);
|
||||
void def_word(std::string name, WordRef word);
|
||||
void def_word(std::string name, DictEntry word);
|
||||
void undef_word(td::Slice name);
|
||||
|
||||
auto begin() const {
|
||||
|
@ -167,7 +167,7 @@ class Dictionary {
|
|||
static Ref<WordDef> nop_word_def;
|
||||
|
||||
private:
|
||||
std::map<std::string, WordRef, std::less<>> words_;
|
||||
std::map<std::string, DictEntry, std::less<>> words_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -171,26 +171,26 @@ void IntCtx::skipspc(bool skip_eol) {
|
|||
} while (load_next_line());
|
||||
}
|
||||
|
||||
void check_compile(const IntCtx& ctx) {
|
||||
if (ctx.state <= 0) {
|
||||
void IntCtx::check_compile() const {
|
||||
if (state <= 0) {
|
||||
throw IntError{"compilation mode only"};
|
||||
}
|
||||
}
|
||||
|
||||
void check_execute(const IntCtx& ctx) {
|
||||
if (ctx.state != 0) {
|
||||
void IntCtx::check_execute() const {
|
||||
if (state != 0) {
|
||||
throw IntError{"interpret mode only"};
|
||||
}
|
||||
}
|
||||
|
||||
void check_not_int_exec(const IntCtx& ctx) {
|
||||
if (ctx.state < 0) {
|
||||
void IntCtx::check_not_int_exec() const {
|
||||
if (state < 0) {
|
||||
throw IntError{"not allowed in internal interpret mode"};
|
||||
}
|
||||
}
|
||||
|
||||
void check_int_exec(const IntCtx& ctx) {
|
||||
if (ctx.state >= 0) {
|
||||
void IntCtx::check_int_exec() const {
|
||||
if (state >= 0) {
|
||||
throw IntError{"internal interpret mode only"};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,12 +141,12 @@ struct IntCtx {
|
|||
Savepoint(IntCtx& _ctx, std::string new_filename, std::string new_current_dir, std::istream* new_input_stream);
|
||||
~Savepoint();
|
||||
};
|
||||
};
|
||||
|
||||
void check_compile(const IntCtx& ctx);
|
||||
void check_execute(const IntCtx& ctx);
|
||||
void check_not_int_exec(const IntCtx& ctx);
|
||||
void check_int_exec(const IntCtx& ctx);
|
||||
void check_compile() const;
|
||||
void check_execute() const;
|
||||
void check_not_int_exec() const;
|
||||
void check_int_exec() const;
|
||||
};
|
||||
|
||||
td::StringBuilder& operator<<(td::StringBuilder& os, const IntCtx& ctx);
|
||||
std::ostream& operator<<(std::ostream& os, const IntCtx& ctx);
|
||||
|
|
|
@ -1782,7 +1782,7 @@ void interpret_wordlist_begin_aux(vm::Stack& stack) {
|
|||
}
|
||||
|
||||
void interpret_wordlist_begin(IntCtx& ctx) {
|
||||
check_not_int_exec(ctx);
|
||||
ctx.check_not_int_exec();
|
||||
interpret_wordlist_begin_aux(ctx.stack);
|
||||
push_argcount(ctx, 0);
|
||||
++(ctx.state);
|
||||
|
@ -1795,20 +1795,20 @@ void interpret_wordlist_end_aux(vm::Stack& stack) {
|
|||
}
|
||||
|
||||
void interpret_wordlist_end(IntCtx& ctx) {
|
||||
check_compile(ctx);
|
||||
ctx.check_compile();
|
||||
interpret_wordlist_end_aux(ctx.stack);
|
||||
push_argcount(ctx, 1);
|
||||
--(ctx.state);
|
||||
}
|
||||
|
||||
void interpret_internal_interpret_begin(IntCtx& ctx) {
|
||||
check_compile(ctx);
|
||||
ctx.check_compile();
|
||||
push_argcount(ctx, 0);
|
||||
ctx.state = -ctx.state;
|
||||
}
|
||||
|
||||
void interpret_internal_interpret_end(IntCtx& ctx) {
|
||||
check_int_exec(ctx);
|
||||
ctx.check_int_exec();
|
||||
ctx.state = -ctx.state;
|
||||
ctx.stack.push({vm::from_object, Dictionary::nop_word_def});
|
||||
}
|
||||
|
@ -1830,9 +1830,9 @@ void interpret_create_aux(IntCtx& ctx, int mode) {
|
|||
bool active = (mode & 1);
|
||||
auto entry = ctx.dictionary->lookup(word);
|
||||
if (entry) {
|
||||
*entry = WordRef{wd_ref, active}; // redefine word
|
||||
*entry = DictEntry{std::move(wd_ref), active}; // redefine word
|
||||
} else {
|
||||
ctx.dictionary->def_word(std::move(word), {wd_ref, active});
|
||||
ctx.dictionary->def_word(std::move(word), {std::move(wd_ref), active});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -235,29 +235,7 @@ variable special-dict
|
|||
// restricted wallet creation
|
||||
|
||||
// same as in new-wallet-v3.fif
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
|
||||
1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs
|
||||
NOW s1 s3 XCHG LEQ 35 THROWIF // signature in_msg subwallet_id cs msg_seqno
|
||||
c4 PUSH CTOS 32 LDU 32 LDU 256 LDU ENDS // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key
|
||||
s3 s2 XCPU EQUAL 33 THROWIFNOT // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet
|
||||
s4 s4 XCPU EQUAL 34 THROWIFNOT // signature in_msg stored_subwallet cs public_key stored_seqno
|
||||
s0 s4 XCHG HASHSU // signature stored_seqno stored_subwallet cs public_key msg_hash
|
||||
s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs msg_hash signature public_key
|
||||
CHKSIGNU 35 THROWIFNOT // public_key stored_seqno stored_subwallet cs
|
||||
ACCEPT
|
||||
WHILE:<{
|
||||
DUP SREFS // public_key stored_seqno stored_subwallet cs _51
|
||||
}>DO<{ // public_key stored_seqno stored_subwallet cs
|
||||
8 LDU LDREF s0 s2 XCHG // public_key stored_seqno stored_subwallet cs _56 mode
|
||||
SENDRAWMSG
|
||||
}> // public_key stored_seqno stored_subwallet cs
|
||||
ENDS SWAP INC // public_key stored_subwallet seqno'
|
||||
NEWC 32 STU 32 STU 256 STU ENDC c4 POP
|
||||
}>c
|
||||
"wallet-v3-code.fif" include
|
||||
=: WCode3
|
||||
|
||||
"auto/wallet-code.fif" include =: WCode0
|
||||
|
|
|
@ -26,7 +26,7 @@ $5 base64>B dup Blen 64 <> abort"validator Ed25519 signature must be exactly 64
|
|||
=: signature
|
||||
$6 savefile replace-if-null =: savefile
|
||||
|
||||
."Creating the body of an internal message to be sent to the elections smart contract" cr }
|
||||
."Creating the body of an internal message to be sent to the elections smart contract" cr
|
||||
."containing a signed request to vote for complaint 0x" compl-hash 64x. ."of past validator set " elect-id .
|
||||
."on behalf of current validator with index " val-idx . "and public key" pubkey Bx. cr
|
||||
|
||||
|
|
|
@ -318,6 +318,19 @@ _ ~credit_to(credits, addr, amount) inline_ref {
|
|||
return (credits, recovered + tot_bonuses - returned_bonuses);
|
||||
}
|
||||
|
||||
int stakes_sum(frozen_dict) inline_ref {
|
||||
var total = 0;
|
||||
var pubkey = -1;
|
||||
do {
|
||||
(pubkey, var cs, var f) = frozen_dict.udict_get_next?(256, pubkey);
|
||||
if (f) {
|
||||
cs~skip_bits(256 + 64);
|
||||
total += cs~load_grams();
|
||||
}
|
||||
} until (~ f);
|
||||
return total;
|
||||
}
|
||||
|
||||
_ unfreeze_all(credits, past_elections, elect_id) inline_ref {
|
||||
var (fs, f) = past_elections~udict_delete_get?(32, elect_id);
|
||||
ifnot (f) {
|
||||
|
@ -325,6 +338,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref {
|
|||
return (credits, past_elections, 0);
|
||||
}
|
||||
var (unfreeze_at, stake_held, vset_hash, fdict, tot_stakes, bonuses, complaints) = fs.unpack_past_election();
|
||||
;; tot_stakes = fdict.stakes_sum(); ;; TEMP BUGFIX
|
||||
var unused_prizes = (bonuses > 0) ?
|
||||
credits~unfreeze_with_bonuses(fdict, tot_stakes, bonuses) :
|
||||
credits~unfreeze_without_bonuses(fdict, tot_stakes);
|
||||
|
@ -468,7 +482,7 @@ int register_complaint(s_addr, complaint, msg_value) {
|
|||
var (_, bits, refs) = slice_compute_data_size(complaint, 4096);
|
||||
var pps = (bits + 1024) * bit_price + (refs + 2) * cell_price;
|
||||
paid = pps * expire_in + deposit;
|
||||
if (paid + (1 << 30) < msg_value) { ;; not enough money
|
||||
if (msg_value < paid + (1 << 30)) { ;; not enough money
|
||||
return -5;
|
||||
}
|
||||
;; re-pack modified complaint
|
||||
|
@ -503,12 +517,12 @@ int register_complaint(s_addr, complaint, msg_value) {
|
|||
return paid;
|
||||
}
|
||||
|
||||
(cell, cell, int) punish(credits, frozen, complaint) inline_ref {
|
||||
(cell, cell, int, int) punish(credits, frozen, complaint) inline_ref {
|
||||
var (validator_pubkey, description, created_at, severity, reward_addr, paid, suggested_fine, suggested_fine_part) = complaint.begin_parse().unpack_complaint();
|
||||
var (cs, f) = frozen.udict_get?(256, validator_pubkey);
|
||||
ifnot (f) {
|
||||
;; no validator to punish
|
||||
return (credits, frozen, 0);
|
||||
return (credits, frozen, 0, 0);
|
||||
}
|
||||
var (addr, weight, stake, banned) = (cs~load_uint(256), cs~load_uint(64), cs~load_grams(), cs~load_int(1));
|
||||
cs.end_parse();
|
||||
|
@ -520,9 +534,8 @@ int register_complaint(s_addr, complaint, msg_value) {
|
|||
.store_grams(stake)
|
||||
.store_int(banned, 1));
|
||||
int reward = min(fine >> 3, paid * 8);
|
||||
fine -= reward;
|
||||
credits~credit_to(reward_addr, reward);
|
||||
return (credits, frozen, fine);
|
||||
return (credits, frozen, fine - reward, fine);
|
||||
}
|
||||
|
||||
(cell, cell, int) register_vote(complaints, chash, idx, weight) inline_ref {
|
||||
|
@ -534,7 +547,12 @@ int register_complaint(s_addr, complaint, msg_value) {
|
|||
var (cur_vset, total_weight, _) = get_current_vset();
|
||||
int cur_vset_id = cur_vset.cell_hash();
|
||||
var (complaint, voters, vset_id, weight_remaining) = unpack_complaint_status(cstatus);
|
||||
if (vset_id != cur_vset_id) {
|
||||
int vset_old? = (vset_id != cur_vset_id);
|
||||
if ((weight_remaining < 0) & vset_old?) {
|
||||
;; previous validator set already collected 2/3 votes, skip new votes
|
||||
return (complaints, null(), -3);
|
||||
}
|
||||
if (vset_old?) {
|
||||
;; complaint votes belong to a previous validator set, reset voting
|
||||
vset_id = cur_vset_id;
|
||||
voters = null();
|
||||
|
@ -572,10 +590,11 @@ int proceed_register_vote(election_id, chash, idx, weight) impure inline_ref {
|
|||
return status;
|
||||
}
|
||||
ifnot (accepted_complaint.null?()) {
|
||||
(credits, frozen_dict, int fine) = punish(credits, frozen_dict, accepted_complaint);
|
||||
grams += fine;
|
||||
(credits, frozen_dict, int fine_unalloc, int fine_collected) = punish(credits, frozen_dict, accepted_complaint);
|
||||
grams += fine_unalloc;
|
||||
total_stake -= fine_collected;
|
||||
}
|
||||
past_elections.udict_set_builder(32, election_id, pack_past_election(unfreeze_at, stake_held, vset_hash, frozen_dict, total_stake, bonuses, complaints));
|
||||
past_elections~udict_set_builder(32, election_id, pack_past_election(unfreeze_at, stake_held, vset_hash, frozen_dict, total_stake, bonuses, complaints));
|
||||
store_data(elect, credits, past_elections, grams, active_id, active_hash);
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -32,11 +32,11 @@ file>B B>boc dup =: complaint hash =: c-hash
|
|||
complaint <s 8 u@ 0xbc <> abort"Not a valid ValidatorComplaint"
|
||||
complaint <s csr.
|
||||
|
||||
." complaint envelope will expire at " expire-at . ."(in " expire-in . ."seconds)" cr
|
||||
// ." complaint envelope will expire at " expire-at . ."(in " expire-in . ."seconds)" cr
|
||||
now 32 << c-hash 0xffffffff and or =: query-id
|
||||
."Query id is " query-id . cr
|
||||
|
||||
<b x{52674370} s, query-id 64 u, election-id 32 u, expire-at 32 u,
|
||||
<b x{52674370} s, query-id 64 u, election-id 32 u,
|
||||
complaint <s s, b>
|
||||
|
||||
dup ."resulting internal message body: " <s csr. cr
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#!/usr/bin/create-state -s
|
||||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
"Lists.fif" include
|
||||
|
||||
def? $1 { @' $1 } { "" } cond constant suffix
|
||||
{ suffix $+ } : +suffix
|
||||
256 1<<1- 15 / constant AllOnes
|
||||
|
||||
wc_master setworkchain
|
||||
-17 setglobalid // negative value means a test instance of the blockchain
|
||||
-239 setglobalid // negative value means a test instance of the blockchain
|
||||
|
||||
// Initial state of Workchain 0 (Basic workchain)
|
||||
|
||||
|
@ -16,30 +19,35 @@ dup dup 31 boc+>B dup Bx. cr
|
|||
dup "basestate0" +suffix +".boc" tuck B>file
|
||||
."(Initial basechain state saved to file " type .")" cr
|
||||
Bhashu dup =: basestate0_fhash
|
||||
."file hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
."file hash=" dup 64x. space 256 u>B dup B>base64url type cr
|
||||
"basestate0" +suffix +".fhash" B>file
|
||||
hashu dup =: basestate0_rhash
|
||||
."root hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
."root hash=" dup 64x. space 256 u>B dup B>base64url type cr
|
||||
"basestate0" +suffix +".rhash" B>file
|
||||
|
||||
basestate0_rhash basestate0_fhash now 0 2 32 0 add-std-workchain
|
||||
// root-hash file-hash start-at actual-min-split min-split-depth max-split-depth wc-id
|
||||
basestate0_rhash basestate0_fhash now 0 4 8 0 add-std-workchain
|
||||
config.workchains!
|
||||
|
||||
// SmartContract #1 (Simple wallet)
|
||||
|
||||
<{ SETCP0 DUP IFNOTRET INC 32 THROWIF // return if recv_internal, fail unless recv_external
|
||||
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt
|
||||
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk
|
||||
s1 s2 XCPU // sign cs cnt pubk cnt' cnt
|
||||
EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
s2 PUSH HASHSU // sign cs cnt pubk hash
|
||||
s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk
|
||||
CHKSIGNU // pubk cs cnt ?
|
||||
34 THROWIFNOT // signature mismatch
|
||||
ACCEPT
|
||||
SWAP 32 LDU NIP 8 LDU LDREF ENDS // pubk cnt mode msg
|
||||
SWAP SENDRAWMSG // pubk cnt ; ( message sent )
|
||||
INC NEWC 32 STU 256 STU ENDC c4 POPCTR
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
|
||||
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt
|
||||
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk
|
||||
s1 s2 XCPU // sign cs cnt pubk cnt' cnt
|
||||
EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
s2 PUSH HASHSU // sign cs cnt pubk hash
|
||||
s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk
|
||||
CHKSIGNU // pubk cs cnt ?
|
||||
34 THROWIFNOT // signature mismatch
|
||||
ACCEPT
|
||||
SWAP 32 LDU NIP 8 LDU LDREF ENDS // pubk cnt mode msg
|
||||
SWAP SENDRAWMSG // pubk cnt ; ( message sent )
|
||||
INC NEWC 32 STU 256 STU ENDC c4 POPCTR
|
||||
}>c
|
||||
// code
|
||||
<b 0 32 u,
|
||||
|
@ -50,10 +58,11 @@ Libs{
|
|||
x{ABACABADABACABA} s>c public_lib
|
||||
x{1234} x{5678} |_ s>c private_lib
|
||||
}Libs // libraries
|
||||
GR$1700000000 // balance
|
||||
GR$4999990000 // balance
|
||||
0 // split_depth
|
||||
0 // ticktock
|
||||
2 // mode: create
|
||||
AllOnes 0 * // address
|
||||
6 // mode: create+setaddr
|
||||
register_smc
|
||||
dup make_special dup constant smc1_addr
|
||||
Masterchain over
|
||||
|
@ -61,7 +70,11 @@ Masterchain over
|
|||
"main-wallet" +suffix +".addr" save-address-verbose
|
||||
|
||||
// SmartContract #2 (Simple money giver for test network)
|
||||
<{ SETCP0 DUP IFNOTRET INC 32 THROWIF // return if recv_internal, fail unless recv_external
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
|
||||
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
32 LDU SWAP // cs cnt
|
||||
c4 PUSHCTR CTOS 32 LDU ENDS // cs cnt cnt'
|
||||
TUCK EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
|
@ -74,8 +87,8 @@ Masterchain over
|
|||
// code
|
||||
<b 0 32 u, b> // data
|
||||
empty_cell // libraries
|
||||
GR$1000000 // initial balance (1m test Grams)
|
||||
0 0 2 register_smc
|
||||
GR$1000 // initial balance (1k test Grams)
|
||||
0 0 AllOnes 6 * 6 register_smc
|
||||
dup make_special dup constant smc2_addr
|
||||
Masterchain over
|
||||
2dup ."free test gram giver address = " .addr cr 2dup 6 .Addr cr
|
||||
|
@ -112,60 +125,95 @@ Libs{
|
|||
x{ABACABADABACABA} s>c public_lib
|
||||
x{1234} x{5678} |_ s>c public_lib
|
||||
}Libs // libraries
|
||||
0x333333333 // balance
|
||||
GR$666 // balance
|
||||
0 // split_depth
|
||||
3 // ticktock: tick
|
||||
2 // mode: create
|
||||
register_smc
|
||||
dup make_special dup constant smc3_addr
|
||||
."address = " x. cr
|
||||
."address = " 64x. cr
|
||||
|
||||
// SmartContract #4 (elector)
|
||||
/*
|
||||
*
|
||||
* SmartContract #4 (elector)
|
||||
*
|
||||
*/
|
||||
"auto/elector-code.fif" include // code in separate source file
|
||||
<b 0 1 1+ 1+ 5 + u, 0 256 u, b> // data
|
||||
<b 0 1 1+ 1+ 4 + 32 + u, 0 256 u, b> // data: dict dict dict grams uint32 uint256
|
||||
empty_cell // libraries
|
||||
GR$10 // balance: 10 grams
|
||||
0 // split_depth
|
||||
1 // ticktock: tick
|
||||
2 // mode: create
|
||||
2 // ticktock: tick
|
||||
AllOnes 3 * // address: -1:333...333
|
||||
6 // mode: create + setaddr
|
||||
register_smc
|
||||
dup make_special dup constant smc4_addr dup constant elector_addr
|
||||
Masterchain swap
|
||||
."elector smart contract address = " 2dup .addr cr 2dup 7 .Addr cr
|
||||
"elector" +suffix +".addr" save-address-verbose
|
||||
|
||||
// Configuration Parameters
|
||||
|
||||
/*
|
||||
*
|
||||
* Configuration Parameters
|
||||
*
|
||||
*/
|
||||
// version capabilities
|
||||
1 capCreateStats capBounceMsgBody or capReportVersion or capShortDequeue or config.version!
|
||||
// max-validators max-main-validators min-validators
|
||||
// 9 3 2 config.validator_num!
|
||||
1000 100 5 config.validator_num!
|
||||
// 9 4 1 config.validator_num!
|
||||
1000 100 13 config.validator_num!
|
||||
// min-stake max-stake min-total-stake max-factor
|
||||
GR$10000 GR$10000000 GR$1000000 sg~10 config.validator_stake_limits!
|
||||
GR$10000 GR$10000000 GR$500000 sg~3 config.validator_stake_limits!
|
||||
// elected-for elect-start-before elect-end-before stakes-frozen-for
|
||||
400000 200000 4000 400000 config.election_params!
|
||||
// 400000 200000 4000 400000 config.election_params!
|
||||
// 4000 2000 500 1000 config.election_params! // DEBUG
|
||||
65536 32768 8192 32768 config.election_params! // TestNet DEBUG
|
||||
// config-addr = -1:5555...5555
|
||||
AllOnes 5 * constant config_addr
|
||||
config_addr config.config_smc!
|
||||
// elector-addr
|
||||
elector_addr config.elector_smc!
|
||||
|
||||
1 sg* 100 sg* 1000 sg* 1000000 sg* config.storage_prices!
|
||||
// 1 sg* 100 sg* 1000 sg* 1000000 sg* config.storage_prices! // old values (too high)
|
||||
1 500 1000 500000 config.storage_prices!
|
||||
config.special!
|
||||
|
||||
// gas_price gas_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit --
|
||||
1000 sg* 1000000 10000 10000000 GR$0.1 GR$1.0 config.gas_prices!
|
||||
10000 sg* 1000000 10000 10000000 GR$0.1 GR$1.0 config.mc_gas_prices!
|
||||
// gas_price gas_limit special_gas_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit flat_gas_limit flat_gas_price --
|
||||
1000 sg* 1 *M dup 10000 10 *M GR$0.1 GR$1.0 1000 1000000 config.gas_prices!
|
||||
10000 sg* 1 *M 10 *M 10000 10 *M GR$0.1 GR$1.0 1000 10000000 config.mc_gas_prices!
|
||||
// lump_price bit_price cell_price ihr_factor first_frac next_frac
|
||||
1000000 1000 sg* 100000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.fwd_prices!
|
||||
10000000 10000 sg* 1000000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.mc_fwd_prices!
|
||||
// mc-cc-lifetime sh-cc-lifetime sh-val-lifetime sh-val-num
|
||||
250 250 1000 7 config.catchain_params!
|
||||
// mc-cc-lifetime sh-cc-lifetime sh-val-lifetime sh-val-num mc-shuffle
|
||||
250 250 1000 7 true config.catchain_params!
|
||||
// round-candidates next-cand-delay-ms consensus-timeout-ms fast-attempts attempt-duration cc-max-deps max-block-size max-collated-size new-cc-ids
|
||||
3 2000 16000 3 8 4 2 *Mi 2 *Mi true config.consensus_params!
|
||||
|
||||
128 *Ki 512 *Ki 1 *Mi triple // [ underload soft hard ] : block bytes limit
|
||||
100000 500000 1000000 triple // gas limits
|
||||
1000 5000 10000 triple // lt limits
|
||||
|
||||
128 *Ki 512 *Ki 1 *Mi triple // [ underload soft hard ] : block bytes limit
|
||||
2000000 10000000 20000000 triple // gas limits
|
||||
1000 5000 10000 triple // lt limits
|
||||
triple dup untriple config.mc_block_limits!
|
||||
untriple config.block_limits!
|
||||
|
||||
GR$1.7 GR$1 config.block_create_fees!
|
||||
smc1_addr config.collector_smc!
|
||||
// smc1_addr config.collector_smc!
|
||||
smc1_addr config.minter_smc!
|
||||
|
||||
1000000000000 -17 of-cc 666666666666 239 of-cc cc+ config.to_mint!
|
||||
|
||||
( 0 1 9 10 12 14 15 16 17 18 20 21 22 23 24 25 28 34 ) config.mandatory_params!
|
||||
( -999 -1000 -1001 0 1 9 10 12 14 15 16 17 32 34 36 ) config.critical_params!
|
||||
|
||||
// [ min_tot_rounds max_tot_rounds min_wins max_losses min_store_sec max_store_sec bit_pps cell_pps ]
|
||||
// first for ordinary proposals, then for critical proposals
|
||||
_( 2 3 2 2 1000000 10000000 1 500 )
|
||||
_( 4 7 4 2 5000000 20000000 2 1000 )
|
||||
config.param_proposals_setup!
|
||||
|
||||
// deposit bit_pps cell_pps
|
||||
GR$100 1 500 config.complaint_prices!
|
||||
|
||||
"validator-keys" +suffix +".pub" file>B
|
||||
{ dup Blen } { 32 B| swap dup ."Validator public key = " Bx. cr
|
||||
17 add-validator } while drop
|
||||
|
@ -173,66 +221,57 @@ smc1_addr config.minter_smc!
|
|||
// 17 add-validator
|
||||
// newkeypair nip dup ."Validator #2 public key = " Bx. cr
|
||||
// 239 add-validator
|
||||
now dup 1000000 + 0 config.validators!
|
||||
100000 =: orig_vset_valid_for // original validator set valid 100000 seconds
|
||||
now dup orig_vset_valid_for + 0 config.validators!
|
||||
|
||||
// SmartContract #5 (Config)
|
||||
PROGRAM{
|
||||
recv_internal x{} PROC
|
||||
recv_external PROC:<{
|
||||
512 INT LDSLICEX DUP 32 LDU 32 PLDU // sign cs cnt valid-until
|
||||
NOW LEQ 35 THROWIF // ( fail if now >= valid-until )
|
||||
c4 PUSH CTOS LDREF 32 LDU 256 LDU ENDS // sign cs cnt dict cnt' pubk
|
||||
s1 s3 XCPU // sign cs cnt dict pubk cnt' cnt
|
||||
EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
s3 PUSH HASHSU // sign cs cnt dict pubk hash
|
||||
s0 s5 s5 XC2PU // pubk cs cnt dict hash sign pubk
|
||||
CHKSIGNU // pubk cs cnt dict ?
|
||||
34 THROWIFNOT // signature mismatch
|
||||
ACCEPT
|
||||
ROT 64 LDU NIP 32 LDI LDREF ENDS // pubk cnt dict index value
|
||||
s0 s2 XCHG 32 INT // pubk cnt value index dict 32
|
||||
DICTISETREF ROTREV // dict' pubk cnt
|
||||
INC NEWC 32 STU 256 STU STREF ENDC c4 POP
|
||||
}>
|
||||
run_ticktock PROC:<{
|
||||
// store (now >> 8) into config param #-17, if the new value is different
|
||||
c4 PUSH CTOS LDREF SWAP // s' D
|
||||
NOW 8 RSHIFT# TUCK // s' t D t
|
||||
NEWC 32 STU ENDC // s' t D c
|
||||
-17 INT ROT 32 INT // s' t c -17 D 32
|
||||
DICTISETGETREF // s' t D' c' -1 or s' t D' 0
|
||||
IF:<{ CTOS 32 LDU ENDS }>ELSE<{ ZERO }> // s' t D' y'
|
||||
ROT EQUAL IFNOT: // s' D'
|
||||
NEWC STREF STSLICE ENDC // c
|
||||
c4 POP
|
||||
}>
|
||||
}END>c
|
||||
// code
|
||||
<b 0 32 u,
|
||||
/*
|
||||
*
|
||||
* SmartContract #5 (Configuration smart contract)
|
||||
*
|
||||
*/
|
||||
"auto/config-code.fif" include // code in separate source file
|
||||
<b configdict ref, // initial configuration
|
||||
0 32 u, // seqno
|
||||
"config-master" +suffix +".pk" load-generate-keypair drop
|
||||
B,
|
||||
configdict ref,
|
||||
dictnew dict, // vote dict
|
||||
b> // data
|
||||
empty_cell // libraries
|
||||
1 // balance
|
||||
0 1 2 register_smc // tock
|
||||
GR$10 // balance
|
||||
0 1 config_addr 6 register_smc // tock
|
||||
dup set_config_smc
|
||||
Masterchain swap
|
||||
."config smart contract address = " 2dup .addr cr 2dup 7 .Addr cr
|
||||
"config-master" +suffix +".addr" save-address-verbose
|
||||
// Other data
|
||||
|
||||
/*
|
||||
*
|
||||
* Initial wallets (test)
|
||||
*
|
||||
*/
|
||||
|
||||
// pubkey amount `create-wallet1` or pubkey amount `create-wallet2`
|
||||
PK'PuZPPXK5Rff9SvtoS7Y9lUuEixvy-J6aishYFj3Qn6P0pJMb GR$1000000000 create-wallet1
|
||||
PK'PuYiB1zAWzr4p8j6I681+sGUrRGcn6Ylf7vXl0xaUl/w6Xfg GR$1700000000 create-wallet0
|
||||
|
||||
/*
|
||||
*
|
||||
* Create state
|
||||
*
|
||||
*/
|
||||
|
||||
create_state
|
||||
cr cr ."new state is:" cr dup <s csr. cr
|
||||
dup 31 boc+>B dup Bx. cr
|
||||
dup "zerostate" +suffix +".boc" tuck B>file
|
||||
."(Initial masterchain state saved to file " type .")" cr
|
||||
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
|
||||
hashu 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
|
||||
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
|
||||
zerostate_rhash ."Zerostate root hash=" dup x. space 256 u>B B>base64url type cr
|
||||
zerostate_fhash ."Zerostate file 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
|
||||
zerostate_rhash ."Zerostate root hash= " dup X. space 256 u>B B>base64url type cr
|
||||
zerostate_fhash ."Zerostate file hash= " dup X. space 256 u>B B>base64url type cr
|
||||
|
|
|
@ -8,7 +8,8 @@ def? $1 { @' $1 } { "" } cond constant suffix
|
|||
256 1<<1- 15 / constant AllOnes
|
||||
|
||||
wc_master setworkchain
|
||||
-239 setglobalid // negative value means a test instance of the blockchain
|
||||
13 setglobalid // negative value means a test instance of the blockchain
|
||||
0x11EF55AA default-subwallet-id! // use this subwallet id in user wallets by default
|
||||
|
||||
// Initial state of Workchain 0 (Basic workchain)
|
||||
|
||||
|
@ -29,110 +30,57 @@ hashu dup =: basestate0_rhash
|
|||
basestate0_rhash basestate0_fhash now 0 4 8 0 add-std-workchain
|
||||
config.workchains!
|
||||
|
||||
// SmartContract #1 (Simple wallet)
|
||||
/*
|
||||
*
|
||||
* Initial wallets (test)
|
||||
*
|
||||
*/
|
||||
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
|
||||
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt
|
||||
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk
|
||||
s1 s2 XCPU // sign cs cnt pubk cnt' cnt
|
||||
EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
s2 PUSH HASHSU // sign cs cnt pubk hash
|
||||
s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk
|
||||
CHKSIGNU // pubk cs cnt ?
|
||||
34 THROWIFNOT // signature mismatch
|
||||
ACCEPT
|
||||
SWAP 32 LDU NIP 8 LDU LDREF ENDS // pubk cnt mode msg
|
||||
SWAP SENDRAWMSG // pubk cnt ; ( message sent )
|
||||
INC NEWC 32 STU 256 STU ENDC c4 POPCTR
|
||||
}>c
|
||||
// code
|
||||
<b 0 32 u,
|
||||
// Stage 1 wallets
|
||||
|
||||
PK'Puasxr0QfFZZnYISRphVse7XHKfW7pZU5SJarVHXvQ+rpzkD rwallet-init-pubkey !
|
||||
-86400 rwallet-start-at +!
|
||||
|
||||
{ swap create-wallet3 } : stage1
|
||||
{ bl word $>GR bl word parse-pubkey } : parse-amount-pubkey
|
||||
{ parse-amount-pubkey stage1 } : StA
|
||||
|
||||
// test
|
||||
StA 1001 PuZ8WoEOTgSR8-HopmCIVlOVSL94tNn9zgraiJqMk1SnioEQ
|
||||
|
||||
// Stage 2 wallets
|
||||
|
||||
{ swap create-wallet0 } : stage2
|
||||
{ parse-amount-pubkey stage2 } : StB
|
||||
|
||||
// test
|
||||
StB 999. PubMMGvqM08jx_6BibYldMclwjl-D88r7-u0_IEcDXHA30-G
|
||||
|
||||
// Lockdowns
|
||||
|
||||
{ swap create-wallet3b } : stage3
|
||||
{ parse-amount-pubkey stage3 } : StC
|
||||
|
||||
// SmartContract #1 (Advanced wallet)
|
||||
|
||||
// Create new advanced wallet; code adapted from `auto/wallet3-code.fif`
|
||||
WCode3 // code
|
||||
<b 0 32 u, 0 32 u, // subwallet-id=0
|
||||
"main-wallet" +suffix +".pk" load-generate-keypair drop
|
||||
B,
|
||||
b> // data
|
||||
Libs{
|
||||
x{ABACABADABACABA} s>c public_lib
|
||||
x{1234} x{5678} |_ s>c private_lib
|
||||
}Libs // libraries
|
||||
GR$4999990000 // balance
|
||||
empty_cell // libs
|
||||
GR$4999999000 allocated-balance - // balance
|
||||
0 // split_depth
|
||||
0 // ticktock
|
||||
AllOnes 0 * // address
|
||||
AllOnes 1 * // address
|
||||
6 // mode: create+setaddr
|
||||
register_smc
|
||||
dup make_special dup constant smc1_addr
|
||||
Masterchain over
|
||||
2dup ."wallet address = " .addr cr 2dup 6 .Addr cr
|
||||
2dup ."main wallet address = " .addr cr 2dup 6 .Addr cr
|
||||
"main-wallet" +suffix +".addr" save-address-verbose
|
||||
|
||||
// SmartContract #2 (Simple money giver for test network)
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
|
||||
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
32 LDU SWAP // cs cnt
|
||||
c4 PUSHCTR CTOS 32 LDU ENDS // cs cnt cnt'
|
||||
TUCK EQUAL 33 THROWIFNOT // ( seqno mismatch? )
|
||||
ACCEPT // cs cnt'
|
||||
SWAP 8 LDU LDREF ENDS // cnt'' mode msg
|
||||
GR$20 INT 3 INT RAWRESERVE // reserve all but 20 Grams from the balance
|
||||
SWAP SENDRAWMSG
|
||||
INC NEWC 32 STU ENDC c4 POPCTR // store cnt''
|
||||
}>c
|
||||
// code
|
||||
<b 0 32 u, b> // data
|
||||
empty_cell // libraries
|
||||
GR$1000 // initial balance (1k test Grams)
|
||||
0 0 AllOnes 6 * 6 register_smc
|
||||
dup make_special dup constant smc2_addr
|
||||
Masterchain over
|
||||
2dup ."free test gram giver address = " .addr cr 2dup 6 .Addr cr
|
||||
"testgiver" +suffix +".addr" save-address-verbose
|
||||
|
||||
// SmartContract #3
|
||||
PROGRAM{
|
||||
recv_internal x{} PROC
|
||||
run_ticktock PROC:<{
|
||||
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS
|
||||
NEWC ROT INC 32 STUR OVER 256 STUR ENDC
|
||||
c4 POPCTR
|
||||
// first 32 bits of persistent data have been increased
|
||||
// remaining 256 bits with an address have been fetched
|
||||
// create new empty message with 0.1 Grams to that address
|
||||
NEWC b{00100010011111111} STSLICECONST TUCK 256 STU
|
||||
100000000 INT STGRAMS // store 0.1 Grams
|
||||
1 4 + 4 + 64 + 32 + 1+ 1+ INT STZEROES ENDC
|
||||
// send raw message from Cell
|
||||
ZERO SENDRAWMSG
|
||||
-17 INT 256 STIR 130000000 INT STGRAMS
|
||||
107 INT STZEROES ENDC
|
||||
ZERO // another message with 0.13 Grams to account -17
|
||||
NEWC b{11000100100000} "test" $>s |+ STSLICECONST
|
||||
123456789 INT STGRAMS
|
||||
107 INT STZEROES "Hello, world!" $>s STSLICECONST ENDC
|
||||
ZERO SENDRAWMSG SENDRAWMSG // external message to address "test"
|
||||
}>
|
||||
}END>c
|
||||
// code
|
||||
<b x{11EF55AA} s, smc1_addr 256 u, b> // data
|
||||
// empty_cell // libraries
|
||||
Libs{
|
||||
x{ABACABADABACABA} s>c public_lib
|
||||
x{1234} x{5678} |_ s>c public_lib
|
||||
}Libs // libraries
|
||||
GR$666 // balance
|
||||
0 // split_depth
|
||||
3 // ticktock: tick
|
||||
2 // mode: create
|
||||
register_smc
|
||||
dup make_special dup constant smc3_addr
|
||||
."address = " 64x. cr
|
||||
|
||||
/*
|
||||
*
|
||||
* SmartContract #4 (elector)
|
||||
|
@ -141,7 +89,7 @@ dup make_special dup constant smc3_addr
|
|||
"auto/elector-code.fif" include // code in separate source file
|
||||
<b 0 1 1+ 1+ 4 + 32 + u, 0 256 u, b> // data: dict dict dict grams uint32 uint256
|
||||
empty_cell // libraries
|
||||
GR$10 // balance: 10 grams
|
||||
GR$500 // balance: 500 grams
|
||||
0 // split_depth
|
||||
2 // ticktock: tick
|
||||
AllOnes 3 * // address: -1:333...333
|
||||
|
@ -196,7 +144,7 @@ config.special!
|
|||
triple dup untriple config.mc_block_limits!
|
||||
untriple config.block_limits!
|
||||
|
||||
GR$1.7 GR$1 config.block_create_fees!
|
||||
GR$160 GR$100 config.block_create_fees!
|
||||
// smc1_addr config.collector_smc!
|
||||
smc1_addr config.minter_smc!
|
||||
|
||||
|
@ -214,14 +162,26 @@ config.param_proposals_setup!
|
|||
// deposit bit_pps cell_pps
|
||||
GR$100 1 500 config.complaint_prices!
|
||||
|
||||
"validator-keys" +suffix +".pub" file>B
|
||||
{ dup Blen } { 32 B| swap dup ."Validator public key = " Bx. cr
|
||||
17 add-validator } while drop
|
||||
{ file>B { dup Blen } {
|
||||
32 B| swap dup ."Validator public key = " Bx. cr
|
||||
17 add-validator
|
||||
} while drop
|
||||
} : load-keys-from-file
|
||||
|
||||
false =: keys-from-file
|
||||
keys-from-file
|
||||
{ "validator-keys" +suffix +".pub" load-keys-from-file
|
||||
} {
|
||||
VPK'xrQTSOn2F9RjLgeHdSS0uIvde4Lv49l+/KXfJe0I7wYatz6e
|
||||
B64{8E9AbL8blhRiBUoZt/b/vIo3+iZzglLKiL8MTf0g6Sg=} 256 B>u@
|
||||
1 add-adnl-validator
|
||||
} cond
|
||||
// newkeypair nip dup ."Validator #1 public key = " Bx. cr
|
||||
// 17 add-validator
|
||||
// newkeypair nip dup ."Validator #2 public key = " Bx. cr
|
||||
// 239 add-validator
|
||||
100000 =: orig_vset_valid_for // original validator set valid 100000 seconds
|
||||
|
||||
3000 =: orig_vset_valid_for // original validator set valid 3000 seconds
|
||||
now dup orig_vset_valid_for + 0 config.validators!
|
||||
|
||||
/*
|
||||
|
@ -237,24 +197,14 @@ now dup orig_vset_valid_for + 0 config.validators!
|
|||
dictnew dict, // vote dict
|
||||
b> // data
|
||||
empty_cell // libraries
|
||||
GR$10 // balance
|
||||
GR$500 // balance
|
||||
0 1 config_addr 6 register_smc // tock
|
||||
dup set_config_smc
|
||||
Masterchain swap
|
||||
."config smart contract address = " 2dup .addr cr 2dup 7 .Addr cr
|
||||
"config-master" +suffix +".addr" save-address-verbose
|
||||
// Other data
|
||||
|
||||
/*
|
||||
*
|
||||
* Initial wallets (test)
|
||||
*
|
||||
*/
|
||||
|
||||
// pubkey amount `create-wallet1` or pubkey amount `create-wallet2`
|
||||
PK'PuZPPXK5Rff9SvtoS7Y9lUuEixvy-J6aishYFj3Qn6P0pJMb GR$1000000000 create-wallet1
|
||||
PK'PuYiB1zAWzr4p8j6I681+sGUrRGcn6Ylf7vXl0xaUl/w6Xfg GR$1700000000 create-wallet0
|
||||
|
||||
/*
|
||||
*
|
||||
* Create state
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
null =: subwallet-id
|
||||
86400 =: expires-in
|
||||
now =: start-at
|
||||
0x5EA62080 =: start-at
|
||||
0x4BA92D8A =: subwallet-base
|
||||
// 0x11EF55AA =: subwallet-base
|
||||
|
||||
begin-options
|
||||
" <creator-filename-base> <public-key> <amount> [-w<workchain>][-r<restrict-mode>][-i<subwallet-id>][-t<start-at>] [<savefile>]" +cr +tab
|
||||
|
@ -27,8 +26,8 @@ begin-options
|
|||
"x" "--expires-in" { parse-int =: expires-in } short-long-option-arg
|
||||
"Expiration time of the initialization message (" expires-in (.) $+
|
||||
+" seconds by default)" option-help
|
||||
"t" "--start-at" { parse-int =: start-at } short-long-option-arg
|
||||
"Restriction start Unixtime (now by default)" option-help
|
||||
"t" "--start-at" { dup "now" $= { drop now } { parse-int } cond =: start-at } short-long-option-arg
|
||||
"Restriction start Unixtime (`now` by default)" option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
@ -50,7 +49,7 @@ wc 8 fits not abort"invalid workchain id"
|
|||
subwallet-id 32 fits not abort"invalid subwallet-id"
|
||||
expires-at 32 ufits not abort"invalid expiration time"
|
||||
start-at 32 ufits not abort"invalid restriction start time"
|
||||
restrict-mode dup 1 < swap 2 > or abort"unknown restriction mode"
|
||||
restrict-mode dup 0 < swap 2 > or abort"unknown restriction mode"
|
||||
filename-base +".pk" load-keypair =: init_pk =: init_pubkey
|
||||
|
||||
."Creating new restricted lockup wallet v3 in workchain " wc .
|
||||
|
@ -79,9 +78,16 @@ filename-base +".pk" load-keypair =: init_pk =: init_pubkey
|
|||
swap .2225 */ 3 years* rdict-entry
|
||||
0 4 years* 86400 + rdict-entry
|
||||
} : make-rdict2
|
||||
{ dictnew
|
||||
swap 31 -1<< rdict-entry
|
||||
0 0 rdict-entry
|
||||
} : make-rdict0
|
||||
|
||||
amount
|
||||
restrict-mode 1 = { make-rdict1 } { make-rdict2 } cond =: rdict
|
||||
restrict-mode ?dup {
|
||||
1 = { make-rdict1 } { make-rdict2 } cond
|
||||
} { make-rdict0 } cond
|
||||
=: rdict
|
||||
|
||||
."Restrictions start at " start-at ._ .": " cr
|
||||
rdict 32 { swap . ."-> " Gram@ .GR cr true } idictforeach cr
|
||||
|
|
|
@ -17,29 +17,8 @@ $3 "new-wallet" replace-if-null =: file-base
|
|||
."with unique wallet id " subwallet-id . cr
|
||||
|
||||
// Create new advanced wallet; code adapted from `auto/wallet3-code.fif`
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
|
||||
1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs
|
||||
NOW s1 s3 XCHG LEQ 35 THROWIF // signature in_msg subwallet_id cs msg_seqno
|
||||
c4 PUSH CTOS 32 LDU 32 LDU 256 LDU ENDS // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key
|
||||
s3 s2 XCPU EQUAL 33 THROWIFNOT // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet
|
||||
s4 s4 XCPU EQUAL 34 THROWIFNOT // signature in_msg stored_subwallet cs public_key stored_seqno
|
||||
s0 s4 XCHG HASHSU // signature stored_seqno stored_subwallet cs public_key msg_hash
|
||||
s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs msg_hash signature public_key
|
||||
CHKSIGNU 35 THROWIFNOT // public_key stored_seqno stored_subwallet cs
|
||||
ACCEPT
|
||||
WHILE:<{
|
||||
DUP SREFS // public_key stored_seqno stored_subwallet cs _51
|
||||
}>DO<{ // public_key stored_seqno stored_subwallet cs
|
||||
8 LDU LDREF s0 s2 XCHG // public_key stored_seqno stored_subwallet cs _56 mode
|
||||
SENDRAWMSG
|
||||
}> // public_key stored_seqno stored_subwallet cs
|
||||
ENDS SWAP INC // public_key stored_subwallet seqno'
|
||||
NEWC 32 STU 32 STU 256 STU ENDC c4 POP
|
||||
}>c // >libref
|
||||
"wallet-v3-code.fif" include
|
||||
// >libref
|
||||
// code
|
||||
<b 0 32 u, subwallet-id 32 u,
|
||||
file-base +".pk" load-generate-keypair
|
||||
|
|
27
crypto/smartcont/wallet-v3-code.fif
Normal file
27
crypto/smartcont/wallet-v3-code.fif
Normal file
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/fift -s
|
||||
"Asm.fif" include
|
||||
|
||||
// New advanced wallet code adapted from `auto/wallet3-code.fif`
|
||||
<{ SETCP0 DUP IFNOTRET // return if recv_internal
|
||||
DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods
|
||||
1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk
|
||||
}>
|
||||
INC 32 THROWIF // fail unless recv_external
|
||||
9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs
|
||||
NOW s1 s3 XCHG LEQ 35 THROWIF // signature in_msg subwallet_id cs msg_seqno
|
||||
c4 PUSH CTOS 32 LDU 32 LDU 256 LDU ENDS // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key
|
||||
s3 s2 XCPU EQUAL 33 THROWIFNOT // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet
|
||||
s4 s4 XCPU EQUAL 34 THROWIFNOT // signature in_msg stored_subwallet cs public_key stored_seqno
|
||||
s0 s4 XCHG HASHSU // signature stored_seqno stored_subwallet cs public_key msg_hash
|
||||
s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs msg_hash signature public_key
|
||||
CHKSIGNU 35 THROWIFNOT // public_key stored_seqno stored_subwallet cs
|
||||
ACCEPT
|
||||
WHILE:<{
|
||||
DUP SREFS // public_key stored_seqno stored_subwallet cs _51
|
||||
}>DO<{ // public_key stored_seqno stored_subwallet cs
|
||||
8 LDU LDREF s0 s2 XCHG // public_key stored_seqno stored_subwallet cs _56 mode
|
||||
SENDRAWMSG
|
||||
}> // public_key stored_seqno stored_subwallet cs
|
||||
ENDS SWAP INC // public_key stored_subwallet seqno'
|
||||
NEWC 32 STU 32 STU 256 STU ENDC c4 POP
|
||||
}>c
|
|
@ -663,6 +663,32 @@ bool TestNode::parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr
|
|||
return block::parse_std_account_addr(word, wc, addr) || set_error("cannot parse account address");
|
||||
}
|
||||
|
||||
bool TestNode::parse_account_addr_ext(ton::WorkchainId& wc, ton::StdSmcAddress& addr, int& addr_ext, bool allow_none) {
|
||||
addr_ext = 0;
|
||||
auto word = get_word();
|
||||
if (allow_none && (word == "none" || word == "root")) {
|
||||
wc = ton::workchainInvalid;
|
||||
return true;
|
||||
}
|
||||
if (word == "config" || word == "elector" || word == "dnsroot") {
|
||||
wc = ton::masterchainId;
|
||||
addr.set_zero();
|
||||
addr_ext = 1 + (word == "elector") + (word == "dnsroot") * 2;
|
||||
if (addr_ext == 1 && config_addr_queried_) {
|
||||
addr = config_addr_;
|
||||
addr_ext = 0;
|
||||
} else if (addr_ext == 2 && elect_addr_queried_) {
|
||||
addr = elect_addr_;
|
||||
addr_ext = 0;
|
||||
} else if (addr_ext == 3 && dns_root_queried_) {
|
||||
addr = dns_root_;
|
||||
addr_ext = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return block::parse_std_account_addr(word, wc, addr) || set_error("cannot parse account address");
|
||||
}
|
||||
|
||||
bool TestNode::convert_uint64(td::Slice word, td::uint64& val) {
|
||||
val = ~0ULL;
|
||||
if (word.empty()) {
|
||||
|
@ -958,6 +984,7 @@ bool TestNode::show_help(std::string command) {
|
|||
|
||||
bool TestNode::do_parse_line() {
|
||||
ton::WorkchainId workchain = ton::masterchainId; // change to basechain later
|
||||
int addr_ext = 0;
|
||||
ton::StdSmcAddress addr{};
|
||||
ton::BlockIdExt blkid{};
|
||||
ton::LogicalTime lt{};
|
||||
|
@ -977,21 +1004,22 @@ bool TestNode::do_parse_line() {
|
|||
} else if (word == "sendfile") {
|
||||
return !eoln() && set_error(send_ext_msg_from_filename(get_line_tail()));
|
||||
} else if (word == "getaccount") {
|
||||
return parse_account_addr(workchain, addr) &&
|
||||
(seekeoln() ? get_account_state(workchain, addr, mc_last_id_)
|
||||
: parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid));
|
||||
return parse_account_addr_ext(workchain, addr, addr_ext) &&
|
||||
(seekeoln()
|
||||
? get_account_state(workchain, addr, mc_last_id_, addr_ext)
|
||||
: parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, addr_ext));
|
||||
} else if (word == "saveaccount" || word == "saveaccountcode" || word == "saveaccountdata") {
|
||||
std::string filename;
|
||||
int mode = ((word.c_str()[11] >> 1) & 3);
|
||||
return get_word_to(filename) && parse_account_addr(workchain, addr) &&
|
||||
(seekeoln()
|
||||
? get_account_state(workchain, addr, mc_last_id_, filename, mode)
|
||||
: parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, filename, mode));
|
||||
return get_word_to(filename) && parse_account_addr_ext(workchain, addr, addr_ext) &&
|
||||
(seekeoln() ? get_account_state(workchain, addr, mc_last_id_, addr_ext, filename, mode)
|
||||
: parse_block_id_ext(blkid) && seekeoln() &&
|
||||
get_account_state(workchain, addr, blkid, addr_ext, filename, mode));
|
||||
} else if (word == "runmethod" || word == "runmethodx" || word == "runmethodfull") {
|
||||
std::string method;
|
||||
return parse_account_addr(workchain, addr) && get_word_to(method) &&
|
||||
return parse_account_addr_ext(workchain, addr, addr_ext) && get_word_to(method) &&
|
||||
(parse_block_id_ext(method, blkid) ? get_word_to(method) : (blkid = mc_last_id_).is_valid()) &&
|
||||
parse_run_method(workchain, addr, blkid, method, word.size() <= 10);
|
||||
parse_run_method(workchain, addr, blkid, addr_ext, method, word.size() <= 10);
|
||||
} else if (word == "dnsresolve" || word == "dnsresolvestep") {
|
||||
workchain = ton::workchainInvalid;
|
||||
bool step = (word.size() > 10);
|
||||
|
@ -1141,13 +1169,22 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) {
|
|||
}
|
||||
|
||||
bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string filename, int mode) {
|
||||
int addr_ext, std::string filename, int mode) {
|
||||
if (!ref_blkid.is_valid()) {
|
||||
return set_error("must obtain last block information before making other queries");
|
||||
}
|
||||
if (!(ready_ && !client_.empty())) {
|
||||
return set_error("server connection not ready");
|
||||
}
|
||||
if (addr_ext) {
|
||||
return get_special_smc_addr(addr_ext, [this, ref_blkid, filename, mode](td::Result<ton::StdSmcAddress> res) {
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << "cannot resolve special smart contract address: " << res.move_as_error();
|
||||
} else {
|
||||
get_account_state(ton::masterchainId, res.move_as_ok(), ref_blkid, 0, filename, mode);
|
||||
}
|
||||
});
|
||||
}
|
||||
auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
|
||||
auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
|
||||
ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
|
||||
|
@ -1190,12 +1227,27 @@ bool TestNode::cache_cell(Ref<vm::Cell> cell) {
|
|||
}
|
||||
|
||||
bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, bool ext_mode) {
|
||||
int addr_ext, std::string method_name, bool ext_mode) {
|
||||
auto R = vm::parse_stack_entries(td::Slice(parse_ptr_, parse_end_));
|
||||
if (R.is_error()) {
|
||||
return set_error(R.move_as_error().to_string());
|
||||
}
|
||||
parse_ptr_ = parse_end_;
|
||||
if (addr_ext) {
|
||||
return get_special_smc_addr(addr_ext, [this, ref_blkid, method_name, ext_mode,
|
||||
args = R.move_as_ok()](td::Result<ton::StdSmcAddress> res) mutable {
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << "cannot resolve special smart contract address: " << res.move_as_error();
|
||||
} else {
|
||||
after_parse_run_method(ton::masterchainId, res.move_as_ok(), ref_blkid, method_name, std::move(args), ext_mode);
|
||||
}
|
||||
});
|
||||
}
|
||||
return after_parse_run_method(workchain, addr, ref_blkid, method_name, R.move_as_ok(), ext_mode);
|
||||
}
|
||||
|
||||
bool TestNode::after_parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, std::vector<vm::StackEntry> params, bool ext_mode) {
|
||||
auto P = td::PromiseCreator::lambda([this](td::Result<std::vector<vm::StackEntry>> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << R.move_as_error();
|
||||
|
@ -1209,7 +1261,8 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
|
|||
}
|
||||
}
|
||||
});
|
||||
return start_run_method(workchain, addr, ref_blkid, method_name, R.move_as_ok(), ext_mode ? 0x1f : 0, std::move(P));
|
||||
return start_run_method(workchain, addr, ref_blkid, method_name, std::move(params), ext_mode ? 0x1f : 0,
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
|
@ -1293,6 +1346,23 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
|
|||
}
|
||||
}
|
||||
|
||||
bool TestNode::get_config_addr(td::Promise<ton::StdSmcAddress> promise) {
|
||||
if (config_addr_queried_) {
|
||||
promise.set_result(config_addr_);
|
||||
return true;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([this, promise = std::move(promise)](
|
||||
td::Result<std::unique_ptr<block::Config>> R) mutable {
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, config, std::move(R), "cannot obtain configurator address from configuration:");
|
||||
if (config_addr_queried_) {
|
||||
promise.set_result(config_addr_);
|
||||
} else {
|
||||
promise.set_error(td::Status::Error("cannot obtain configurator address from configuration parameter #0"));
|
||||
}
|
||||
});
|
||||
return get_config_params(mc_last_id_, std::move(P), 0x3000, "", {0});
|
||||
}
|
||||
|
||||
bool TestNode::get_elector_addr(td::Promise<ton::StdSmcAddress> promise) {
|
||||
if (elect_addr_queried_) {
|
||||
promise.set_result(elect_addr_);
|
||||
|
@ -1310,6 +1380,37 @@ bool TestNode::get_elector_addr(td::Promise<ton::StdSmcAddress> promise) {
|
|||
return get_config_params(mc_last_id_, std::move(P), 0x3000, "", {1});
|
||||
}
|
||||
|
||||
bool TestNode::get_dns_root(td::Promise<ton::StdSmcAddress> promise) {
|
||||
if (dns_root_queried_) {
|
||||
promise.set_result(dns_root_);
|
||||
return true;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[this, promise = std::move(promise)](td::Result<std::unique_ptr<block::Config>> R) mutable {
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, config, std::move(R), "cannot obtain dns root address from configuration:");
|
||||
if (dns_root_queried_) {
|
||||
promise.set_result(dns_root_);
|
||||
} else {
|
||||
promise.set_error(td::Status::Error("cannot obtain dns root address from configuration parameter #4"));
|
||||
}
|
||||
});
|
||||
return get_config_params(mc_last_id_, std::move(P), 0x3000, "", {4});
|
||||
}
|
||||
|
||||
bool TestNode::get_special_smc_addr(int addr_ext, td::Promise<ton::StdSmcAddress> promise) {
|
||||
switch (addr_ext) {
|
||||
case 1:
|
||||
return get_config_addr(std::move(promise));
|
||||
case 2:
|
||||
return get_elector_addr(std::move(promise));
|
||||
case 3:
|
||||
return get_dns_root(std::move(promise));
|
||||
default:
|
||||
promise.set_error(td::Status::Error(PSLICE() << "unknown special smart contract address class " << addr_ext));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestNode::get_past_validator_sets() {
|
||||
return get_elector_addr([this](td::Result<ton::StdSmcAddress> res) {
|
||||
if (res.is_error()) {
|
||||
|
@ -1427,7 +1528,7 @@ void TestNode::save_complaints(unsigned elect_id, Ref<vm::Cell> complaints, std:
|
|||
}
|
||||
LOG(DEBUG) << "saved " << len << " bytes into file `" << filename << "`";
|
||||
td::TerminalIO::out() << "SAVE_COMPLAINT\t" << elect_id << '\t' << entry.first.to_hex(256) << '\t'
|
||||
<< rec2.validator_pubkey.to_hex() << '\t' << rec2.created_at << '\t' << filename;
|
||||
<< rec2.validator_pubkey.to_hex() << '\t' << rec2.created_at << '\t' << filename << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2609,12 +2710,15 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, int mode, std::strin
|
|||
}
|
||||
|
||||
bool TestNode::register_config_param(int idx, Ref<vm::Cell> value) {
|
||||
if (idx == 1) {
|
||||
return register_config_param1(std::move(value));
|
||||
} else if (idx == 4) {
|
||||
return register_config_param4(std::move(value));
|
||||
} else {
|
||||
return true;
|
||||
switch (idx) {
|
||||
case 0:
|
||||
return register_config_param0(std::move(value));
|
||||
case 1:
|
||||
return register_config_param1(std::move(value));
|
||||
case 4:
|
||||
return register_config_param4(std::move(value));
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2654,6 +2758,24 @@ bool TestNode::register_config_param1(Ref<vm::Cell> value) {
|
|||
}
|
||||
}
|
||||
|
||||
bool TestNode::register_config_param0(Ref<vm::Cell> value) {
|
||||
if (value.is_null()) {
|
||||
return false;
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd(), std::move(value)};
|
||||
ton::StdSmcAddress addr;
|
||||
if (cs.size_ext() == 256 && cs.fetch_bits_to(addr)) {
|
||||
config_addr_queried_ = true;
|
||||
if (config_addr_ != addr) {
|
||||
config_addr_ = addr;
|
||||
LOG(INFO) << "configuration smart contract address set to -1:" << addr.to_hex();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestNode::get_block(ton::BlockIdExt blkid, bool dump) {
|
||||
LOG(INFO) << "got block download request for " << blkid.to_str();
|
||||
auto b = ton::serialize_tl_object(
|
||||
|
|
|
@ -68,8 +68,8 @@ class TestNode : public td::actor::Actor {
|
|||
ton::BlockIdExt last_block_id_, last_state_id_;
|
||||
td::BufferSlice last_block_data_, last_state_data_;
|
||||
|
||||
ton::StdSmcAddress dns_root_, elect_addr_;
|
||||
bool dns_root_queried_{false}, elect_addr_queried_{false};
|
||||
ton::StdSmcAddress dns_root_, elect_addr_, config_addr_;
|
||||
bool dns_root_queried_{false}, elect_addr_queried_{false}, config_addr_queried_{false};
|
||||
|
||||
std::string line_;
|
||||
const char *parse_ptr_, *parse_end_;
|
||||
|
@ -191,12 +191,14 @@ class TestNode : public td::actor::Actor {
|
|||
td::Status send_ext_msg_from_filename(std::string filename);
|
||||
td::Status save_db_file(ton::FileHash file_hash, td::BufferSlice data);
|
||||
bool get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string filename = "", int mode = -1);
|
||||
int addr_ext = 0, std::string filename = "", int mode = -1);
|
||||
void got_account_state(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
|
||||
td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
|
||||
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string filename, int mode);
|
||||
bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, int addr_ext,
|
||||
std::string method_name, bool ext_mode);
|
||||
bool after_parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, std::vector<vm::StackEntry> params, bool ext_mode);
|
||||
bool start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, std::vector<vm::StackEntry> params, int mode,
|
||||
td::Promise<std::vector<vm::StackEntry>> promise);
|
||||
|
@ -207,6 +209,7 @@ class TestNode : public td::actor::Actor {
|
|||
td::BufferSlice remote_result, int remote_exit_code,
|
||||
td::Promise<std::vector<vm::StackEntry>> promise);
|
||||
bool register_config_param(int idx, Ref<vm::Cell> value);
|
||||
bool register_config_param0(Ref<vm::Cell> value);
|
||||
bool register_config_param1(Ref<vm::Cell> value);
|
||||
bool register_config_param4(Ref<vm::Cell> value);
|
||||
bool dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
|
||||
|
@ -283,7 +286,10 @@ class TestNode : public td::actor::Actor {
|
|||
ton::Bits256 vset_hash = ton::Bits256::zero());
|
||||
td::Status continue_check_validator_load_proof(std::unique_ptr<ValidatorLoadInfo> info1,
|
||||
std::unique_ptr<ValidatorLoadInfo> info2, Ref<vm::Cell> root);
|
||||
bool get_config_addr(td::Promise<ton::StdSmcAddress> promise);
|
||||
bool get_elector_addr(td::Promise<ton::StdSmcAddress> promise);
|
||||
bool get_dns_root(td::Promise<ton::StdSmcAddress> promise);
|
||||
bool get_special_smc_addr(int addr_ext, td::Promise<ton::StdSmcAddress> promise);
|
||||
bool get_past_validator_sets();
|
||||
bool send_past_vset_query(ton::StdSmcAddress elector_addr);
|
||||
void register_past_vset_info(vm::StackEntry list);
|
||||
|
@ -313,6 +319,7 @@ class TestNode : public td::actor::Actor {
|
|||
bool set_error(std::string err_msg);
|
||||
void show_context() const;
|
||||
bool parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr, bool allow_none = false);
|
||||
bool parse_account_addr_ext(ton::WorkchainId& wc, ton::StdSmcAddress& addr, int& addr_ext, bool allow_none = false);
|
||||
static int parse_hex_digit(int c);
|
||||
static bool parse_hash(const char* str, ton::Bits256& hash);
|
||||
static bool parse_hash(td::Slice str, ton::Bits256& hash);
|
||||
|
|
|
@ -649,6 +649,7 @@ engine.validator.setVerbosity verbosity:int = engine.validator.Success;
|
|||
|
||||
engine.validator.createElectionBid election_date:int election_addr:string wallet:string = engine.validator.ElectionBid;
|
||||
engine.validator.createProposalVote vote:bytes = engine.validator.ProposalVote;
|
||||
engine.validator.createComplaintVote election_id:int vote:bytes = engine.validator.ProposalVote;
|
||||
|
||||
engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus;
|
||||
|
||||
|
|
Binary file not shown.
|
@ -678,6 +678,29 @@ td::Status CreateProposalVoteQuery::receive(td::BufferSlice data) {
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status CreateComplaintVoteQuery::run() {
|
||||
TRY_RESULT_ASSIGN(election_id_, tokenizer_.get_token<td::uint32>());
|
||||
TRY_RESULT_ASSIGN(data_, tokenizer_.get_token<std::string>());
|
||||
TRY_RESULT_ASSIGN(fname_, tokenizer_.get_token<std::string>());
|
||||
TRY_STATUS(tokenizer_.check_endl());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status CreateComplaintVoteQuery::send() {
|
||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_createComplaintVote>(election_id_,
|
||||
td::BufferSlice(data_));
|
||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status CreateComplaintVoteQuery::receive(td::BufferSlice data) {
|
||||
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_proposalVote>(data.as_slice(), true),
|
||||
"received incorrect answer: ");
|
||||
td::TerminalIO::out() << "success: permkey=" << f->perm_key_.to_hex() << "\n";
|
||||
TRY_STATUS(td::write_file(fname_, f->to_send_.as_slice()));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status CheckDhtServersQuery::run() {
|
||||
TRY_RESULT_ASSIGN(id_, tokenizer_.get_token<ton::PublicKeyHash>());
|
||||
return td::Status::OK();
|
||||
|
|
|
@ -858,6 +858,30 @@ class CreateProposalVoteQuery : public Query {
|
|||
std::string fname_;
|
||||
};
|
||||
|
||||
class CreateComplaintVoteQuery : public Query {
|
||||
public:
|
||||
CreateComplaintVoteQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||
: Query(console, std::move(tokenizer)) {
|
||||
}
|
||||
td::Status run() override;
|
||||
td::Status send() override;
|
||||
td::Status receive(td::BufferSlice data) override;
|
||||
static std::string get_name() {
|
||||
return "createcomplaintvote";
|
||||
}
|
||||
static std::string get_help() {
|
||||
return "createcomplaintvote <election-id> <data> <fname>\tcreate proposal vote";
|
||||
}
|
||||
std::string name() const override {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
private:
|
||||
td::uint32 election_id_;
|
||||
std::string data_;
|
||||
std::string fname_;
|
||||
};
|
||||
|
||||
class CheckDhtServersQuery : public Query {
|
||||
public:
|
||||
CheckDhtServersQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||
|
|
|
@ -131,6 +131,7 @@ void ValidatorEngineConsole::run() {
|
|||
add_query_runner(std::make_unique<QueryRunnerImpl<AddNetworkProxyAddressQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<CreateElectionBidQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<CreateProposalVoteQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<CreateComplaintVoteQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<CheckDhtServersQuery>>());
|
||||
}
|
||||
|
||||
|
|
|
@ -956,9 +956,131 @@ class ValidatorProposalVoteCreator : public td::actor::Actor {
|
|||
|
||||
td::Promise<td::BufferSlice> promise_;
|
||||
|
||||
td::uint32 ttl_;
|
||||
AdnlCategory cat_ = 2;
|
||||
double frac = 2.7;
|
||||
ton::PublicKeyHash perm_key_;
|
||||
ton::PublicKey perm_key_full_;
|
||||
ton::adnl::AdnlNodeIdShort adnl_addr_;
|
||||
ton::adnl::AdnlNodeIdFull adnl_key_full_;
|
||||
};
|
||||
|
||||
class ValidatorPunishVoteCreator : public td::actor::Actor {
|
||||
public:
|
||||
ValidatorPunishVoteCreator(td::uint32 election_id, td::BufferSlice proposal, std::string dir,
|
||||
td::actor::ActorId<ValidatorEngine> engine,
|
||||
td::actor::ActorId<ton::keyring::Keyring> keyring, td::Promise<td::BufferSlice> promise)
|
||||
: election_id_(election_id)
|
||||
, proposal_(std::move(proposal))
|
||||
, dir_(std::move(dir))
|
||||
, engine_(engine)
|
||||
, keyring_(keyring)
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::pair<ton::PublicKey, size_t>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ValidatorPunishVoteCreator::abort_query,
|
||||
R.move_as_error_prefix("failed to find self permanent key: "));
|
||||
} else {
|
||||
auto v = R.move_as_ok();
|
||||
td::actor::send_closure(SelfId, &ValidatorPunishVoteCreator::got_id, v.first, v.second);
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(engine_, &ValidatorEngine::get_current_validator_perm_key, std::move(P));
|
||||
}
|
||||
|
||||
void got_id(ton::PublicKey pubkey, size_t idx) {
|
||||
pubkey_ = std::move(pubkey);
|
||||
idx_ = idx;
|
||||
auto codeR = td::read_file_str(dir_ + "/complaint-vote-req.fif");
|
||||
if (codeR.is_error()) {
|
||||
abort_query(codeR.move_as_error_prefix("fif not found (complaint-vote-req.fif)"));
|
||||
return;
|
||||
}
|
||||
auto data = proposal_.as_slice().str();
|
||||
auto R = fift::mem_run_fift(codeR.move_as_ok(),
|
||||
{"complaint-vote-req.fif", td::to_string(idx_), td::to_string(election_id_), data},
|
||||
dir_ + "/");
|
||||
if (R.is_error()) {
|
||||
abort_query(R.move_as_error_prefix("fift fail (complaint-vote-req.fif)"));
|
||||
return;
|
||||
}
|
||||
auto res = R.move_as_ok();
|
||||
auto to_signR = res.source_lookup.read_file("validator-to-sign.req");
|
||||
if (to_signR.is_error()) {
|
||||
abort_query(td::Status::Error(PSTRING() << "strange error: no to sign file. Output: " << res.output));
|
||||
return;
|
||||
}
|
||||
auto to_sign = td::BufferSlice{to_signR.move_as_ok().data};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ValidatorPunishVoteCreator::abort_query,
|
||||
R.move_as_error_prefix("sign fail: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidatorPunishVoteCreator::signed_vote, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_message, pubkey_.compute_short_id(),
|
||||
std::move(to_sign), std::move(P));
|
||||
}
|
||||
|
||||
void signed_vote(td::BufferSlice signature) {
|
||||
signature_ = std::move(signature);
|
||||
|
||||
auto codeR = td::read_file_str(dir_ + "/complaint-vote-signed.fif");
|
||||
if (codeR.is_error()) {
|
||||
abort_query(codeR.move_as_error_prefix("fif not found (complaint-vote-signed.fif)"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto key = td::base64_encode(pubkey_.export_as_slice().as_slice());
|
||||
auto sig = td::base64_encode(signature_.as_slice());
|
||||
|
||||
auto data = proposal_.as_slice().str();
|
||||
auto R = fift::mem_run_fift(
|
||||
codeR.move_as_ok(),
|
||||
{"complaint-vote-signed.fif", td::to_string(idx_), td::to_string(election_id_), data, key, sig}, dir_ + "/");
|
||||
if (R.is_error()) {
|
||||
abort_query(R.move_as_error_prefix("fift fail (complaint-vote-signed.fif)"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto res = R.move_as_ok();
|
||||
auto dataR = res.source_lookup.read_file("vote-query.boc");
|
||||
if (dataR.is_error()) {
|
||||
abort_query(td::Status::Error("strage error: no result boc"));
|
||||
return;
|
||||
}
|
||||
|
||||
result_ = td::BufferSlice(dataR.move_as_ok().data);
|
||||
finish_query();
|
||||
}
|
||||
|
||||
void abort_query(td::Status error) {
|
||||
promise_.set_value(ValidatorEngine::create_control_query_error(std::move(error)));
|
||||
stop();
|
||||
}
|
||||
void finish_query() {
|
||||
promise_.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_proposalVote>(
|
||||
pubkey_.compute_short_id().bits256_value(), std::move(result_)));
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
td::uint32 election_id_;
|
||||
td::BufferSlice proposal_;
|
||||
std::string dir_;
|
||||
|
||||
ton::PublicKey pubkey_;
|
||||
size_t idx_;
|
||||
|
||||
td::BufferSlice signature_;
|
||||
td::BufferSlice result_;
|
||||
td::actor::ActorId<ValidatorEngine> engine_;
|
||||
td::actor::ActorId<ton::keyring::Keyring> keyring_;
|
||||
|
||||
td::Promise<td::BufferSlice> promise_;
|
||||
|
||||
ton::PublicKeyHash perm_key_;
|
||||
ton::PublicKey perm_key_full_;
|
||||
|
@ -2988,6 +3110,32 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_createPro
|
|||
.release();
|
||||
}
|
||||
|
||||
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_createComplaintVote &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
||||
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
||||
return;
|
||||
}
|
||||
if (keyring_.empty()) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "keyring not started")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!started_) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fift_dir_.empty()) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "no fift dir")));
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::create_actor<ValidatorPunishVoteCreator>("votecomplaintcreate", query.election_id_, std::move(query.vote_),
|
||||
fift_dir_, actor_id(this), keyring_.get(), std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
|
||||
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -385,6 +385,8 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_createProposalVote &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_createComplaintVote &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
template <class T>
|
||||
void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -1507,14 +1507,9 @@ const ValidatorSessionState* ValidatorSessionState::make_one(ValidatorSessionDes
|
|||
return state;
|
||||
}
|
||||
made = true;
|
||||
auto old = state->old_rounds_;
|
||||
if (made && round->check_block_is_signed(desc)) {
|
||||
old = CntVector<const ValidatorSessionOldRoundState*>::push(desc, old, round->get_seqno(),
|
||||
ValidatorSessionOldRoundState::create(desc, round));
|
||||
round = ValidatorSessionRoundState::create(desc, round->get_seqno());
|
||||
}
|
||||
CHECK(!round->check_block_is_signed(desc));
|
||||
|
||||
return ValidatorSessionState::create(desc, std::move(ts_vec), std::move(old), std::move(round));
|
||||
return ValidatorSessionState::create(desc, std::move(ts_vec), state->old_rounds_, std::move(round));
|
||||
}
|
||||
|
||||
const SentBlock* ValidatorSessionState::get_committed_block(ValidatorSessionDescription& desc, td::uint32 seqno) const {
|
||||
|
|
Loading…
Reference in a new issue