DTeam 技术日志

Doer、Delivery、Dream

Ethers.js 非权威开发指南(续)

胡键 Posted at — Feb 14, 2022 阅读
<p>原本以为两篇文章的内容应该足以覆盖 <a href="https://docs.ethers.io/v5/">Ethers.js</a> 的关键内容,但目前看来似乎还有些遗漏,于是乎就有了这个续篇。与之前的风格一样,本篇的内容同样采用问题驱动的风格。</p> <p>在本篇中,你可以了解到:</p> <ul> <li>不要忽视地址</li> <li>如何读取合约中的 public 变量</li> <li>合约地址不定,仅能确定事件名,如何监听。</li> <li>优化 infura 调用次数</li> <li>留意日志查询的跨度</li> <li>对接其他网络</li> <li>值得了解的 ethers 周边工具</li> </ul> <p>相比前两篇包含的都是实战代码,本篇则更偏向于开发策略和一些优化方法的总结。</p> <h2 id="看似简单的地址">看似简单的地址</h2> <p>从接触 dapp 开发的第一天,你就要跟地址打交道,不论是 EOA 还是 contract address,离了任何一个都很难开发出有意义的应用。地址本身,其实没有什么太多的复杂性,即便你不了解以下的几个事实,也并不影响应用的开发:</p> <ul> <li>地址可以由私钥或者公钥生成:<code>ethers.utils.computeAddress</code></li> <li>它可以由用户签名恢复:参见<a href="../2021-06/ethersjs-indefinitive-guide-part2.html">下篇</a>。</li> <li>它可以由部署交易号获得:<code>ethers.utils.getContractAddress</code></li> <li>它也可以提前计算出来:参见 <a href="https://blog.smartdec.net/how-to-define-smart-contract-address-before-the-deploy-create2-use-case-for-decentralized-exchange-52b7daa7873b">How to Define Smart Contract Address Before the Deploy</a>。</li> </ul> <p>然而,一个容易忽略的细小地方却可能对于你的 dapp 体验带来比较大的影响,虽然这个影响在数据量小的时候并不会暴露出来:<strong>地址同时包含了大小写</strong>。</p> <p>这种地址有个专有名称:<code>Checksum 地址</code>,并且 ethers 也提供了方法来得到它:<code>ethers.utils.getAddress</code>。对于一般 dapp 来说,如何生成和计算 checksum 地址并不重要,真正值得关注的地方在于:你打算如何保存地址?</p> <p>我在<a href="../2022-01/patterns-of-eth-state-synchronization.html">这篇状态同步的文章</a>里曾经解释过为何要做状态同步的同步的原因,也提到过一般会利用数据库来作为状态同步数据的存储。看到这里,有经验的朋友应该很快就会明白我的潜台词:地址的大小写会影响数据查询的速度!</p> <p>没错,这正是我的意思。看看典型的一个开发场景:<code>findSomethingByAddress</code>。它的几个版本的演进可能是这样的:</p> <ul> <li>version 1: 后端直接将前端传入的参数传入查询:</li> </ul> <div class="highlight"><pre tabindex="0" style="color:#586e75;background-color:#eee8d5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#859900">select</span> * <span style="color:#859900">from</span> <span style="color:#268bd2">some_table</span> <span style="color:#859900">where</span> <span style="color:#268bd2">address</span> = $<span style="color:#2aa198;font-weight:bold">1</span> </span></span></code></pre></div><ul> <li>很快就会遇到经典场景:前端说这个地址明明应该有数据,但后端却没有返回。后端一检查,恍然大悟:地址大小写的问题。于是查询变成 version 2:</li> </ul> <div class="highlight"><pre tabindex="0" style="color:#586e75;background-color:#eee8d5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#859900">select</span> * <span style="color:#859900">from</span> <span style="color:#268bd2">some_table</span> <span style="color:#859900">where</span> <span style="color:#268bd2">address</span> <span style="color:#859900">ilike</span> $<span style="color:#2aa198;font-weight:bold">1</span> </span></span></code></pre></div><p>当然,也可以利用字符串函数把大小写统一转换再用相等比较来实现,但是 <code>ilike</code> 最省事嘛,😄。</p> <ul> <li>随着数据的积累,开始有人抱怨查询慢了,于是有人说:给 address 加上索引。</li> </ul> <p>然而,问题似乎并没有解决。</p> <p>原因很简单:<code>ilike</code> 不会命中索引。并且,如果即使前面用了函数加相等判断来解决,也会有同样的问题,或许熟悉数据库(如 PG)的同学会说:利用表达式索引就行了。</p>

本文是付费文章,剩余内容请访问以下链接支付之后继续阅读:

付费链接 (已付费:10)

友情链接


相关文章