Skip to content

Commit fd354ae

Browse files
authored
feature(target_chains/ton): add upgrade standard (#1939)
* add execute_upgrade_contract * add upgrade feature * precommit
1 parent 0fc2579 commit fd354ae

File tree

17 files changed

+535
-377
lines changed

17 files changed

+535
-377
lines changed

pnpm-lock.yaml

Lines changed: 209 additions & 359 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

target_chains/ton/contracts/contracts/Main.fc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313

1414
;; * A 32-bit (big-endian) unsigned integer `op`, identifying the `operation` to be performed, or the `method` of the smart contract to be invoked.
1515
int op = in_msg_body~load_uint(32);
16-
;; * A 64-bit (big-endian) unsigned integer `query_id`, used in all query-response internal messages to indicate that a response is related to a query (the `query_id` of a response must be equal to the `query_id` of the corresponding query). If `op` is not a query-response method (e.g., it invokes a method that is not expected to send an answer), then `query_id` may be omitted.
17-
int query_id = in_msg_body~load_uint(64);
16+
cell data = in_msg_body~load_ref();
17+
slice data_slice = data.begin_parse();
1818

1919
;; * The remainder of the message body is specific for each supported value of `op`.
2020
if (op == OP_UPDATE_GUARDIAN_SET) {
21-
update_guardian_set(in_msg_body);
21+
update_guardian_set(data_slice);
2222
} elseif (op == OP_EXECUTE_GOVERNANCE_ACTION) {
23-
execute_governance_action(in_msg_body);
23+
execute_governance_action(data_slice);
24+
} elseif (op == OP_UPGRADE_CONTRACT) {
25+
execute_upgrade_contract(data);
2426
} else {
2527
throw(0xffff); ;; Throw exception for unknown op
2628
}

target_chains/ton/contracts/contracts/Pyth.fc

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,25 @@ int apply_decimal_expo(int value, int expo) {
254254
return result;
255255
}
256256

257-
() execute_upgrade_contract(slice payload) impure {
258-
;; TODO: Implement
257+
() execute_upgrade_contract(cell new_code) impure {
258+
load_data();
259+
int hash_code = cell_hash(new_code);
260+
throw_unless(ERROR_INVALID_CODE_HASH, upgrade_code_hash == hash_code);
261+
262+
;; Set the new code
263+
set_code(new_code);
264+
265+
;; Set the code continuation to the new code
266+
set_c3(new_code.begin_parse().bless());
267+
268+
;; Throw an exception to end the current execution
269+
;; The contract will be restarted with the new code
270+
throw(0);
271+
}
272+
273+
() execute_authorize_upgrade_contract(slice payload) impure {
274+
int code_hash = payload~load_uint(256);
275+
upgrade_code_hash = code_hash;
259276
}
260277

261278
() execute_authorize_governance_data_source_transfer(slice payload) impure {
@@ -317,8 +334,8 @@ int apply_decimal_expo(int value, int expo) {
317334
}
318335

319336
() execute_governance_payload(int action, slice payload) impure {
320-
if (action == UPGRADE_CONTRACT) {
321-
execute_upgrade_contract(payload);
337+
if (action == AUTHORIZE_UPGRADE_CONTRACT) {
338+
execute_authorize_upgrade_contract(payload);
322339
} elseif (action == AUTHORIZE_GOVERNANCE_DATA_SOURCE_TRANSFER) {
323340
execute_authorize_governance_data_source_transfer(payload);
324341
} elseif (action == SET_DATA_SOURCES) {

target_chains/ton/contracts/contracts/common/errors.fc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const int ERROR_OLD_GOVERNANCE_MESSAGE = 1033;
4040
const int ERROR_INVALID_GOVERNANCE_TARGET = 1034;
4141
const int ERROR_INVALID_GOVERNANCE_MAGIC = 1035;
4242
const int ERROR_INVALID_GOVERNANCE_MODULE = 1036;
43+
const int ERROR_INVALID_CODE_HASH = 1037;
4344

4445
;; Common
45-
const int ERROR_INSUFFICIENT_GAS = 1037;
46+
const int ERROR_INSUFFICIENT_GAS = 1038;

target_chains/ton/contracts/contracts/common/governance_actions.fc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const int UPGRADE_CONTRACT = 0;
1+
const int AUTHORIZE_UPGRADE_CONTRACT = 0;
22
const int AUTHORIZE_GOVERNANCE_DATA_SOURCE_TRANSFER = 1;
33
const int SET_DATA_SOURCES = 2;
44
const int SET_FEE = 3;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
const int OP_UPDATE_GUARDIAN_SET = 1;
22
const int OP_UPDATE_PRICE_FEEDS = 2;
33
const int OP_EXECUTE_GOVERNANCE_ACTION = 3;
4+
const int OP_UPGRADE_CONTRACT = 4;

target_chains/ton/contracts/contracts/common/storage.fc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ global int single_update_fee;
1111
global cell data_sources; ;; Dictionary of DataSource tuples, keyed by u8
1212
global int num_data_sources;
1313
global cell is_valid_data_source; ;; Dictionary of int (0 as false, -1 as true), keyed by DataSource cell_hash
14+
global int upgrade_code_hash; ;; 256-bit unsigned integer
1415

1516

1617
;; Wormhole
@@ -54,6 +55,7 @@ global int governance_data_source_index; ;; u32
5455
.store_ref(governance_data_source)
5556
.store_uint(last_executed_governance_sequence, 64)
5657
.store_uint(governance_data_source_index, 32)
58+
.store_uint(upgrade_code_hash, 256)
5759
.end_cell();
5860

5961
begin_cell()
@@ -94,6 +96,7 @@ global int governance_data_source_index; ;; u32
9496
governance_data_source = governance_slice~load_ref();
9597
last_executed_governance_sequence = governance_slice~load_uint(64);
9698
governance_data_source_index = governance_slice~load_uint(32);
99+
upgrade_code_hash = governance_slice~load_uint(256);
97100

98101
ds.end_parse();
99102
}

target_chains/ton/contracts/contracts/tests/PythTest.fc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@
2020

2121
int op = in_msg_body~load_uint(32);
2222
cell data = in_msg_body~load_ref();
23+
slice data_slice = data.begin_parse();
2324
if (op == OP_UPDATE_GUARDIAN_SET) {
24-
update_guardian_set(data.begin_parse());
25+
update_guardian_set(data_slice);
2526
} elseif (op == OP_UPDATE_PRICE_FEEDS) {
26-
update_price_feeds(msg_value, data.begin_parse());
27+
update_price_feeds(msg_value, data_slice);
2728
} elseif (op == OP_EXECUTE_GOVERNANCE_ACTION) {
28-
execute_governance_action(data.begin_parse());
29+
execute_governance_action(data_slice);
30+
} elseif (op == OP_UPGRADE_CONTRACT) {
31+
execute_upgrade_contract(data);
2932
} else {
3033
throw(0xffff); ;; Throw exception for unknown op
3134
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{-
2+
This test contract is an upgraded version of PythTest.fc. This is used to test the upgrade functionality of the Pyth contract.
3+
-}
4+
5+
#include "../imports/stdlib.fc";
6+
#include "../Pyth.fc";
7+
#include "../Wormhole.fc";
8+
#include "../common/op.fc";
9+
10+
() recv_internal(int balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
11+
if (in_msg_body.slice_empty?()) {
12+
return ();
13+
}
14+
15+
int op = in_msg_body~load_uint(32);
16+
cell data = in_msg_body~load_ref();
17+
slice data_slice = data.begin_parse();
18+
if (op == OP_UPDATE_GUARDIAN_SET) {
19+
update_guardian_set(data_slice);
20+
} elseif (op == OP_UPDATE_PRICE_FEEDS) {
21+
update_price_feeds(msg_value, data_slice);
22+
} elseif (op == OP_EXECUTE_GOVERNANCE_ACTION) {
23+
execute_governance_action(data_slice);
24+
} elseif (op == OP_UPGRADE_CONTRACT) {
25+
execute_upgrade_contract(data);
26+
} else {
27+
throw(0xffff); ;; Throw exception for unknown op
28+
}
29+
}
30+
31+
(int, int, int, int) test_get_price_unsafe(int price_feed_id) method_id {
32+
return get_price_unsafe(price_feed_id);
33+
}
34+
35+
(int, int, int, int) test_get_price_no_older_than(int time_period, int price_feed_id) method_id {
36+
return get_price_no_older_than(time_period, price_feed_id);
37+
}
38+
39+
(int, int, int, int) test_get_ema_price_unsafe(int price_feed_id) method_id {
40+
return get_ema_price_unsafe(price_feed_id);
41+
}
42+
43+
(int, int, int, int) test_get_ema_price_no_older_than(int time_period, int price_feed_id) method_id {
44+
return get_ema_price_no_older_than(time_period, price_feed_id);
45+
}
46+
47+
(int) test_get_update_fee(slice in_msg_body) method_id {
48+
return get_update_fee(in_msg_body);
49+
}
50+
51+
(int) test_get_single_update_fee() method_id {
52+
return get_single_update_fee();
53+
}
54+
55+
(int) test_get_chain_id() method_id {
56+
return get_chain_id();
57+
}
58+
59+
(int) test_get_last_executed_governance_sequence() method_id {
60+
return get_last_executed_governance_sequence();
61+
}
62+
63+
(int) test_get_governance_data_source_index() method_id {
64+
return get_governance_data_source_index();
65+
}
66+
67+
(cell) test_get_governance_data_source() method_id {
68+
return get_governance_data_source();
69+
}
70+
71+
(int) test_get_is_valid_data_source(cell data_source) method_id {
72+
return get_is_valid_data_source(data_source);
73+
}
74+
75+
;; Add a new function to demonstrate the upgrade
76+
(int) test_new_function() method_id {
77+
return 1;
78+
}

target_chains/ton/contracts/contracts/tests/WormholeTest.fc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919

2020
int op = in_msg_body~load_uint(32);
2121
cell data = in_msg_body~load_ref();
22+
slice data_slice = data.begin_parse();
2223
if (op == OP_UPDATE_GUARDIAN_SET) {
23-
update_guardian_set(data.begin_parse());
24+
update_guardian_set(data_slice);
2425
} else {
2526
throw(0xffff); ;; Throw exception for unknown op
2627
}

0 commit comments

Comments
 (0)