Source: Beosin
With the rapid development of blockchain technology today, TON (The Open Network), as an efficient and flexible blockchain platform, is receiving more and more attention Developer concerns. TON's unique architecture and features provide powerful tools and rich possibilities for the development of decentralized applications.
However, as functionality and complexity increase, the security of smart contracts becomes increasingly important. As a smart contract programming language on TON, FunC is known for its flexibility and efficiency, but it also brings many potential risks and challenges. Writing safe and reliable smart contracts requires developers to have a deep understanding of the characteristics of the FunC language and possible risks.
This article will analyze in detail some features related to smart contracts on the TON blockchain, as well as the easily overlooked vulnerability points of smart contracts on TON.
Ton asynchronous features and account mechanism analysis h2>Smart contract asynchronous call
Network sharding and asynchronous communication
The TON blockchain is divided into three chains in design: main chain Chain (Masterchain), Workingchains (Workingchains) and Shardchains (Shardchains).
The main chain is the core of the entire network and is responsible for storing the metadata and consensus mechanism of the entire network. It records the status of all work chains and shard chains and ensures the consistency and security of the entire network. The working chain is an independent blockchain, with up to 2^32 blocks, responsible for processing specific types of transactions and smart contracts. Each work chain can have its own rules and characteristics to meet different application needs. Sharding chains are sub-chains of the work chain, used to further divide the load of the work chain and improve processing capabilities and scalability. Each work chain can be split into up to 2^60 shard chains, and the shard chains process some transactions independently, thereby achieving efficient parallel processing.
Theoretically, each account can exclusively occupy a shard chain, each account independently maintains its own COIN/TOKEN balance, and transactions between each account can be completely parallel. Accounts are transmitted through asynchronous messages. The path of messages transmitted between shard chains is log_16(N) - 1, where N is the number of shard chains.
Image source: https://frontierlabzh.medium.com/ton-weixin-e1d3ae3b3574 in the web3 world
In Ton, smart contracts interact by sending and receiving messages. These messages can be internal messages (generally speaking, messages sent by smart contracts interacting with each other) or external messages (messages sent by external sources). The message delivery process does not need to wait for the immediate response of the target contract, and the sender can continue to execute the rest of the logic code. Compared with Ethereum's synchronous calls, this asynchronous messaging mechanism provides higher flexibility and scalability, reduces performance bottlenecks caused by waiting for responses, and also brings challenges in handling concurrency and race conditions.
Message format and structure
In Ton, messages usually include sender, recipient, amount, message body and other information. The message body can be a function call, data transfer, or other custom content. The message format used by Ton can be flexibly defined and expanded, allowing various types of information to be efficiently transmitted between different contracts.
Message Queue and status processing
Each contract maintains a message queue to store unprocessed messages. During the execution of the contract, it will be processed one by one according to the messages in the queue. Since message processing is asynchronous, the contract's state is not updated immediately until the message is received.
Advantages of asynchronous messaging
•Efficient sharding mechanism: Ton’s asynchronous mechanism and its sharding The design fits perfectly. Each shard processes contract messages and status changes independently, avoiding the delay problem caused by cross-shard synchronous communication. This design improves the throughput and scalability of the entire network.
•Reduce resource consumption: Since asynchronous messages do not require immediate response, Ton's contract execution can be completed in multiple blocks, avoiding excessive consumption of resources in a single block. This enables Ton to support more complex and resource-intensive smart contracts.
•Fault tolerance and reliability: The asynchronous message delivery mechanism makes the system more fault tolerant. For example, if a contract cannot respond to messages in time due to resource constraints or other reasons, the sender can still continue to process other logic, and the system will not be stalled due to the delay of a single contract.
Challenges of asynchronous contract design
•State consistency issue: Since message delivery is asynchronous, the state of the contract may change at different times. Different messages are received, which requires developers to pay special attention to state consistency issues. When designing a contract, the possible state changes caused by different message sequences must be taken into account to ensure that the system can maintain consistency under any circumstances.
• Race conditions and protection: Asynchronous message processing brings potential race condition problems, and multiple messages may try to modify the contract state at the same time. Developers need to introduce appropriate locking mechanisms or use transactional operations to prevent state conflicts.
• Security considerations: Asynchronous contracts are vulnerable to man-in-the-middle attacks or replay attacks when processing cross-contract communications. Therefore, when designing asynchronous contracts, these potential security risks must be taken into consideration and measures to prevent them from occurring, such as using timestamps, random numbers, or multi-signatures.
Ledger Model
Ton (The Open Network) uses a unique account when designing its blockchain infrastructure Abstraction and ledger models. The flexibility of this model is reflected in how it handles account state, messaging, and contract execution.
Account Abstraction
Ton’s account model adopts a contract-based abstraction. Each account can be regarded as a contract, which is similar to Ethereum. The account abstraction model has some similarities, but is more flexible and general. In Ton, accounts are not just containers for holding assets, they also contain contract code and status data. Each account is composed of its code (Code), data (Data) and message processing (Message Handling) logic.
Account structure: Each Ton account has a unique address, which is a combination of the hash value of the account code, initial data during deployment, and some other parameters. This means that the same code and initial data deployed in different environments (e.g., different blockchains or shards) may generate different addresses.
Flexibility: Since each account can run its own contract code, Ton's account can implement very complex logic. Accounts are not just simple balance holders, but can also handle complex state transfers, cross-account message communication, and even automated operations based on specific conditions. This makes Ton’s account model more scalable and flexible than those on traditional blockchains.
Ledger structure
Ton’s ledger structure is designed to efficiently handle large-scale concurrent transactions and supports asynchronous messaging and multi-shard operations. The status of each account is stored in a Merkle tree structure, which enables Ton's ledger to have efficient status verification capabilities.
State Storage
Account status information is stored in persistent storage and organized through Merkle trees to ensure the integrity and security of the state. This design also enables efficient querying and verification of status, especially in cross-shard transaction scenarios.
The account or smart contract status usually contains the following:
1. The balance of the base currency
2. The balance of other currencies
3. Smart contract code (or its hash)
4. Persistent data of the smart contract (or its Merkle hash)
5. Regarding the number and use of persistent storage units Statistics of the raw number of bytes
6. The most recent time of payment persisted by the smart contract (actually the main chain block number)
7. Transfer currency and send from this account The public key required for the message (optional; defaults to account_id itself). In some cases, similar to what is done with Bitcoin transaction outputs, a more sophisticated signature checking code can be found here; the account_id will then be equal to the hash of this code.
Not all information is required for every account. For example, smart contract code only works with smart contracts, but not "simple" accounts. Additionally, while any account must have a non-zero balance in the primary currency (e.g., the main chain for the base working chain and the Gram for the shard chain), other currencies may have zero balances. To avoid retaining unused data, a sum-product type is defined during the creation of the work chain, which uses different marker bytes to distinguish different "constructors". Ultimately, the account state itself is saved as a collection of cells for TVM persistence storage.
Message passing and processing
Ton’s ledger structure has built-in support for asynchronous messaging. Each account can independently process received messages and update its status. This asynchronous messaging mechanism allows complex interactions between accounts without affecting the normal operation of other accounts due to delays in one operation.
Gas Model
Ton (The Open Network) blockchain greatly optimizes the execution efficiency of smart contracts through its unique Gas fee model. The gas fee model is used in the blockchain to measure and limit the resources consumed during the execution of smart contracts. Compared with the Gas model of traditional blockchains (such as Ethereum), Ton's model design is more complex and efficient, and can more accurately manage resource consumption during contract execution.
Refined Gas consumption measurement
Ton’s Gas model can accurately measure the computing resources, storage operations and message delivery costs consumed by smart contracts during execution. Through detailed measurement of resources such as computing, storage, and messaging, Ton's Gas model can prevent certain overly complex operations from taking up too many resources. By limiting Gas consumption, Ton ensures that each node in the network can fairly allocate computing resources and avoid excessive consumption of network resources by a single contract or operation.
Parallel processing and Gas optimization
Ton supports parallel processing of smart contracts, which enables multiple contracts to run on different shards at the same time without blocking each other. Under this design, its Gas model is closely integrated with its parallel execution and sharding mechanism. By processing contracts in parallel on multiple shards, Ton can disperse Gas calculations and payments to different nodes and chains, avoiding network congestion. , while maximizing resource utilization.
Dynamic Gas Adjustment Mechanism
Ton’s Gas model includes a dynamic adjustment mechanism that allows the Gas fee to be adjusted according to the real-time load of the network. This means that when the network load is low, users can execute contracts with lower gas fees, thereby encouraging operations during low load periods and balancing the resource usage of the network. This mechanism not only improves the user experience, but also controls the peak usage of resources through a market-oriented approach.
Ton smart contracts are easy to ignore vulnerabilities
In our The previous TON security analysis article has detailed the general security vulnerabilities of the Ton ecosystem. You can also refer to the following table: p>
This article will focus on the easily overlooked vulnerability points in the TON contract summarized by our team:
(1) Optimization of code readability
< p>In TON's smart contracts, numbers are used to store relevant data sent by messages. For example, in the following code, numbers are used multiple times to represent the corresponding identification and data storage length, which greatly reduces the readability and data storage length of the code. Maintainability. When other developers read this code, it is difficult to understand the meaning and purpose of these numbers. In order to improve the readability and maintainability of the code, it is recommended to define key numeric values as named constants, for example: 0x18 is defined as NON_BOUNCEABLE.
check_std_addr(address);var msg = begin_cell() store_uint(0x18, 6) ;; nobounce store_slice( address) store_coins(amount) store_uint(0, 1 + 4 + 4 + 64 + 32 + 1  ;+ 1) end_cell();send_raw_message(msg, 1);
In addition, it is also recommended to define corresponding variables for the error message in the contract judgment conditions Replace error code.
(2) Use end_parse() ensures data integrity
In the TON contract, data parsing follows a fixed order, gradually loading specified types of data from the original data. This method of parsing ensures data consistency and accuracy. As shown below:
Note that end_parse() here is used to check whether the data slice (slice) is empty. If the slice is not empty, the function will throw an exception. This ensures that the format and content of the data are as expected. If the end_parse() function finds that there is still data left in the data slice, this may indicate that the data parsing is not going exactly as expected, or that there is an issue with the format of the data. Therefore, by calling end_parse(), you can check whether there are any omissions or exceptions in the data during the parsing process.
(3) Exceptions caused by mismatch between data records and storage types
The main thing to note here is that the access types of int and uint match. In the code shown below, the data When storing, store_int() is used to store the int type value as -42, but load_uint() is used to load this value. An exception may occur here.
(4)inline_ref and the reasonable use of inline modifiers
First of all, it is necessary to explain the difference between inline_ref and inline modifiers:
lInline: A function that uses inline modifiers, its code will be in Each time it is called, it is inserted directly into the calling position. That is, every time a function is called, the actual code of the function will be copied to the calling location, instead of being executed by jumping to the function body like a normal function.
linline_ref: A function using the inline_ref modifier, whose code is stored in a separate cell. Each time a function is called, TVM executes the code stored in the cell through the CALLREF command instead of inserting the function code at the call location.
So, the inline modifier is suitable for simple functions, reducing function call overhead, but may lead to duplication of contract code; while the inline_ref modifier is suitable for more complex or multiple-called functions, by storing the function code In a separate cell to improve efficiency and avoid code duplication. Then it can be summarized as follows: when the function is large or called from multiple places, it is recommended to use inline_ref; otherwise, it is recommended to use inline.
(5) Determine the correct work chain
TON allows the creation of up to 2^32 work chains, and each work chain can be subdivided into up to 2^60 points. There are only 2 working chains before the slice: the main chain (-1) and the basic chain (0). When calculating the target address in the contract, the chain ID to which the target address belongs must be clearly specified to ensure that the generated wallet address is on the correct working chain. In order to avoid generating wrong addresses, it is recommended to use force_chain() to force the chain ID to be specified.
(6) Avoid error code conflicts
In contract design, in order to ensure standardization and avoid confusion, the management of error codes is very critical. For TON smart contracts, first of all, you should ensure that each error code is unique in the contract and avoid defining repeated error codes in the same contract to prevent confusion of error codes and unclear information; secondly, the TON platform or underlying system has already Some standard error codes are defined, and conflicts with these system error codes should be avoided. For example, the 333 error code indicates a chain ID mismatch. Therefore, it is recommended that the error code of the contract is preferably between 400 and 1000.
(7) After the operation is completed, you need to store the data and call return()
In the TON smart contract, message processing will select different logic according to the op-code. After completing the corresponding business logic, two operations need to be completed: first, if data changes are involved, save_data() must be called to ensure that the data is stored, otherwise the changes will be invalid; second, return() must be called to indicate that the operation is completed, otherwise A throw(0xffff) exception will be triggered.
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
int flags = cs~load_uint(4);
code>if (flags & 1) {
;; ignore all bounced messages
return ();
}< /code>slice sender_address = cs~load_msg_addr();
load_data();
int op = in_msg_body~load_op();
if ((op == op::op_1())) {
handle_op1();
save_data();
return ();
}
if ((op == op::op_2())) {
handle_op2();
save_data();
return ();
}
if ((op == op::op_3()) ) {
handle_op3();
save_data();
return ();
}< /code>throw(0xffff);
}
In summary, the TON blockchain, with its innovative architecture and flexibility The development environment is gradually becoming an ideal platform for decentralized application developers. However, as smart contracts play an increasingly important role in the TON ecosystem, contract security issues cannot be ignored. Developers should have a deep understanding of the characteristics of the TON ecosystem, strictly follow best practices, strengthen the security audit process, and ensure the robustness and security of the contract. Only in this way can we give full play to the advantages of the TON platform, build more secure and reliable decentralized applications, and protect the healthy development of the entire ecosystem.
At present, the TON ecosystem is developing rapidly, attracting a large amount of funds and active users. However, the resulting security issues cannot be ignored.