解釋這些 Solidity 智能合約的核心概念
我來詳細解釋這些 Solidity 智能合約的核心概念:
1. 合約生命周期
合約部署階段
// 1. 合約創(chuàng)建
contract MyContract {
// 2. 狀態(tài)變量初始化
uint256 public value;
address public owner;
// 3. 構造函數(shù)執(zhí)行
constructor(uint256 _initialValue) {
value = _initialValue;
owner = msg.sender;
}
// 4. 合約部署完成,可以接收交易
}
合約運行階段
contract LifecycleExample {
uint256 public state;
bool public isActive;
// 構造函數(shù) - 部署時執(zhí)行一次
constructor() {
state = 0;
isActive = true;
}
// 普通函數(shù) - 可被多次調用
function updateState(uint256 _newValue) public {
require(isActive, "Contract is not active");
state = _newValue;
}
// 自毀函數(shù) - 銷毀合約
function destroy() public {
require(msg.sender == owner, "Only owner can destroy");
selfdestruct(payable(owner));
}
}
生命周期階段總結
- 編譯:Solidity 代碼編譯為字節(jié)碼
- 部署:字節(jié)碼部署到區(qū)塊鏈
- 初始化:構造函數(shù)執(zhí)行
- 運行:接收交易和函數(shù)調用
- 銷毀:通過
selfdestruct銷毀(可選)
2. 事件 (Events)
事件定義和發(fā)出
contract EventExample {
// 定義事件
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowances;
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
// 發(fā)出事件
emit Transfer(msg.sender, to, amount);
}
function approve(address spender, uint256 amount) public {
allowances[msg.sender][spender] = amount;
// 發(fā)出事件
emit Approval(msg.sender, spender, amount);
}
}
事件的特點
- 日志記錄:事件數(shù)據(jù)存儲在區(qū)塊鏈日志中
- 索引參數(shù):最多3個
indexed參數(shù),便于搜索 - Gas 消耗:比存儲狀態(tài)變量便宜
- 不可修改:一旦發(fā)出,無法修改
事件 vs 狀態(tài)變量
contract Comparison {
uint256 public stateVariable; // 存儲在狀態(tài)中,消耗更多Gas
event StateChanged(uint256 newValue); // 存儲在日志中,消耗較少Gas
function updateState(uint256 _value) public {
stateVariable = _value;
emit StateChanged(_value); // 同時更新狀態(tài)和發(fā)出事件
}
}
3. Modifier(修飾符)
基本 Modifier
contract ModifierExample {
address public owner;
bool public paused;
// 基本修飾符
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_; // 執(zhí)行被修飾的函數(shù)
}
modifier whenNotPaused() {
require(!paused, "Contract is paused");
_;
}
modifier validAddress(address _addr) {
require(_addr != address(0), "Invalid address");
_;
}
// 使用修飾符
function setOwner(address _newOwner) public onlyOwner validAddress(_newOwner) {
owner = _newOwner;
}
function pause() public onlyOwner {
paused = true;
}
function unpause() public onlyOwner {
paused = false;
}
}
帶參數(shù)的 Modifier
contract AdvancedModifier {
mapping(address => uint256) public balances;
modifier hasBalance(uint256 _amount) {
require(balances[msg.sender] >= _amount, "Insufficient balance");
_;
}
modifier limitAmount(uint256 _maxAmount) {
require(msg.value <= _maxAmount, "Amount exceeds limit");
_;
}
function withdraw(uint256 _amount) public hasBalance(_amount) {
balances[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
function deposit() public payable limitAmount(10 ether) {
balances[msg.sender] += msg.value;
}
}
Modifier 執(zhí)行順序
contract ModifierOrder {
modifier first() {
console.log("First modifier");
_;
console.log("First modifier after");
}
modifier second() {
console.log("Second modifier");
_;
console.log("Second modifier after");
}
function test() public first second {
console.log("Function body");
}
// 輸出順序:
// First modifier
// Second modifier
// Function body
// Second modifier after
// First modifier after
}
4. Storage vs Memory
Storage(存儲)
contract StorageExample {
// 狀態(tài)變量存儲在 storage 中
uint256 public globalValue;
mapping(address => uint256) public balances;
function storageExample() public {
// 局部變量引用 storage
uint256 storage localValue = globalValue;
localValue = 100; // 修改會影響 globalValue
// 直接修改 storage
globalValue = 200;
}
}
Memory(內存)
contract MemoryExample {
uint256 public globalValue;
function memoryExample() public {
// 局部變量存儲在 memory 中
uint256 memory localValue = globalValue;
localValue = 100; // 不會影響 globalValue
// 數(shù)組示例
uint256[] memory tempArray = new uint256[](3);
tempArray[0] = 1;
tempArray[1] = 2;
tempArray[2] = 3;
// 函數(shù)執(zhí)行完畢后,memory 數(shù)據(jù)被清除
}
}
詳細對比
| 特性 | Storage | Memory |
|---|---|---|
| 位置 | 區(qū)塊鏈狀態(tài) | 函數(shù)執(zhí)行期間 |
| 持久性 | 永久存儲 | 臨時存儲 |
| Gas 消耗 | 高 | 低 |
| 訪問速度 | 慢 | 快 |
| 作用域 | 合約級別 | 函數(shù)級別 |
實際應用示例
contract StorageMemoryExample {
uint256[] public storageArray;
function demonstrateDifference() public {
// Storage 引用
uint256[] storage s = storageArray;
s.push(1); // 會影響 storageArray
// Memory 復制
uint256[] memory m = storageArray;
m.push(2); // 不會影響 storageArray
// 修改 memory 后賦值給 storage
storageArray = m; // 現(xiàn)在 storageArray 包含 memory 的修改
}
function gasOptimization() public {
// 使用 memory 減少 Gas 消耗
uint256[] memory tempArray = new uint256[](100);
for (uint256 i = 0; i < 100; i++) {
tempArray[i] = i;
}
// 一次性寫入 storage
storageArray = tempArray;
}
}
5. 綜合示例:完整的合約生命周期
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CompleteExample {
// 狀態(tài)變量 (Storage)
address public owner;
uint256 public totalSupply;
mapping(address => uint256) public balances;
bool public paused;
// 事件
event Transfer(address indexed from, address indexed to, uint256 value);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event Paused(address account);
event Unpaused(address account);
// 修飾符
modifier onlyOwner() {
require(msg.sender == owner, "Ownable: caller is not the owner");
_;
}
modifier whenNotPaused() {
require(!paused, "Pausable: paused");
_;
}
// 構造函數(shù) - 合約部署時執(zhí)行
constructor(uint256 _initialSupply) {
owner = msg.sender;
totalSupply = _initialSupply;
balances[msg.sender] = _initialSupply;
emit Transfer(address(0), msg.sender, _initialSupply);
}
// 普通函數(shù)
function transfer(address to, uint256 amount) public whenNotPaused {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
emit Transfer(msg.sender, to, amount);
}
// 使用 memory 優(yōu)化 Gas
function batchTransfer(address[] memory recipients, uint256[] memory amounts) public whenNotPaused {
require(recipients.length == amounts.length, "Arrays length mismatch");
uint256 totalAmount = 0;
for (uint256 i = 0; i < amounts.length; i++) {
totalAmount += amounts[i];
}
require(balances[msg.sender] >= totalAmount, "Insufficient balance");
balances[msg.sender] -= totalAmount;
for (uint256 i = 0; i < recipients.length; i++) {
balances[recipients[i]] += amounts[i];
emit Transfer(msg.sender, recipients[i], amounts[i]);
}
}
// 管理函數(shù)
function pause() public onlyOwner {
paused = true;
emit Paused(msg.sender);
}
function unpause() public onlyOwner {
paused = false;
emit Unpaused(msg.sender);
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
// 自毀函數(shù) - 合約生命周期結束
function destroy() public onlyOwner {
selfdestruct(payable(owner));
}
}
總結
合約生命周期
- 編譯 → 部署 → 初始化 → 運行 → 銷毀
事件的作用
- 記錄重要狀態(tài)變化
- 提供鏈下監(jiān)聽接口
- 比存儲狀態(tài)變量更便宜
Modifier 的優(yōu)勢
- 代碼復用
- 權限控制
- 條件檢查
- 提高代碼可讀性
Storage vs Memory
- Storage:永久存儲,高 Gas 消耗
- Memory:臨時存儲,低 Gas 消耗
- 合理選擇可以優(yōu)化 Gas 消耗
這些概念共同構成了 Solidity 智能合約開發(fā)的基礎,理解它們對于編寫高效、安全的智能合約至關重要。

浙公網(wǎng)安備 33010602011771號