Solidity全局变量与安全实践指南

1. 区块与交易属性
solidity 复制代码
function getBlockData() public view returns (
    uint number, 
    uint timestamp, 
    uint gasLimit,
    address miner
) {
    return (
        block.number,       // 当前区块号
        block.timestamp,   // 区块时间戳(Unix秒)
        block.gaslimit,    // 当前区块的gas上限
        block.coinbase     // 矿工地址
    );
}

function getTxData() public view returns (
    uint gasPrice,
    address origin
) {
    return (
        tx.gasprice,      // 当前交易的gas价格
        tx.origin         // 原始交易发送者(慎用!)
    );
}
2. 消息属性 (msg)
solidity 复制代码
function processPayment() public payable {
    // 获取调用信息
    address sender = msg.sender;
    uint value = msg.value;
    bytes4 selector = msg.sig;
    
    // 验证至少转账1 ETH
    require(value >= 1 ether, "Minimum 1 ETH required");
    
    // 记录交易
    payments[sender] += value;
}
3. 地址操作
solidity 复制代码
// 安全ETH转账
function sendEther(address payable to, uint amount) public {
    // 检查合约余额
    require(address(this).balance >= amount, "Insufficient balance");
    
    // 使用call代替transfer/send (推荐)
    (bool success, ) = to.call{value: amount}("");
    require(success, "Transfer failed");
}

// 调用其他合约
function callExternalContract(
    address contractAddr, 
    string memory funcSig,
    uint param
) public {
    bytes memory data = abi.encodeWithSignature(funcSig, param);
    (bool success, bytes memory result) = contractAddr.call(data);
    
    require(success, "External call failed");
    // 处理返回结果...
}

// 检查合约余额
function checkBalance(address addr) public view returns (uint) {
    return addr.balance;  // 地址的ETH余额(wei)
}
4. ABI编码/解码
solidity 复制代码
// 创建函数调用数据
function createTransferData(
    address recipient, 
    uint amount
) public pure returns (bytes memory) {
    return abi.encodeWithSignature(
        "transfer(address,uint256)", 
        recipient, 
        amount
    );
}

// 解析数据
function decodeData(
    bytes memory data
) public pure returns (address, uint) {
    (address recipient, uint amount) = abi.decode(
        abi.decode(data[4:]),  // 跳过函数选择器
        (address, uint)
    );
    return (recipient, amount);
}
5. 数学与加密
solidity 复制代码
// 创建唯一标识符
function createTokenId(
    string memory name, 
    address owner
) public pure returns (bytes32) {
    return keccak256(abi.encodePacked(name, owner));
}

// 签名验证
function verify(
    bytes32 messageHash,
    uint8 v,
    bytes32 r,
    bytes32 s
) public pure returns (address) {
    return ecrecover(messageHash, v, r, s);
}

// 安全数学运算
function safeModAdd(
    uint a,
    uint b,
    uint mod
) public pure returns (uint) {
    return addmod(a, b, mod);
}
6. 错误处理
solidity 复制代码
function withdraw(uint amount) public {
    // 检查条件
    require(
        balances[msg.sender] >= amount, 
        "Insufficient balance"
    );
    
    // 更新状态
    balances[msg.sender] -= amount;
    
    // 执行转账
    (bool success, ) = msg.sender.call{value: amount}("");
    
    // 自定义错误处理
    if (!success) {
        revert WithdrawFailed(msg.sender, amount);
    }
}

// 自定义错误类型
error WithdrawFailed(address sender, uint amount);

// 内部一致性检查
function validateState() public view {
    assert(totalSupply == calculateTotalSupply());
}
7. 合约操作
solidity 复制代码
// 获取合约信息
function getContractInfo() public view returns (
    address contractAddress,
    uint balance
) {
    return (
        address(this),       // 当前合约地址
        address(this).balance // 合约ETH余额
    );
}

// 安全销毁合约
function destroyContract() public onlyOwner {
    // 保存所有者地址
    address owner = owner;
    
    // 清除状态
    delete owner;
    
    // 销毁合约并发送余额
    selfdestruct(payable(owner));
}
8. Gas 操作
solidity 复制代码
function optimizeGas() public {
    uint startGas = gasleft();
    
    // 执行复杂操作...
    for(uint i = 0; i < 100; i++) {
        // 某些操作
    }
    
    uint gasUsed = startGas - gasleft();
    emit GasConsumed(gasUsed);
}
9. 类型信息
solidity 复制代码
// 获取接口ID (ERC-165)
function getERC721InterfaceId() public pure returns (bytes4) {
    return type(IERC721).interfaceId;
}

// 检查合约支持的接口
function supportsInterface(
    address contractAddr,
    bytes4 interfaceId
) public view returns (bool) {
    (bool success, bytes memory result) = contractAddr.staticcall(
        abi.encodeWithSignature("supportsInterface(bytes4)", interfaceId)
    );
    
    return success && abi.decode(result, (bool));
}

关键实践建议

  1. 安全转账模式
solidity 复制代码
// 安全转账模板
function safeTransferETH(address to, uint value) internal {
    (bool success, ) = to.call{value: value}(new bytes(0));
    require(success, "ETH transfer failed");
}
  1. call vs delegatecall
solidity 复制代码
// 普通调用:在目标合约上下文中执行
contractA.call(abi.encodeWithSignature("func()"));

// 委托调用:在当前合约上下文中执行目标合约代码
contractB.delegatecall(abi.encodeWithSignature("func()"));
  1. 时间戳使用警告
solidity 复制代码
// 不安全的随机数生成(容易被矿工操纵)
uint badRandom = uint(keccak256(abi.encodePacked(block.timestamp)));

// 更安全的方案(但仍不完全安全)
uint betterRandom = uint(keccak256(abi.encodePacked(
    block.timestamp, 
    block.difficulty,
    msg.sender
)));
  1. ABI编码最佳实践
solidity 复制代码
// 安全:明确指定类型防止哈希碰撞
bytes32 safeHash = keccak256(abi.encode(
    "Transfer(address,uint256)",
    recipient,
    amount
));

// 危险:紧密打包可能导致不同类型数据碰撞
bytes32 unsafeHash = keccak256(abi.encodePacked(
    "Transfer",
    recipient,
    amount
));

这些全局属性和方法是 Solidity 智能合约开发的基石,正确理解和使用它们对于编写安全、高效的合约至关重要。在实际开发中,始终优先考虑安全性,特别是处理资金转账和外部调用时。