---
# System prepended metadata

title: Solidity合约开发小贴士
tags: [Smart Contract, Solidity]

---

## 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);
}
```

