Skip to content

Commit 6635edd

Browse files
authored
Merge pull request #2925 from pyth-network/ton-8-pf-optimizations
fix(TON): gas optimizations to enable parsePriceFeeds for 8 price ids in one instruction
2 parents f25035a + 18a9b76 commit 6635edd

File tree

3 files changed

+1472
-15
lines changed

3 files changed

+1472
-15
lines changed

target_chains/ton/contracts/contracts/common/utils.fc

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,39 +62,64 @@ int keccak256_slice(slice s) inline {
6262
{-
6363
This function reads a specified number of bits from the input slice and stores them in a cell structure,
6464
handling data that may exceed the maximum cell capacity in FunC (1023 bits).
65+
Optimized to build cells directly in forward order without double reversal.
6566

6667
Parameters:
6768
- in_msg_body: The input slice containing the data to be read
6869
- size: The number of bits to read from the input
6970
Returns:
7071
- A tuple containing:
7172
1. A cell containing the read data, potentially spanning multiple cells if the size exceeds 1016 bits
72-
2. A slice containing the remaining unread data from the input
73+
2. A slice containing the remaining unread data from the input
7374

7475
Note:
7576
- The function uses a maximum of 1016 bits per cell (instead of 1023) to ensure byte alignment
7677
- If the input data exceeds 1016 bits, it is split into multiple cells linked by references
78+
- Uses direct forward construction to avoid gas-inefficient double reversal
7779
-}
7880
(cell, slice) read_and_store_large_data(slice in_msg_body, int size) {
79-
(cell chunks, slice remaining) = split_into_reverse_chunks(in_msg_body, size);
80-
cell last_cell = null();
81-
while (~ cell_null?(chunks)) {
82-
slice chunk = chunks.begin_parse();
83-
builder cb = begin_cell().store_slice(chunk~load_bits(chunk.slice_bits()));
84-
if (~ cell_null?(last_cell)) {
85-
cb = cb.store_ref(last_cell);
81+
;; Collect chunks in order as we build them
82+
tuple chunk_list = empty_tuple();
83+
int total_bits_loaded = 0;
84+
builder current_builder = begin_cell();
85+
86+
while ((~ in_msg_body.slice_empty?()) & (total_bits_loaded < size)) {
87+
int bits_to_load = min(min(in_msg_body.slice_bits(), MAX_BITS - current_builder.builder_bits()), size - total_bits_loaded);
88+
current_builder = current_builder.store_slice(in_msg_body~load_bits(bits_to_load));
89+
total_bits_loaded += bits_to_load;
90+
91+
if ((current_builder.builder_bits() == MAX_BITS) | (size - total_bits_loaded == 0)) {
92+
cell current_chunk = current_builder.end_cell();
93+
chunk_list~tpush(current_chunk);
94+
current_builder = begin_cell();
8695
}
87-
last_cell = cb.end_cell();
88-
if (chunk.slice_refs_empty?()) {
89-
chunks = null();
90-
} else {
91-
chunks = chunk~load_ref();
96+
97+
if ((in_msg_body.slice_bits() == 0) & (~ in_msg_body.slice_refs_empty?())) {
98+
in_msg_body = in_msg_body~load_ref().begin_parse();
9299
}
93100
}
94-
95-
return (last_cell, remaining);
101+
102+
;; Build forward chain: first chunk → second chunk → third chunk etc
103+
cell result = null();
104+
int chunk_count = chunk_list.tlen();
105+
106+
if (chunk_count > 0) {
107+
;; Start from the last chunk (no references)
108+
result = chunk_list.at(chunk_count - 1);
109+
110+
;; Build forward by adding references from earlier chunks to later chunks
111+
int i = chunk_count - 2;
112+
while (i >= 0) {
113+
cell current_chunk = chunk_list.at(i);
114+
result = begin_cell().store_slice(current_chunk.begin_parse()).store_ref(result).end_cell();
115+
i -= 1;
116+
}
117+
}
118+
119+
return (result, in_msg_body);
96120
}
97121

122+
98123
(int) pubkey_to_eth_address(int x1, int x2) {
99124
slice pubkey = begin_cell()
100125
.store_uint(x1, 256)

0 commit comments

Comments
 (0)