3分钟Solidity: 4.8 高级事件

29 阅读2分钟

如需获取本内容的最新版本,请参见 Cyfrin.io 上的Events Advanced(代码示例)

本页面涵盖了与Solidity事件相关的高级主题和用例,建立在事件页面所介绍的基础知识之上。

Solidity中的事件是一种强大的工具,能够实现各种高级功能和架构。事件的一些高级用例包括:

  • 事件过滤与监控,实现实时更新与分析
  • 事件日志分析与解码,用于数据提取和处理
  • 为去中心化应用(dApp)设计的事件驱动架构
  • 事件订阅功能,提供实时通知与更新

事件驱动架构

EventDrivenArchitecture合约展示了一种事件驱动架构,其中事件用于协调和触发流程的不同阶段,例如启动和确认转账。

事件订阅与实时更新

EventSubscription合约展示了如何实现事件订阅,允许外部合约或客户端订阅并在事件触发时接收实时更新。

它还演示了如何处理事件订阅以及管理订阅的生命周期。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.14;

// 事件驱动架构
contract EventDrivenArchitecture {
    event TransferInitiated(
        address indexed from, address indexed to, uint256 value
    );
    event TransferConfirmed(
        address indexed from, address indexed to, uint256 value
    );

    mapping(bytes32 => bool) public transferConfirmations;

    function initiateTransfer(address to, uint256 value) public {
        emit TransferInitiated(msg.sender, to, value);
        // ... (初始化转账逻辑)
    }

    function confirmTransfer(bytes32 transferId) public {
        require(
            !transferConfirmations[transferId], "转账已确认"
        );
        transferConfirmations[transferId] = true;
        emit TransferConfirmed(msg.sender, address(this), 0);
        // ... (确认转账逻辑)
    }
}

// Event Subscription and Real-Time Updates
interface IEventSubscriber {
    function handleTransferEvent(address from, address to, uint256 value)
        external;
}

contract EventSubscription {
    event LogTransfer(address indexed from, address indexed to, uint256 value);

    mapping(address => bool) public subscribers;
    address[] public subscriberList;

    function subscribe() public {
        require(!subscribers[msg.sender], "已订阅");
        subscribers[msg.sender] = true;
        subscriberList.push(msg.sender);
    }

    function unsubscribe() public {
        require(subscribers[msg.sender], "未订阅");
        subscribers[msg.sender] = false;
        for (uint256 i = 0; i < subscriberList.length; i++) {
            if (subscriberList[i] == msg.sender) {
                subscriberList[i] = subscriberList[subscriberList.length - 1];
                subscriberList.pop();
                break;
            }
        }
    }

    function transfer(address to, uint256 value) public {
        emit LogTransfer(msg.sender, to, value);
        for (uint256 i = 0; i < subscriberList.length; i++) {
            IEventSubscriber(subscriberList[i]).handleTransferEvent(
                msg.sender, to, value
            );
        }
    }
}

最佳实践与建议

  • 索引正确的事件参数以实现高效的过滤和搜索。地址通常应被索引,而金额通常不应被索引。
  • 避免冗余事件,不要发出已被底层库或合约涵盖的事件。
  • 事件不能在viewpure函数中使用,因为它们通过存储日志来改变区块链的状态。
  • 注意与发出事件相关的gas成本,特别是在索引参数时,因为它可能影响合约的整体gas消耗。

Remix Lite 尝试一下

solidity-event_advanced


END