## 0x00: 概述 以太坊是一个公共网络,在设计合约的接口时,除了考虑己方的交互外,还应该考虑公众是否方便获取到合约中的数据。 <br> ## 0x01: 举例 现有一个订单簿交易系统,存在一个订单结构体, 包含owner,amount,price字段: ```solidity struct Booking { address owner; uint256 amount; uint256 price; } ``` 另外还有个订单id,通过mapping进行存储: ```solidity mapping(uint256 => Booking) public bookings; ``` <br> 有些时候,项目开发方会在前端或者后端生成id(比如生成一个随机数),然后id存放到官方服务器中,便于后续使用。这种情况,合约中创建订单的函数可能会是这样子: ```solidity function createBooking(uint256 _id, uint256 _amount, uint256 _price) public { Booking storage booking = Booking[_id]; booking.owner = msg.sender; booking.amount = _amount; booking.price = _price; } ``` 这样设计存在的问题是,**id是存放在官方服务器中的,公众难以获取到**。比较艰难的一个方法是遍历所有交易,通过参数得到全部的id。这样导致公众不得不选择使用官方提供的应用程序与合约交互,而无法通过区块浏览器或自己写脚本交互。 <br> ## 0x02: 建议 对于上面的例子,为了让公众也能愉快地交互,可以添加一个存储id的数组: ```solidity uint256[] public ids; ``` 或者,id由订单的某些数据生成: ```solidity id = keccak256(abi.encodePacked(msg.sender, _price)); ``` 可根据具体需求选择... <br> 话又说回来,对于合约的设计,效率和存储也占有较高的优先级。那么,也应当触发一个事件,像这样: ```solidity function createBooking(uint256 _id, uint256 _amount, uint256 _price) public { Booking storage booking = Booking[_id]; booking.owner = msg.sender; booking.amount = _amount; booking.price = _price; // 触发事件 emit CreateBooking(_id, msg.sender, _amount, _price); } ```