Ton

Форк
0
228 строк · 8.4 Кб
1
;; Storage contract fabric
2

3
#include "stdlib.fc";
4
#include "constants.fc";
5

6
const min_deploy_amount = 50000000;
7

8
cell storage_contract_code() asm """ "storage-contract-code.boc" file>B B>boc PUSHREF """;
9

10
slice calculate_address_by_stateinit(cell state_init) {
11
    return begin_cell().store_uint(4, 3)
12
            .store_int(0, 8)
13
            .store_uint(cell_hash(state_init), 256)
14
            .end_cell()
15
            .begin_parse();
16
}
17

18
cell build_storage_contract_stateinit(int merkle_hash, int file_size, int rate_per_mb_day,
19
        int max_span, slice client, int torrent_hash) {
20
    cell data = begin_cell()
21
            .store_int(0, 1) ;; active
22
            .store_coins(0) ;; client balance
23
            .store_slice(my_address())
24
            .store_uint(merkle_hash, 256)
25
            .store_uint(file_size, 64)
26
            .store_uint(0, 64) ;; next_proof
27
            .store_coins(rate_per_mb_day)
28
            .store_uint(max_span, 32)
29
            .store_uint(now(), 32) ;; last_proof_time
30
            .store_ref(begin_cell()
31
                    .store_slice(client)
32
                    .store_uint(torrent_hash, 256)
33
                    .end_cell())
34
            .end_cell();
35

36
    cell state_init = begin_cell()
37
            .store_uint(0, 2)
38
            .store_maybe_ref(storage_contract_code())
39
            .store_maybe_ref(data)
40
            .store_uint(0, 1) .end_cell();
41
    return state_init;
42
}
43

44
() deploy_storage_contract (slice client, int query_id, int file_size, int merkle_hash, int torrent_hash,
45
        int expected_rate, int expected_max_span) impure {
46
    var ds = get_data().begin_parse();
47
    var (wallet_data,
48
            accept_new_contracts?,
49
            rate_per_mb_day,
50
            max_span,
51
            minimal_file_size,
52
            maximal_file_size) = (ds~load_bits(32 + 32 + 256),
53
            ds~load_int(1),
54
            ds~load_coins(),
55
            ds~load_uint(32),
56
            ds~load_uint(64),
57
            ds~load_uint(64));
58
    throw_unless(error::no_new_contracts, accept_new_contracts?);
59
    throw_unless(error::file_too_small, file_size >= minimal_file_size);
60
    throw_unless(error::file_too_big, file_size <= maximal_file_size);
61
    throw_unless(error::provider_params_changed, expected_rate == rate_per_mb_day);
62
    throw_unless(error::provider_params_changed, expected_max_span == max_span);
63
    cell state_init = build_storage_contract_stateinit(merkle_hash, file_size, rate_per_mb_day,
64
            max_span, client, torrent_hash);
65
    cell msg = begin_cell()
66
            .store_uint(0x18, 6)
67
            .store_slice(calculate_address_by_stateinit(state_init))
68
            .store_coins(0)
69
            .store_uint(4 + 2, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
70
            .store_ref(state_init)
71
            .store_uint(op::offer_storage_contract, 32)
72
            .store_uint(query_id, 64)
73
            .end_cell();
74
    send_raw_message(msg, 64);
75
}
76

77
() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure {
78
    slice cs = in_msg_full.begin_parse();
79
    int flags = cs~load_uint(4);
80

81
    if ((flags & 1) | in_msg_body.slice_empty?()) { ;; ignore all bounced and empty messages
82
        return ();
83
    }
84
    slice sender_address = cs~load_msg_addr();
85

86
    int op = in_msg_body~load_uint(32);
87
    if (op == 0) { ;; transfer with text message
88
        return ();
89
    }
90
    int query_id = in_msg_body~load_uint(64);
91

92
    if(op == op::offer_storage_contract) {
93
        throw_unless(error::not_enough_money, msg_value >= min_deploy_amount);
94
        ;; torrent_info piece_size:uint32 file_size:uint64 root_hash:(## 256) header_size:uint64 header_hash:(## 256)
95
        ;;     microchunk_hash:(Maybe (## 256)) description:Text = TorrentInfo;
96
        ;;
97
        ;; new_storage_contract#00000001 query_id:uint64 info:(^ TorrentInfo) microchunk_hash:uint256
98
        ;;                      expected_rate:Coins expected_max_span:uint32 = NewStorageContract;
99
        cell torrent_info = in_msg_body~load_ref();
100
        int torrent_hash = cell_hash(torrent_info);
101
        slice info_cs = torrent_info.begin_parse();
102
        info_cs~skip_bits(32);
103
        int file_size = info_cs~load_uint(64);
104
        int merkle_hash = in_msg_body~load_uint(256);
105

106
        int expected_rate = in_msg_body~load_coins();
107
        int expected_max_span = in_msg_body~load_uint(32);
108
        deploy_storage_contract(sender_address, query_id, file_size, merkle_hash, torrent_hash,
109
                expected_rate, expected_max_span);
110
        return ();
111
    }
112
    if(op == op::storage_contract_terminated) {
113
        return ();
114
    }
115

116
    if(op == op::update_pubkey) {
117
        if(~ equal_slice_bits(my_address(), sender_address)) {
118
            return ();
119
        }
120
        var ds = get_data().begin_parse();
121
        var (seqno_subwallet,
122
                _,
123
                non_wallet_data) = (ds~load_bits(32 + 32),
124
                ds~load_uint(256),
125
                ds);
126
        int new_pubkey = in_msg_body~load_uint(256);
127
        set_data(begin_cell()
128
                .store_slice(seqno_subwallet)
129
                .store_uint(new_pubkey, 256)
130
                .store_slice(non_wallet_data)
131
                .end_cell());
132
    }
133
    if(op == op::update_storage_params) {
134
        if(~ equal_slice_bits(my_address(), sender_address)) {
135
            return ();
136
        }
137
        var ds = get_data().begin_parse();
138
        var wallet_data = ds~load_bits(32 + 32 + 256);
139
        var(accept_new_contracts?,
140
                rate_per_mb_day,
141
                max_span,
142
                minimal_file_size,
143
                maximal_file_size) = (in_msg_body~load_int(1),
144
                in_msg_body~load_coins(),
145
                in_msg_body~load_uint(32),
146
                in_msg_body~load_uint(64),
147
                in_msg_body~load_uint(64));
148
        set_data(begin_cell()
149
                .store_slice(wallet_data)
150
                .store_int(accept_new_contracts?, 1)
151
                .store_coins(rate_per_mb_day)
152
                .store_uint(max_span, 32)
153
                .store_uint(minimal_file_size, 64)
154
                .store_uint(maximal_file_size, 64)
155
                .end_cell());
156
    }
157
}
158

159
() recv_external(slice in_msg) impure {
160
    var signature = in_msg~load_bits(512);
161
    var cs = in_msg;
162
    var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
163
    throw_if(35, valid_until <= now());
164
    var ds = get_data().begin_parse();
165
    var (stored_seqno,
166
            stored_subwallet,
167
            public_key,
168
            non_wallet_data) = (ds~load_uint(32),
169
            ds~load_uint(32),
170
            ds~load_uint(256),
171
            ds);
172
    throw_unless(33, msg_seqno == stored_seqno);
173
    throw_unless(34, subwallet_id == stored_subwallet);
174
    throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
175
    accept_message();
176
    cs~touch();
177
    while (cs.slice_refs()) {
178
        var mode = cs~load_uint(8);
179
        send_raw_message(cs~load_ref(), mode);
180
    }
181
    set_data(begin_cell()
182
            .store_uint(stored_seqno + 1, 32)
183
            .store_uint(stored_subwallet, 32)
184
            .store_uint(public_key, 256)
185
            .store_slice(non_wallet_data)
186
            .end_cell());
187
}
188

189
;; Get methods
190

191
int seqno() method_id {
192
    return get_data().begin_parse().preload_uint(32);
193
}
194

195
int get_public_key() method_id {
196
    var cs = get_data().begin_parse();
197
    cs~load_uint(64);
198
    return cs.preload_uint(256);
199
}
200

201
;; seqno, subwallet, key
202
_ get_wallet_params() method_id {
203
    var ds = get_data().begin_parse();
204
    var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
205
    return (stored_seqno, stored_subwallet, public_key);
206
}
207

208
_ get_storage_params() method_id {
209
    var ds = get_data().begin_parse();
210
    var (wallet_data,
211
            accept_new_contracts?,
212
            rate_per_mb_day,
213
            max_span,
214
            minimal_file_size,
215
            maximal_file_size) = (ds~load_bits(32 + 32 + 256),
216
            ds~load_int(1),
217
            ds~load_coins(),
218
            ds~load_uint(32),
219
            ds~load_uint(64),
220
            ds~load_uint(64));
221
    return (accept_new_contracts?, rate_per_mb_day, max_span, minimal_file_size, maximal_file_size);
222
}
223

224
slice get_storage_contract_address(int merkle_hash, int file_size, slice client, int torrent_hash) method_id {
225
    var (_, rate_per_mb_day, max_span, _, _) = get_storage_params();
226
    cell state_init = build_storage_contract_stateinit(merkle_hash, file_size, rate_per_mb_day, max_span, client, torrent_hash);
227
    return calculate_address_by_stateinit(state_init);
228
}
229

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

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

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

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