以太坊(eth)交易所钱包开发 - 7 - 冲币提币回调

回调时序图大概如下

当用户冲币和提币的时候,我们需要把这些信息通知用户。这个通知我们也是通过http调用实现,只不过我们调用的是product中提供的回调地址。

比如用户冲币的时候,我们回调的内容是:

1
2
3
4
5
6
7
8
9
{
"address":"0xa94ae9cd4d3ad8a29697da180bda45040e633501",
"app_name":"app_1",
"balance":"0.0001",
"notify_type":1,
"sign":"97E589CEC28A80CD9FBCE0F042C08837",
"symbol":"eth",
"tx_hash":"0xd1fe86cc358f525e452cbab251adc403b531da230304e71887fda911a40e8286"
}

这里我们用相同的逻辑签名获得sign一同返回,因为tx_hash每笔交易都不相同,可以作为nonce使用。

创建一个表,用来储存待发送给客户端的通知,并保留返回值和处理状态。在发送时,如果遇到返回错误是需要重试的,这样能避免对方服务器出错或者网络出问题而错过消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE `t_product_notify` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`nonce` varchar(128) NOT NULL DEFAULT '',
`product_id` int(11) NOT NULL,
`item_type` int(11) NOT NULL,
`item_id` int(11) NOT NULL,
`notify_type` int(11) NOT NULL,
`url` varchar(512) NOT NULL DEFAULT '',
`msg` varchar(4089) NOT NULL,
`handle_status` int(11) NOT NULL,
`handle_msg` varchar(512) NOT NULL,
`create_time` bigint(20) unsigned NOT NULL,
`update_time` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `product_id` (`product_id`,`item_type`,`item_id`,`notify_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

有几个地方处理的时候需要将待发送数据存入待发送表。

  1. 检测区块链入账的时候
  2. 发送提币交易的时候
  3. 提币交易被确认打包的时候

发送通知也很简单,遍历这个表里没有成功的数据,逐个发送就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
gresp, body, errs := gorequest.New().Post(initNotifyRow.URL).Timeout(time.Second * 30).Send(initNotifyRow.Msg).End()
if errs != nil {
hcommon.Log.Errorf("err: [%T] %s", errs[0], errs[0].Error())
_, err = SQLUpdateTProductNotifyStatusByID(
context.Background(),
DbCon,
&model.DBTProductNotify{
ID: initNotifyRow.ID,
HandleStatus: 1,
HandleMsg: errs[0].Error(),
UpdateTime: time.Now().Unix(),
},
)
if err != nil {
hcommon.Log.Errorf("err: [%T] %s", err, err.Error())
}
continue
}
if gresp.StatusCode != http.StatusOK {
// 状态错误
hcommon.Log.Errorf("req status error: %d", gresp.StatusCode)
_, err = SQLUpdateTProductNotifyStatusByID(
context.Background(),
DbCon,
&model.DBTProductNotify{
ID: initNotifyRow.ID,
HandleStatus: 1,
HandleMsg: fmt.Sprintf("http status: %d", gresp.StatusCode),
UpdateTime: time.Now().Unix(),
},
)
if err != nil {
hcommon.Log.Errorf("err: [%T] %s", err, err.Error())
}
continue
}
resp := gin.H{}
err = json.Unmarshal([]byte(body), &resp)
if err != nil {
hcommon.Log.Errorf("err: [%T] %s", err, err.Error())
_, err = SQLUpdateTProductNotifyStatusByID(
context.Background(),
DbCon,
&model.DBTProductNotify{
ID: initNotifyRow.ID,
HandleStatus: 1,
HandleMsg: body,
UpdateTime: time.Now().Unix(),
},
)
if err != nil {
hcommon.Log.Errorf("err: [%T] %s", err, err.Error())
}
continue
}
_, ok := resp["error"]
if ok {
// 处理成功
_, err = SQLUpdateTProductNotifyStatusByID(
context.Background(),
DbCon,
&model.DBTProductNotify{
ID: initNotifyRow.ID,
HandleStatus: 2,
HandleMsg: body,
UpdateTime: time.Now().Unix(),
},
)
if err != nil {
hcommon.Log.Errorf("err: [%T] %s", err, err.Error())
}
} else {
hcommon.Log.Errorf("no error in resp")
_, err = SQLUpdateTProductNotifyStatusByID(
context.Background(),
DbCon,
&model.DBTProductNotify{
ID: initNotifyRow.ID,
HandleStatus: 1,
HandleMsg: body,
UpdateTime: time.Now().Unix(),
},
)
if err != nil {
hcommon.Log.Errorf("err: [%T] %s", err, err.Error())
}
continue
}

具体实现的代码已经传到了github https://github.com/moremorefun/go-dc-wallet

功能入口在

  • cmd/do_notify/main.go
  • cmd/eth_block_seek/main.go
  • cmd/eth_raw_tx_send/main.go
  • cmd/eth_raw_tx_confirm/main.go

坚持原创技术分享,您的支持鼓励我继续创作!