怎样实现以太坊交易可靠提交
在真实环境下的以太坊Dapp开发,是一定涉及到链上链下逻辑的交互的。那么开发者可能会遇到这样一种场景,当用户使用metamask签名交易并提交后,Dapp的中心服务端需要拿到这个交易ID,并跟踪这个交易的执行,甚至会根据这笔交易去触发后端逻辑(当然使用event可以一定程度避开这个问题,但这种回避式的解决方案不在此讨论),但现实情况往往是令人痛苦的,因为很可能会因为种种原因,我们无法取到metamask的回调,导致开发者因此”丢失”掉这笔交易。
那么,如果我们要直面这个问题,要怎么样实现交易可靠提交呢?
提炼问题
首先,我再次描述下问题的发生场景: 在metamask环境下,我们需要拿到用户提交的交易来触发后续中心化逻辑,但是在现实情况下很可能拿不到这个回调交易ID.
看起来,问题的核心并不是交易可靠提交,而是可靠地拿到交易提交的回调。那么解决问题,就有两种思路:
1. 最显而易见,metamask能够提供可靠回调
这个解决方案最无痛,然而完全依赖于metamask团队的开发意愿。所幸的是metamask团队在接收开发者的反馈后,有意愿往这方面努力。但开发时间不确定,甚至于我认为,在浏览器环境下,可能无法完美解决。所以短期内,这个方向是无法在生产环境实施的。
2. metamask将交易签名和发送拆分开来
如果没做过以太坊Dapp开发,可能不清楚metamask提交交易其实是串行执行了两步操作: 一.先对交易裸数据签名,得到签名后的交易,二.将签名后的交易提交到以太坊。
实际上,在metamask完成第一步签名后,这个交易就已经是一笔以太坊合法交易了,任何一个以太坊节点都可以拿着这笔交易进行全网广播,要求矿工打包。试想,如果metamsk将这两个操作拆分开来,那么开发者就可以要求metamask先对裸交易签名,然后客户端将这笔交易发送给服务端,让服务端向以太坊节点提交交易,这样应用开发者就能够使用各种传统手段保证交易提交,并且能够实施后续各种中心化逻辑了。
看似很美好,然而metamask目前不提供这样的接口。虽然web3js已经有这样的接口,但metamask并没有对接。不过前景还是可以期望的,metamask团队表示已经会进行操作拆分,将来可以这样做。详细可以参考Issue#3475.
3. 弄脏手自己做
既然靠不了别人,就自己来解决。这第3种解决方案,其实和第二种思路是一样的,只是达到这个目的有些纠结。
首先,metamsk支持web3js一个比较原始的签名方法web3.eth.sign
,他是对一段数据进行以太坊签名,看起来可以满足我们的需求,不过为了使用这个方法我们还需要做很多工作。
该方法输入是交易的hash,但web3并没有提供从裸交易数据计算hash的方法,所以我选择让前端提交裸交易数据到服务端,服务端计算出hash值返还给前端;
前端拿到这个交易hash后,就可以调用web3.eth.sign
唤起metamask签名,然后将签名字段和裸交易数据再次发送给服务端,服务端负责验证签名并且将交易和签名拼装好后发送到以太坊。
关键实现
1.前端获取裸交易数据
前端直面用户,可以拿到裸交易全部数据
1 2 3 4 5 6 7 8 9 |
|
2.后端计算裸交易hash
后端拿到前端的裸交易json,可以很容易计算出交易hash,下面给出计算的golang代码
1 2 |
|
然后将计算出的hash返回给前端
3.前端唤起metamask签名
1 2 3 |
|
这里将唤起metamask.
4.后端发送交易
前端将裸交易数据和第3步得到的签名发送给后端,后端验证签名并发送到以太坊,关键go代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
反思
看起来,上面的技术方案好像完美解决了问题,实则不然,这只是当前环境下的较优方案罢了,并且这个方案还是存在诸多问题:
1.安全性
这是最大的问题,因为调用web3.eth.sign
进行数据签名时,metamask无法展示签名的数据,所以用户根本不了解他到底是在对什么授权签名。这是非常可怕的,这可能被骇客利用,让用户对一笔转出自己账户所有余额的交易进行签名,导致资金盗窃。
2.用户体验
还是因为签名的方法,metamask在签名时会展示一段红色警告,导致用户体验下降。
3.时效性
因为这个安全原因,metamask团队将来也许会放弃对这个方法的支持,不过我倒是觉得,保留对这个方法的支持,将签名数据做详细展示,让开发者自己做安全性的权衡。
最后聊一点感想吧,目前区块链上簇拥了太多投机者,真正致力于深耕技术的人不多,metamask团队算一个,区块链是个有意思的技术,因为它的技术背后,隐含了人类社会化的意识,它目前的基础组件都还不够完善,需要我们热爱技术的所有人,去投入,去发展。