-
Notifications
You must be signed in to change notification settings - Fork 3
/
master_counter.fc
140 lines (117 loc) · 4.33 KB
/
master_counter.fc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
{-
This is the Master Counter contract in the network stress test system.
It stays in the masterchain, receives sync messages from the middle
Counters (counter.fc), which contain transactions amount and where they
need to be placed in history. It adds this info to the history dictionary,
which anyone can easily access through get methods.
-}
#include "imports/stdlib.fc";
#include "imports/utils.fc";
const history_step = 5;
{-
owner:MsgAddress counter:uint256 history:(HashmapE 48 uint64) public_key:uint256 counter_code:^Cell = Storage;
-}
(slice, int, cell, int, cell) load_data() inline {
slice ds = get_data().begin_parse();
return (ds~load_msg_addr(), ds~load_uint(256), ds~load_dict(),
ds~load_uint(256), ds~load_ref());
}
() save_data(slice owner, int counter, cell history, int public_key, cell counter_code) impure inline {
set_data(
begin_cell().store_slice(owner)
.store_uint(counter, 256)
.store_dict(history)
.store_uint(public_key, 256)
.store_ref(counter_code)
.end_cell()
);
}
() main(cell in_msg_full, slice in_msg_body) impure {
slice cs = in_msg_full.begin_parse();
int flags = cs~load_uint(4);
if (flags & 1) {
return ();
}
slice sender_address = cs~load_msg_addr();
(slice owner, int counter, cell history, int public_key, cell counter_code) = load_data();
if (in_msg_body.slice_refs() >= 1) {
throw_unless(401, equal_slices(owner, sender_address));
cell counter_code = in_msg_body~load_ref();
save_data(owner, counter, history, public_key, counter_code);
return ();
}
int sender_id = in_msg_body~load_uint(16);
cell sender_expected_initstate = counter_init(sender_id, public_key, counter_code);
slice expected_address = calc_address(sender_expected_initstate);
throw_unless(401, equal_slice_bits(expected_address, sender_address));
accept_message();
int to_add = in_msg_body~load_uint(32);
int from_time = in_msg_body~load_uint(48);
int to_time = in_msg_body~load_uint(48);
int timedelta = to_time - from_time;
int steps = timedelta / history_step;
steps = max(steps, 1); ;; prevent division by 0
var (per_step, reminder) = divmod(to_add, steps);
int time = from_time;
time -= time % history_step; ;; round down
while (steps > 0) {
int time_txs = per_step;
(slice history_value, int found?) = history.udict_get?(48, time);
if (found?) {
time_txs += history_value~load_uint(64);
}
steps -= 1;
if (steps == 0) {
time_txs += reminder;
}
history~udict_set_builder(48, time, begin_cell().store_uint(time_txs, 64));
time += history_step;
}
counter += to_add;
save_data(owner, counter, history, public_key, counter_code);
return ();
}
() recv_external(slice in_msg) impure { ;; withdraw tons
var signature = in_msg~load_bits(512);
var cs = in_msg;
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
throw_if(35, valid_until <= now());
(_, _, _, int public_key, _) = load_data();
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
accept_message();
var mode = cs~load_uint(8);
;; just send a message
send_raw_message(cs~load_ref(), mode);
}
int get_counter() method_id {
var ds = get_data().begin_parse().skip_bits(267);
int counter = ds~load_uint(256);
return counter;
}
cell get_history() method_id {
return get_data().begin_parse().preload_ref();
}
int get_txs_on_sec(int timestamp) method_id {
cell history = get_history();
throw_if(400, cell_null?(history));
(slice history_value, int found?) = history.udict_get?(48, timestamp);
ifnot (found?) {
return 0;
}
return history_value~load_uint(64);
}
int get_txs_on_period(int start, int end) method_id {
cell history = get_history();
throw_if(400, cell_null?(history));
int txs = 0;
while (start < end) {
(start, slice history_value, int found?) = history.udict_get_nexteq?(48, start);
if (found?) {
txs += history_value~load_uint(64);
} else {
start = end;
}
start += 1;
}
return txs;
}