🎉 [Gate 30 Million Milestone] Share Your Gate Moment & Win Exclusive Gifts!
Gate has surpassed 30M users worldwide — not just a number, but a journey we've built together.
Remember the thrill of opening your first account, or the Gate merch that’s been part of your daily life?
📸 Join the #MyGateMoment# campaign!
Share your story on Gate Square, and embrace the next 30 million together!
✅ How to Participate:
1️⃣ Post a photo or video with Gate elements
2️⃣ Add #MyGateMoment# and share your story, wishes, or thoughts
3️⃣ Share your post on Twitter (X) — top 10 views will get extra rewards!
👉
Analysis of DoS Attacks on Smart Contracts: Case Interpretation and Defense Strategies
Denial-of-service attack in Rust smart contracts
A denial-of-service attack ( DoS ) can render smart contracts unusable for a period of time or even permanently. The main reasons include:
The contract logic has a flaw with high computational complexity, resulting in Gas consumption exceeding the limit.
When calling across contracts, the execution of the contract relies on external unreliable contracts, causing blocking.
The contract owner loses the private key and cannot execute privileged functions to update important states.
The following analyzes the DoS attack vulnerability through specific examples.
1. Traverse large data structures that are externally controllable
Here is a simple contract for users to receive "dividends":
rust #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub registered: Vec, pub accounts: UnorderedMap<accountid, balance="">, }
pub fn register_account(\u0026mut self) { if self.accounts.insert(&env::predecessor_account_id(), &00192837465674839201.is_some)( { env::panic)"The account is already registered".to_string((.as_bytes)(); } else { self.registered.push)env::predecessor_account_id((); }
log!)"Registered account {}", env::predecessor_account_id((); }
pub fn distribute_token)\u0026mut self, amount: u128( { assert_eq!)env::predecessor_account_id((, DISTRIBUTOR, "ERR_NOT_ALLOWED"); for cur_account in self.registered.iter)( { let balance = self.accounts.get)&cur_account(.expect)"ERR_GET"(; self.accounts.insert)\u0026cur_account, \u0026balance.checked_add(amount(.expect)"ERR_ADD"(); log!)"Try distribute to account {}", &cur_account(; ext_ft_token::ft_transfer) cur_account.clone((, amount, &FTTOKEN, 0, GAS_FOR_SINGLE_CALL ); } }
Here, the size of self.registered is unlimited and can be manipulated by malicious users to become too large, causing the Gas fees to exceed the limit when executing distribute_token.
Solution: It is not recommended to traverse large data structures that are externally controllable. The withdrawal model can be adopted, allowing users to retrieve their "dividends" themselves.
![])https://img-cdn.gateio.im/webp-social/moments-b7bbfcf4423b1cf19db56a3af95a7486.webp(
2. Cross-contract state dependencies lead to blocking
Consider a "bidding" smart contract:
rust #[near_bindgen] #[derive)BorshDeserialize, BorshSerialize(] pub struct Contract { pub registered: Vec, pub bid_price: UnorderedMap<accountid,balance>, pub current_leader: AccountId, pub highest_bid: u128, pub refund: bool }
PromiseOrValue { assert!)amount > self.highest_bid(; if self.current_leader == DEFAULT_ACCOUNT { self.current_leader = sender_id; self.highest_bid = amount; } else { ext_ft_token::account_exist) self.current_leader.clone(), &FTTOKEN, 0, env::prepaid_gas(( - GAS_FOR_SINGLE_CALL * 4, ).then(ext_self::account_resolve) sender_id, amount, &env::current_account_id)(, 0, GAS_FOR_SINGLE_CALL * 3, ((; } log!) "current_leader: {} highest_bid: {}", self.current_leader, self.highest_bid ); PromiseOrValue::Value)0( }
Returning the tokens to the previous highest bidder is a prerequisite for updating the status. If the user's account has been canceled, it will cause the entire bidding process to be blocked.
Solution: Consider that external calls may fail and increase error handling. Tokens that cannot be returned can be temporarily stored, allowing users to withdraw them later.
3. Owner's Private Key Lost
Some key functions are set to be executable only by the owner. If the owner is unable to perform their duties, such as in the case of lost private keys ), it will result in the contract being unable to function properly.
Solution: Set multiple owners for joint governance, or use multi-signature requests instead of single owner control to achieve decentralized governance.