mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
bugfixed + crypto update
- compiles vs BoringSSL - config proposal/vote fift code - bugfixes in catchain - other small fixes
This commit is contained in:
parent
606e970ed5
commit
a31f8d4424
39 changed files with 722 additions and 132 deletions
|
@ -40,6 +40,9 @@
|
|||
{ <b x{c4} s, rot 32 u, swap 64 u, b> 8 config! } : config.version!
|
||||
1 constant capIhr
|
||||
2 constant capCreateStats
|
||||
4 constant capBounceMsgBody
|
||||
8 constant capReportVersion
|
||||
16 constant capSplitMergeTransactions
|
||||
|
||||
// max-validators masterchain-validators min-validators --
|
||||
{ swap rot <b swap 16 u, swap 16 u, swap 16 u, b> 16 config! } : config.validator_num!
|
||||
|
@ -54,21 +57,24 @@
|
|||
|
||||
variable validator-dict
|
||||
dictnew 0 validator-dict 2!
|
||||
variable validators-weight
|
||||
validators-weight 0!
|
||||
|
||||
{ validator-dict @ second } : validator#
|
||||
// val-pubkey weight --
|
||||
{ dup 0<= abort"validator weight must be non-negative"
|
||||
dup 64 ufits not abort"validator weight must fit into 64 bits"
|
||||
over Blen 32 <> abort"validator public key must be 32 bytes long"
|
||||
<b x{538e81278a} s, rot B, swap 64 u, b> <s
|
||||
tuck <b x{538e81278a} s, rot B, swap 64 u, b> <s
|
||||
validator-dict 2@ dup 1+ 3 -roll swap
|
||||
16 udict!+ 0= abort"cannot add validator"
|
||||
swap validator-dict 2!
|
||||
swap validator-dict 2! validators-weight +!
|
||||
} : add-validator
|
||||
// since-ut until-ut main-val-cnt-or-0 --
|
||||
{ ?dup 0= { validator# } if
|
||||
validator# 0= abort"no initial validators defined"
|
||||
rot <b x{11} s, swap 32 u, rot 32 u, validator# 16 u, swap 16 u,
|
||||
validator-dict @ first <s s, b>
|
||||
rot <b x{12} s, swap 32 u, rot 32 u, validator# 16 u, swap 16 u,
|
||||
validators-weight @ 64 u, validator-dict @ first dict, b>
|
||||
34 config!
|
||||
} : config.validators!
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ _ get_vote_config(int critical?) inline_ref {
|
|||
() after_code_upgrade(slice param, cont old_code) impure method_id(1666) {
|
||||
}
|
||||
|
||||
_ perform_action(cfg_dict, public_key, action, cs) {
|
||||
_ perform_action(cfg_dict, public_key, action, cs) inline_ref {
|
||||
if (action == 0x43665021) {
|
||||
;; change one configuration parameter
|
||||
var param_index = cs~load_int(32);
|
||||
|
@ -166,6 +166,58 @@ _ perform_action(cfg_dict, public_key, action, cs) {
|
|||
return (id, val, hash);
|
||||
}
|
||||
|
||||
(cell, int, cell) accept_proposal(cell cfg_dict, cell proposal, int critical?) inline_ref {
|
||||
var (param_id, param_val, req_hash) = parse_config_proposal(proposal);
|
||||
cell cur_val = cfg_dict.idict_get_ref(32, param_id);
|
||||
int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val);
|
||||
if ((cur_hash != req_hash) & (req_hash >= 0)) {
|
||||
;; current value has incorrect hash, do not apply changes
|
||||
return (cfg_dict, 0, null());
|
||||
}
|
||||
cell mparams = cfg_dict.idict_get_ref(32, 9); ;; mandatory parameters
|
||||
var (_, found?) = mparams.idict_get?(32, param_id);
|
||||
if (found? & param_val.null?()) {
|
||||
;; cannot set a mandatory parameter to (null)
|
||||
return (cfg_dict, 0, null());
|
||||
}
|
||||
cell cparams = cfg_dict.idict_get_ref(32, 10); ;; critical parameters
|
||||
(_, found?) = cparams.idict_get?(32, param_id);
|
||||
if (found? < critical?) {
|
||||
;; trying to set a critical parameter after a non-critical voting
|
||||
return (cfg_dict, 0, null());
|
||||
}
|
||||
;; CHANGE ONE CONFIGURATION PARAMETER (!)
|
||||
cfg_dict~idict_set_ref(32, param_id, param_val);
|
||||
return (cfg_dict, param_id, param_val);
|
||||
}
|
||||
|
||||
(cell, int) perform_proposed_action(cell cfg_dict, int public_key, int param_id, cell param_val) inline_ref {
|
||||
if (param_id == -999) {
|
||||
;; appoint or depose dictator
|
||||
return (cfg_dict, param_val.null?() ? 0 : param_val.begin_parse().preload_uint(256));
|
||||
}
|
||||
if (param_val.null?()) {
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
if (param_id == -1000) {
|
||||
;; upgrade code
|
||||
var cs = param_val.begin_parse();
|
||||
var new_code = cs~load_ref();
|
||||
set_code(new_code);
|
||||
var old_code = get_c3();
|
||||
set_c3(new_code.begin_parse().bless());
|
||||
after_code_upgrade(cs, old_code);
|
||||
throw(0);
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
if (param_id == -1001) {
|
||||
;; update elector code
|
||||
var cs = param_val.begin_parse();
|
||||
change_elector_code(cs);
|
||||
}
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
|
||||
;; cfg_proposal_status#ce expires:uint32 proposal:^ConfigProposal is_critical:Bool
|
||||
;; voters:(HashmapE 16 True) remaining_weight:int64 validator_set_id:uint256
|
||||
;; rounds_remaining:uint8 wins:uint8 losses:uint8 = ConfigProposalStatus;
|
||||
|
@ -174,6 +226,26 @@ _ perform_action(cfg_dict, public_key, action, cs) {
|
|||
return (cs~load_uint(32), cs~load_ref(), cs~load_int(1), cs~load_dict(), cs~load_int(64), cs~load_uint(256), cs);
|
||||
}
|
||||
|
||||
slice update_proposal_status(slice rest, int weight_remaining, int critical?) inline_ref {
|
||||
var [min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _] = get_vote_config(critical?);
|
||||
var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
|
||||
losses -= (weight_remaining >= 0);
|
||||
if (losses > max_losses) {
|
||||
;; lost too many times
|
||||
return null();
|
||||
}
|
||||
rounds_remaining -= 1;
|
||||
if (rounds_remaining < 0) {
|
||||
;; existed for too many rounds
|
||||
return null();
|
||||
}
|
||||
return begin_cell()
|
||||
.store_uint(rounds_remaining, 8)
|
||||
.store_uint(losses, 8)
|
||||
.store_uint(wins, 8)
|
||||
.end_cell().begin_parse();
|
||||
}
|
||||
|
||||
builder begin_pack_proposal_status(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id) inline {
|
||||
return begin_cell()
|
||||
.store_int(0xce - 0x100, 8)
|
||||
|
@ -185,54 +257,107 @@ builder begin_pack_proposal_status(int expires, cell proposal, int critical?, ce
|
|||
.store_uint(vset_id, 256);
|
||||
}
|
||||
|
||||
(cell, int, int, slice) new_proposal(cs) inline {
|
||||
return (null(), 0, 0, cs);
|
||||
}
|
||||
|
||||
(cell, int, int, slice) unpack_proposal(slice cs) inline {
|
||||
return (cs~load_dict(), cs~load_uint(64), cs~load_uint(256), cs);
|
||||
}
|
||||
|
||||
builder pack_proposal(cell voters, int sum_weight, int vset_id, slice body) inline {
|
||||
return begin_cell().store_dict(voters).store_uint(sum_weight, 64).store_uint(vset_id, 256).store_slice(body);
|
||||
}
|
||||
|
||||
(cell, slice) register_vote(vote_dict, action, cs, idx, weight, total_weight, cur_vset_id) {
|
||||
int hash = 0;
|
||||
int found? = 0;
|
||||
var entry = null();
|
||||
if (action & 1) {
|
||||
hash = slice_hash(cs);
|
||||
(entry, found?) = vote_dict.udict_get?(256, hash);
|
||||
} else {
|
||||
hash = cs.preload_uint(256);
|
||||
(entry, found?) = vote_dict.udict_get?(256, hash);
|
||||
throw_unless(42, found?);
|
||||
(cell, cell, int) register_vote(vote_dict, phash, idx, weight) inline_ref {
|
||||
var (pstatus, found?) = vote_dict.udict_get?(256, phash);
|
||||
ifnot (found?) {
|
||||
;; config proposal not found
|
||||
return (vote_dict, null(), false);
|
||||
}
|
||||
var (cur_vset, total_weight, _) = get_current_vset();
|
||||
int cur_vset_id = cur_vset.cell_hash();
|
||||
var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
|
||||
if (expires <= now()) {
|
||||
;; config proposal expired, delete and report not found
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
return (vote_dict, null(), false);
|
||||
}
|
||||
var (voters, sum_weight, vset_id, body) = found? ? unpack_proposal(entry) : (null(), 0, cur_vset_id, cs);
|
||||
if (vset_id != cur_vset_id) {
|
||||
voters = null();
|
||||
sum_weight = 0;
|
||||
;; config proposal belongs to a previous validator set
|
||||
vset_id = cur_vset_id;
|
||||
rest = update_proposal_status(rest, weight_remaining, critical?);
|
||||
voters = null();
|
||||
weight_remaining = muldiv(total_weight, 3, 4);
|
||||
}
|
||||
if (rest.null?()) {
|
||||
;; discard proposal (existed for too many rounds, or too many losses)
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
return (vote_dict, null(), false);
|
||||
}
|
||||
var (_, found?) = voters.udict_get?(16, idx);
|
||||
ifnot (found?) {
|
||||
voters~udict_set_builder(16, idx, begin_cell().store_uint(32, now()));
|
||||
sum_weight += weight;
|
||||
if (sum_weight * 3 > total_weight * 2) {
|
||||
;; proposal accepted
|
||||
vote_dict~udict_delete?(256, hash);
|
||||
return (vote_dict, body);
|
||||
} else {
|
||||
vote_dict~udict_set_builder(256, hash, pack_proposal(voters, sum_weight, cur_vset_id, body));
|
||||
return (vote_dict, null());
|
||||
}
|
||||
} else {
|
||||
return (vote_dict, null());
|
||||
if (found?) {
|
||||
;; already voted for this proposal, ignore vote
|
||||
return (vote_dict, null(), false);
|
||||
}
|
||||
;; register vote
|
||||
voters~udict_set_builder(16, idx, begin_cell().store_uint(now(), 32));
|
||||
int old_wr = weight_remaining;
|
||||
weight_remaining -= weight;
|
||||
if ((weight_remaining ^ old_wr) >= 0) {
|
||||
;; not enough votes, or proposal already accepted in this round
|
||||
;; simply update weight_remaining
|
||||
vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest));
|
||||
return (vote_dict, null(), false);
|
||||
}
|
||||
;; proposal wins in this round
|
||||
var [min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _] = get_vote_config(critical?);
|
||||
var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
|
||||
wins += 1;
|
||||
if (wins >= min_wins) {
|
||||
;; proposal is accepted, remove and process
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
return (vote_dict, proposal, critical?);
|
||||
}
|
||||
;; update proposal info
|
||||
vote_dict~udict_set_builder(256, phash,
|
||||
begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id)
|
||||
.store_uint(rounds_remaining, 8)
|
||||
.store_uint(wins, 8)
|
||||
.store_uint(losses, 8));
|
||||
return (vote_dict, null(), false);
|
||||
}
|
||||
|
||||
int register_voting_proposal(slice cs, int msg_value) inline_ref {
|
||||
(slice, int) scan_proposal(int phash, slice pstatus) inline_ref {
|
||||
var (cur_vset, total_weight, _) = get_current_vset();
|
||||
int cur_vset_id = cur_vset.cell_hash();
|
||||
var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
|
||||
if (expires <= now()) {
|
||||
;; config proposal expired, delete
|
||||
return (null(), true);
|
||||
}
|
||||
if (vset_id == cur_vset_id) {
|
||||
;; config proposal already processed or voted for in this round, change nothing
|
||||
return (pstatus, false);
|
||||
}
|
||||
;; config proposal belongs to a previous validator set
|
||||
vset_id = cur_vset_id;
|
||||
rest = update_proposal_status(rest, weight_remaining, critical?);
|
||||
voters = null();
|
||||
weight_remaining = muldiv(total_weight, 3, 4);
|
||||
if (rest.null?()) {
|
||||
;; discard proposal (existed for too many rounds, or too many losses)
|
||||
return (null(), true);
|
||||
}
|
||||
;; return updated proposal
|
||||
return (begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest).end_cell().begin_parse(), true);
|
||||
}
|
||||
|
||||
cell scan_random_proposal(cell vote_dict) inline_ref {
|
||||
var (phash, pstatus, found?) = vote_dict.udict_get_nexteq?(256, random());
|
||||
ifnot (found?) {
|
||||
return vote_dict;
|
||||
}
|
||||
(pstatus, var changed?) = scan_proposal(phash, pstatus);
|
||||
if (changed?) {
|
||||
if (pstatus.null?()) {
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
} else {
|
||||
vote_dict~udict_set(256, phash, pstatus);
|
||||
}
|
||||
}
|
||||
return vote_dict;
|
||||
}
|
||||
|
||||
int register_voting_proposal(slice cs, int msg_value) impure inline_ref {
|
||||
var (expire_at, proposal, critical?) = (cs~load_uint(32), cs~load_ref(), cs~load_int(1));
|
||||
if (expire_at >> 30) {
|
||||
expire_at -= now();
|
||||
|
@ -306,7 +431,7 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref {
|
|||
}
|
||||
;; obtain current validator set data
|
||||
var (vset, total_weight, _) = get_current_vset();
|
||||
int weight_remaining = muldiv(total_weight, 2, 3) + 1;
|
||||
int weight_remaining = muldiv(total_weight, 3, 4);
|
||||
;; create new proposal
|
||||
vote_dict~udict_set_builder(256, phash,
|
||||
begin_pack_proposal_status(expire_at, proposal, critical?, null(), weight_remaining, vset.cell_hash())
|
||||
|
@ -374,27 +499,32 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref {
|
|||
int msg_seqno = cs~load_uint(32);
|
||||
var valid_until = cs~load_uint(32);
|
||||
throw_if(35, valid_until < now());
|
||||
throw_if(39, slice_depth(cs) > 64);
|
||||
throw_if(39, slice_depth(cs) > 128);
|
||||
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
ifnot ((action - 0x566f7465) & -2) {
|
||||
var idx = cs~load_uint(16);
|
||||
if (action == 0x566f7465) {
|
||||
var (idx, phash) = (cs~load_uint(16), cs~load_uint(256));
|
||||
cs.end_parse();
|
||||
var (vdescr, total_weight) = get_validator_descr(idx);
|
||||
var (val_pubkey, weight) = unpack_validator_descr(vdescr);
|
||||
throw_unless(34, check_signature(slice_hash(in_msg), signature, val_pubkey));
|
||||
throw_unless(34, check_data_signature(in_msg, signature, val_pubkey));
|
||||
accept_message();
|
||||
stored_seqno += 1;
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
commit();
|
||||
var (_, bits, refs) = cs.slice_compute_data_size(1024);
|
||||
(vote_dict, var accepted) = register_vote(vote_dict, action, cs, idx, weight, total_weight, config_param(34).cell_hash());
|
||||
(vote_dict, var accepted_proposal, var critical?) = register_vote(vote_dict, phash, idx, weight);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
ifnot (accepted.null?()) {
|
||||
(cfg_dict, public_key) = perform_action(cfg_dict, public_key, accepted~load_uint(32), accepted);
|
||||
ifnot (accepted_proposal.null?()) {
|
||||
(cfg_dict, var param_id, var param_val) = accept_proposal(cfg_dict, accepted_proposal, critical?);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
if (param_id) {
|
||||
commit();
|
||||
(cfg_dict, public_key) = perform_proposed_action(cfg_dict, public_key, param_id, param_val);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
}
|
||||
}
|
||||
return ();
|
||||
}
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
accept_message();
|
||||
stored_seqno += 1;
|
||||
|
@ -405,11 +535,10 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref {
|
|||
}
|
||||
|
||||
() run_ticktock(int is_tock) impure {
|
||||
var cs = begin_parse(get_data());
|
||||
var cfg_dict = cs~load_ref();
|
||||
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
|
||||
int kl = 32;
|
||||
;; cfg_dict~idict_set_ref(kl, -17, begin_cell().store_uint(now() >> 16, 32).end_cell());
|
||||
var next_vset = cfg_dict.idict_get_ref(kl, 36);
|
||||
var updated? = false;
|
||||
ifnot (next_vset.null?()) {
|
||||
;; check whether we have to set next_vset as the current validator set
|
||||
var ds = next_vset.begin_parse();
|
||||
|
@ -421,12 +550,56 @@ int register_voting_proposal(slice cs, int msg_value) inline_ref {
|
|||
var cur_vset = cfg_dict~idict_set_get_ref(kl, 34, next_vset); ;; next_vset -> cur_vset
|
||||
cfg_dict~idict_set_get_ref(kl, 32, cur_vset); ;; cur_vset -> prev_vset
|
||||
cfg_dict~idict_delete?(kl, 36); ;; (null) -> next_vset
|
||||
updated? = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
set_data(begin_cell().store_ref(cfg_dict).store_slice(cs).end_cell());
|
||||
ifnot (updated?) {
|
||||
;; if nothing has been done so far, scan a random voting proposal instead
|
||||
vote_dict = scan_random_proposal(vote_dict);
|
||||
}
|
||||
;; save data and return
|
||||
return store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
}
|
||||
|
||||
int seqno() impure method_id {
|
||||
int seqno() method_id {
|
||||
return get_data().begin_parse().preload_uint(32);
|
||||
}
|
||||
|
||||
_ unpack_proposal(slice pstatus) inline_ref {
|
||||
(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id, slice rest) = unpack_proposal_status(pstatus);
|
||||
var voters_list = null();
|
||||
var voter_id = (1 << 32);
|
||||
do {
|
||||
(voter_id, _, var f) = voters.udict_get_prev?(16, voter_id);
|
||||
if (f) {
|
||||
voters_list = cons(voter_id, voters_list);
|
||||
}
|
||||
} until (~ f);
|
||||
var (rounds_remaining, losses, wins) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
|
||||
rest.end_parse();
|
||||
var (param_id, param_val, param_hash) = parse_config_proposal(proposal);
|
||||
return [expires, critical?, [param_id, param_val, param_hash], vset_id, voters_list, weight_remaining, rounds_remaining, losses, wins];
|
||||
}
|
||||
|
||||
_ get_proposal(int phash) method_id {
|
||||
(_, _, _, var vote_dict) = load_data();
|
||||
var (pstatus, found?) = vote_dict.udict_get?(256, phash);
|
||||
ifnot (found?) {
|
||||
return null();
|
||||
}
|
||||
return unpack_proposal(pstatus);
|
||||
}
|
||||
|
||||
_ list_proposals() method_id {
|
||||
(_, _, _, var vote_dict) = load_data();
|
||||
var phash = (1 << 255) + ((1 << 255) - 1);
|
||||
var list = null();
|
||||
do {
|
||||
(phash, var pstatus, var f) = vote_dict.udict_get_prev?(256, phash);
|
||||
if (f) {
|
||||
list = cons([phash, unpack_proposal(pstatus)], list);
|
||||
}
|
||||
} until (~ f);
|
||||
return list;
|
||||
}
|
||||
|
|
33
crypto/smartcont/config-proposal-vote-req.fif
Normal file
33
crypto/smartcont/config-proposal-vote-req.fif
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
"validator-to-sign.req" =: savefile
|
||||
|
||||
{ ."usage: " @' $0 type ." <expire-at> <validator-idx> <proposal-hash> [<savefile>]" cr
|
||||
."Creates an unsigned request expiring at unixtime <expire-at> to vote for configuration proposal <proposal-hash> (decimal; prefix with '0x' if needed) on behalf of validator with zero-based index <validator-idx> in current validator set (as stored in configuration parameter 34)" cr
|
||||
."The result is saved into <savefile> (" savefile type ." by default) and output in hexadecimal form, to be signed later by the validator public key" cr 1 halt
|
||||
} : usage
|
||||
|
||||
$# dup 3 < swap 4 > or ' usage if
|
||||
4 :$1..n
|
||||
|
||||
$1 parse-int dup 30 1<< < { now + 1000 + 2000 /c 2000 * } if
|
||||
dup =: expire-at
|
||||
dup now <= abort"expiration time must be in the future"
|
||||
32 ufits not abort"invalid expiration time"
|
||||
$2 parse-int dup =: val-idx
|
||||
16 ufits not abort"validator index out of range"
|
||||
$3 parse-int dup =: prop-hash
|
||||
256 ufits not abort"invalid proposal hash"
|
||||
$4 savefile replace-if-null =: savefile
|
||||
0 =: seqno
|
||||
|
||||
."Creating a request expiring at " expire-at .
|
||||
."to vote for configuration proposal 0x" prop-hash 64x.
|
||||
."on behalf of validator with index " val-idx . cr
|
||||
|
||||
B{566f7465} seqno 32 u>B B+ expire-at 32 u>B B+ val-idx 16 u>B B+ prop-hash 256 u>B B+
|
||||
dup Bx. cr
|
||||
dup B>base64url type cr
|
||||
savefile tuck B>file ."Saved to file " type cr
|
51
crypto/smartcont/config-proposal-vote-signed.fif
Normal file
51
crypto/smartcont/config-proposal-vote-signed.fif
Normal file
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
"vote-query.boc" =: savefile
|
||||
|
||||
{ ."usage: " @' $0 type ." <config-addr> <expire-at> <validator-idx> <proposal-hash> <validator-pubkey> <validator-signature> [<savefile>]" cr
|
||||
."Creates an external message addressed to the configuration smart contract <config-addr> containing a signed request expiring at unixtime <expire-at> to vote for configuration proposal <proposal-hash> (decimal; prefix with '0x' if needed) on behalf of validator with zero-based index <validator-idx> and (Base64) public key <validator-pubkey> in current validator set (as stored in configuration parameter 34)" cr
|
||||
."<validator-signature> must be the base64 representation of Ed25519 signature of the previously generated unsigned request by means of <validator-pubkey>" cr
|
||||
."The result is saved into <savefile> (" savefile type ." by default), to be sent later by the lite-client" cr 1 halt
|
||||
} : usage
|
||||
|
||||
$# dup 6 < swap 7 > or ' usage if
|
||||
7 :$1..n
|
||||
|
||||
$1 true parse-load-address drop over 1+ abort"configuration smart contract must be in masterchain"
|
||||
2=: config-addr
|
||||
$2 parse-int dup 30 1<< < { now + 1000 + 2000 /c 2000 * } if
|
||||
dup =: expire-at
|
||||
dup now <= abort"expiration time must be in the future"
|
||||
32 ufits not abort"invalid expiration time"
|
||||
$3 parse-int dup =: val-idx
|
||||
16 ufits not abort"validator index out of range"
|
||||
$4 parse-int dup =: prop-hash
|
||||
256 ufits not abort"invalid proposal hash"
|
||||
$5 base64>B dup Blen 36 <> abort"validator Ed25519 public key must be exactly 36 bytes long"
|
||||
32 B>u@+ 0xC6B41348 <> abort"invalid Ed25519 public key: unknown magic number"
|
||||
=: pubkey
|
||||
$6 base64>B dup Blen 64 <> abort"validator Ed25519 signature must be exactly 64 bytes long"
|
||||
=: signature
|
||||
$7 savefile replace-if-null =: savefile
|
||||
0 =: seqno
|
||||
|
||||
."Creating an external message to configuration smart contract "
|
||||
config-addr 2dup 6 .Addr ." = " .addr cr
|
||||
."containing a signed request expiring at " expire-at .
|
||||
."to vote for configuration proposal 0x" prop-hash 64x.
|
||||
."on behalf of validator with index " val-idx . "and public key" pubkey 64x. cr
|
||||
|
||||
B{566f7465} seqno 32 u>B B+ expire-at 32 u>B B+ val-idx 16 u>B B+ prop-hash 256 u>B B+
|
||||
dup =: to_sign
|
||||
."String to sign is " Bx. cr
|
||||
|
||||
to_sign signature pubkey ed25519_chksign not abort"Ed25519 signature is invalid"
|
||||
."Provided a valid Ed25519 signature " signature Bx. ." with validator public key " pubkey Bx. cr
|
||||
|
||||
<b b{1000100} s, config-addr addr, 0 Gram, b{00} s,
|
||||
signature B, to_sign B, b>
|
||||
cr ."External message is " dup <s csr. cr
|
||||
|
||||
2 boc+>B savefile tuck B>file ."Saved to file " type cr
|
63
crypto/smartcont/create-config-proposal.fif
Normal file
63
crypto/smartcont/create-config-proposal.fif
Normal file
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ show-options-help 1 halt } : usage
|
||||
86400 30 * =: expire-in
|
||||
false =: critical
|
||||
-1 =: old-hash
|
||||
|
||||
begin-options
|
||||
" <index> <new-value-boc> [-x <expire-in>] [-c] [-H <old-hash>] [<savefile>]" +cr +tab
|
||||
+"Creates a new configuration proposal for setting configuration parameter <index> to <new-value-boc> (`null` means no new value), "
|
||||
+"and saves it as an internal message body into <savefile>.boc ('config-msg-body.boc' by default)"
|
||||
disable-digit-options generic-help-setopt
|
||||
"c" "--critical" { true =: critical } short-long-option
|
||||
"Creates a critical parameter change proposal" option-help
|
||||
"x" "--expires-in" { parse-int =: expire-in } short-long-option-arg
|
||||
"Sets proposal expiration time in seconds (default " expire-in (.) $+ +")" option-help
|
||||
"H" "--old-hash" { (hex-number) not abort"256-bit hex number expected as hash" =: old-hash }
|
||||
short-long-option-arg
|
||||
"Sets the required cell hash of existing parameter value (0 means no value)" option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
$# dup 2 < swap 3 > or ' usage if
|
||||
3 :$1..n
|
||||
|
||||
$1 parse-int dup =: param-idx
|
||||
32 fits not abort"parameter index out of range"
|
||||
$2 =: boc-filename
|
||||
$3 "config-msg-body.boc" replace-if-null =: savefile
|
||||
expire-in now + =: expire-at
|
||||
|
||||
boc-filename dup "null" $= {
|
||||
."New value of configuration parameter" param-idx . ."is null" cr drop null
|
||||
} {
|
||||
."Loading new value of configuration parameter " param-idx . ."from file " dup type cr
|
||||
boc-filename file>B B>boc
|
||||
dup <s csr. cr
|
||||
} cond
|
||||
=: param-value
|
||||
|
||||
{ 2drop true } : is-valid-config?
|
||||
|
||||
dup param-idx is-valid-config? not abort"not a valid value for chosen configuration parameter"
|
||||
|
||||
critical { ."Critical" } { ."Non-critical" } cond
|
||||
." configuration proposal will expire at " expire-at . ."(in " expire-in . ."seconds)" cr
|
||||
|
||||
now 32 << param-idx + =: query-id
|
||||
."Query id is " query-id . cr
|
||||
|
||||
// create message body
|
||||
<b x{6e565052} s, query-id 64 u, expire-at 32 u,
|
||||
<b x{f3} s, param-idx 32 i, param-value dict,
|
||||
old-hash tuck 0>= tuck 1 i, -rot { 256 u, } { drop } cond b> ref,
|
||||
critical 1 i, b>
|
||||
|
||||
dup ."resulting internal message body: " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
savefile tuck B>file
|
||||
."(Saved to file " type .")" cr
|
|
@ -157,7 +157,7 @@ Masterchain swap
|
|||
*
|
||||
*/
|
||||
// version capabilities
|
||||
0 capCreateStats config.version!
|
||||
1 capCreateStats capBounceMsgBody or capReportVersion or config.version!
|
||||
// max-validators max-main-validators min-validators
|
||||
// 9 4 1 config.validator_num!
|
||||
1000 100 13 config.validator_num!
|
||||
|
@ -202,12 +202,12 @@ 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!
|
||||
( -1000 -1001 0 1 9 10 12 14 15 16 17 32 34 36 ) config.critical_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_price cell_price ]
|
||||
// [ 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 GR$.001 GR$.2 )
|
||||
_( 4 7 4 2 5000000 20000000 GR$.002 GR$.8 )
|
||||
_( 2 3 2 2 1000000 10000000 1 500 )
|
||||
_( 4 7 4 2 5000000 20000000 2 1000 )
|
||||
config.param_proposals_setup!
|
||||
|
||||
"validator-keys" +suffix +".pub" file>B
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue