1
0
Fork 0
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:
ton 2020-03-27 18:59:00 +04:00
parent 606e970ed5
commit a31f8d4424
39 changed files with 722 additions and 132 deletions

View file

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