Ton

Форк
0
266 строк · 9.3 Кб
1
#include "stdlib.fc";
2
#include "constants.fc";
3

4
const CHUNK_SIZE = 64;
5
const fee::receipt_value = 20000000;
6
const fee::storage = 10000000;
7

8

9

10
{-
11
  storage#_ active:Bool
12
            balance:Coins provider:MsgAddress
13
            merkle_hash:uint256 file_size:uint64 next_proof_byte:uint64
14
            rate_per_mb_day:Coins
15
            max_span:uint32 last_proof_time:uint32
16
            ^[client:MsgAddress torrent_hash:uint256] = Storage;
17
-}
18

19
(slice, int) begin_parse_special(cell c) asm "x{D739} s,";
20

21
int check_proof(int merkle_hash, int byte_to_proof, int file_size, cell file_dict_proof) {
22
    (slice cs, int special) = file_dict_proof.begin_parse_special();
23
    if (~ special) {
24
        return false;
25
    }
26
    if (cs~load_uint(8) != 3) { ;; Merkle proof
27
        return false;
28
    }
29
    if (cs~load_uint(256) != merkle_hash) {
30
        return false;
31
    }
32
    cell file_dict = cs~load_ref();
33
    int key_len = 0;
34
    while ((CHUNK_SIZE << key_len) < file_size) {
35
        key_len += 1;
36
    }
37
    (slice data, int found?) = file_dict.udict_get?(key_len, byte_to_proof / CHUNK_SIZE);
38
    if(found?) {
39
        return true;
40
    }
41
    return false;
42
}
43

44
() add_to_balance(int amount) impure inline_ref {
45
    var ds = get_data().begin_parse();
46
    var (active, balance, residue) = (ds~load_int(1), ds~load_grams(), ds);
47
    balance += amount;
48
    begin_cell()
49
            .store_int(active, 1)
50
            .store_coins(balance)
51
            .store_slice(residue)
52
            .end_cell().set_data();
53
}
54

55
(slice, int) get_client_data(ds) {
56
    ds = ds.preload_ref().begin_parse();
57
    return (ds~load_msg_addr(), ds~load_uint(256));
58
}
59

60
() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure {
61
    slice cs = in_msg_full.begin_parse();
62
    int flags = cs~load_uint(4);
63

64
    if (flags & 1) { ;; ignore all bounced messages
65
        return ();
66
    }
67
    slice sender_address = cs~load_msg_addr();
68

69
    if (in_msg_body.slice_empty?()) {
70
        return add_to_balance(msg_value);
71
    }
72
    int op = in_msg_body~load_uint(32);
73
    if (op == 0) {
74
        return add_to_balance(msg_value);
75
    }
76

77
    int query_id = in_msg_body~load_uint(64);
78

79
    if(op == op::offer_storage_contract) {
80
        add_to_balance(msg_value - 2 * fee::receipt_value);
81
        var (client, torrent_hash) = get_client_data(get_data().begin_parse());
82
        var msg = begin_cell()
83
                .store_uint(0x18, 6)
84
                .store_slice(client)
85
                .store_coins(fee::receipt_value)
86
                .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
87
                .store_uint(op::contract_deployed, 32)
88
                .store_uint(query_id, 64)
89
                .store_uint(torrent_hash, 256)
90
                .end_cell();
91
        send_raw_message(msg, 0);
92
    }
93

94
    if (op == op::accept_storage_contract) {
95
        var ds = get_data().begin_parse();
96
        (int active, int balance, slice provider, slice rest) =
97
                (ds~load_int(1), ds~load_coins(), ds~load_msg_addr(), ds);
98
        throw_unless(error::contract_already_active, ~ active);
99
        throw_unless(error::unauthorized, equal_slice_bits(sender_address, provider));
100
        begin_cell()
101
                .store_int(true, 1)
102
                .store_coins(balance)
103
                .store_slice(provider)
104
                .store_slice(rest)
105
                .end_cell().set_data();
106
        var (client, torrent_hash) = get_client_data(rest);
107
        var msg = begin_cell()
108
                .store_uint(0x18, 6)
109
                .store_slice(client)
110
                .store_coins(fee::receipt_value)
111
                .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
112
                .store_uint(op::storage_contract_confirmed, 32)
113
                .store_uint(cur_lt(), 64)
114
                .store_uint(torrent_hash, 256)
115
                .end_cell();
116
        send_raw_message(msg, 0);
117
    }
118

119
    if (op == op::close_contract) {
120
        var ds = get_data().begin_parse();
121
        (int active, int balance, slice provider, slice rest) =
122
                (ds~load_int(1), ds~load_coins(), ds~load_msg_addr(), ds);
123
        var (client, torrent_hash) = get_client_data(rest);
124
        throw_unless(error::unauthorized, equal_slice_bits(sender_address, provider) | equal_slice_bits(sender_address, client));
125
        var client_msg = begin_cell()
126
                .store_uint(0x18, 6)
127
                .store_slice(client)
128
                .store_coins(balance)
129
                .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
130
                .store_uint(op::storage_contract_terminated, 32)
131
                .store_uint(cur_lt(), 64)
132
                .store_uint(torrent_hash, 256)
133
                .end_cell();
134
        if(~ active) {
135
            return send_raw_message(client_msg, 128 + 32);
136
        }
137
        send_raw_message(client_msg, 64);
138
        var provider_msg = begin_cell()
139
                .store_uint(0x18, 6)
140
                .store_slice(provider)
141
                .store_coins(0)
142
                .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
143
                .store_uint(op::storage_contract_terminated, 32)
144
                .store_uint(cur_lt(), 64)
145
                .store_uint(torrent_hash, 256)
146
                .end_cell();
147
        return send_raw_message(provider_msg, 128 + 32);
148
    }
149

150
    if (op == op::withdraw) {
151
        var ds = get_data().begin_parse();
152
        (int active, int balance, slice provider) = (ds~load_int(1), ds~load_coins(), ds~load_msg_addr());
153
        throw_unless(error::contract_not_active, active);
154
        throw_unless(error::unauthorized, equal_slice_bits(sender_address, provider));
155
        if(balance > 0) {
156
            raw_reserve(balance + fee::storage, 2);
157
        }
158
        var msg = begin_cell()
159
                .store_uint(0x18, 6)
160
                .store_slice(provider)
161
                .store_coins(fee::receipt_value)
162
                .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
163
                .store_uint(op::reward_withdrawal, 32)
164
                .store_uint(query_id, 64)
165
                .end_cell();
166
        send_raw_message(msg, 128 + 32);
167
    }
168

169
    if (op == op::proof_storage) {
170
        cell file_dict_proof = in_msg_body~load_ref();
171
        var ds = get_data().begin_parse();
172
        var (active,
173
                balance,
174
                provider,
175
                merkle_hash,
176
                file_size,
177
                next_proof,
178
                rate_per_mb_day,
179
                max_span,
180
                last_proof_time,
181
                client_data) = (ds~load_int(1),
182
                ds~load_coins(),
183
                ds~load_msg_addr(),
184
                ds~load_uint(256),
185
                ds~load_uint(64),
186
                ds~load_uint(64),
187
                ds~load_coins(),
188
                ds~load_uint(32),
189
                ds~load_uint(32),
190
                ds~load_ref());
191
        throw_unless(error::contract_not_active, active);
192
        throw_unless(error::unauthorized, equal_slice_bits(sender_address, provider));
193
        throw_unless(error::wrong_proof, check_proof(merkle_hash, next_proof, file_size, file_dict_proof));
194
        next_proof = rand(file_size);
195
        int actual_span = min(now() - last_proof_time, max_span);
196
        int bounty = muldiv(file_size * rate_per_mb_day, actual_span, 24 * 60 * 60 * 1024 * 1024);
197
        balance = max(0, balance - bounty);
198
        last_proof_time = now();
199
        begin_cell()
200
                .store_int(true, 1)
201
                .store_coins(balance)
202
                .store_slice(provider)
203
                .store_uint(merkle_hash, 256)
204
                .store_uint(file_size, 64)
205
                .store_uint(next_proof, 64)
206
                .store_coins(rate_per_mb_day)
207
                .store_uint(max_span, 32)
208
                .store_uint(last_proof_time, 32)
209
                .store_ref(client_data)
210
                .end_cell().set_data();
211

212
        ;; Send remaining balance back
213
        cell msg = begin_cell()
214
                .store_uint(0x18, 6)
215
                .store_slice(sender_address)
216
                .store_uint(0, 4 + 1 + 4 + 4 + 64 + 32 + 1 + 1)
217
                .end_cell();
218
        send_raw_message(msg, 64 + 2);
219
    }
220
}
221

222
_ get_storage_contract_data() method_id {
223
    var ds = get_data().begin_parse();
224
    var (active,
225
            balance,
226
            provider,
227
            merkle_hash,
228
            file_size,
229
            next_proof,
230
            rate_per_mb_day,
231
            max_span,
232
            last_proof_time,
233
            rest) = (ds~load_int(1),
234
            ds~load_coins(),
235
            ds~load_msg_addr(),
236
            ds~load_uint(256),
237
            ds~load_uint(64),
238
            ds~load_uint(64),
239
            ds~load_coins(),
240
            ds~load_uint(32),
241
            ds~load_uint(32),
242
            ds);
243
    var (client, torrent_hash) = get_client_data(rest);
244
    return (active, balance, provider, merkle_hash, file_size,
245
            next_proof, rate_per_mb_day, max_span, last_proof_time,
246
            client, torrent_hash);
247
}
248

249
_ get_torrent_hash() method_id {
250
    var (active, balance, provider, merkle_hash, file_size,
251
            next_proof, rate_per_mb_day, max_span, last_proof_time,
252
            client, torrent_hash) = get_storage_contract_data();
253
    return torrent_hash;
254
}
255

256
_ is_active() method_id {
257
    return get_data().begin_parse().preload_int(1);
258
}
259

260
;; next_proof, last_proof_time, max_span
261
_ get_next_proof_info() method_id {
262
    var (active, balance, provider, merkle_hash, file_size,
263
            next_proof, rate_per_mb_day, max_span, last_proof_time,
264
            client, torrent_hash) = get_storage_contract_data();
265
    return (next_proof, last_proof_time, max_span);
266
}
267

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.