首页 手机兼职平台区块链正文

一文弄清以太坊开发者常见误解:Gas、交易与智能合约等

网赚之家 区块链 2020-11-27 08:30:58 8011 0

|spalladino&&

关于 Gas 的误解

调用 estimateGas 会回来买卖所需耗费的 gas 量

调用 estimateGas 的确会回来一个 gas 耗费量,但这是该笔买卖在当时状况下被打包会花费的 gas 量。而区块链的当时状况或许与你需求该笔买卖上链时的状况截然不同。因而,当你的买卖被有用打包进区块时,或许会选用不同的代码途径,需求耗费的 gas 量也有或许彻底不同。

假如履行的代码相同,我的买卖所需耗费的 gas 量也相同。

不对。即便你运用相同的参数来履行相同的指令,gas 本钱也有或许不同。例如,比较现已有非零值的存储方位,假如你要写入新的存储方位,SSTORE (写入存储操作)的本钱会高得多(拜见 EIP2200)。这就意味着,假如你向一个新地址发送两笔 ERC20 代币转账,第一笔买卖的本钱会比第二笔高得多,即便二者履行的代码彻底相同。

假如状况彻底相同,我的买卖所需耗费的 gas 量也相同

通常状况下是的,除非你很倒运地碰上了硬分叉,导致一些操作从头定价。虽然这听起来很杂乱,但说白了便是,你无法针对 dApp 中买卖的 gas 上限进行安全的硬编码,除非你决计在每次发僵硬分叉后都发布 dApp 更新。

假如代码相同,状况也相同,且没有发僵硬分叉,我就能够信任 estimateGas 的回来值了吗?

这下你能够信任 estimateGas 的回来值便是你的买卖所需耗费的 gas 量了,可是你不知道这笔买卖是否会如你所愿的那般进行。所谓的 gas 估测,便是节点将运用不同的 gas 值来测验你的买卖,并回来保证你的买卖不会失利的最低 gas 值。可是,节点只会看你的买卖,不会看买卖的内部调用。这就意味着,假如你调用的合约代码有一个 try/catch 块,导致内部调用产生后无法吊销,你取得的 gas 估测值对调用合约来说是够用的,可是对被调用合约来说就不行了。

在多签名钱包中,这种状况常常产生:即便是在买卖失利的状况下,大大都多签钱包会将操作标记为已履行,也便是说它们无法吊销最外层的买卖(所带来的影响)。因而,一个原生的 gas 估测回来的值或许对多签代码来说是满足的,对你实践想运转的操作来说不一定满足。这便是为什么 Gnosis Safe 有一个专门的 gas 估测办法。

请注意,这也便是为什么由于 gas 不行而导致操作失利的状况很难发觉。内部调用或许会由于被分配到的 gas 太少而将 gas 耗尽,而买卖本身或许还有许多 gas 可用。这就意味着,检查买卖的 gas 运用量和 gas 上限并非检测 gas 过错的牢靠办法。

管他呢,我每次多发送点 gas 就好了

大都状况下,这个办法是管用的。可是请记住,合约是能够检查它在一笔买卖中收到的 gas 的。因而,能够垂手可得地将合约编写成,一旦收到过多 gas,买卖就会失利。不过我置疑的是,除了证明这一点外,这么做没有任何含义。

关于买卖的误解

只需节点接受了买卖,买卖就会被挖出

想得美哦。以太坊的网络拥堵会导致 gas 价格动摇很大,因而你的买卖或许会被逐出 mempool (等候被挖出的买卖调集)。假如 gas 价格飙升,你就需求从头发送买卖。

我能够稍微进步 gas 价格然后从头提交买卖

只需你将 gas 价格进步到与你交互的节点所需的最小量(拜见 txpool.pricebump ),那就没什么问题,不然仍是会被回绝。

矿工总挑选 gas 价格最高的买卖

并不一定。矿工能够为所欲为进行挑选。他们或许会为了自己的利益而塞入自己的买卖,乃至能够开一个协议外通道,为契合自己要求的用户打包买卖。

可是,即便他们依据收益来决议打包优先级,如何故最优办法填满区块也是一个背包问题(knapsack problem)。由于买卖无法被分割成几部分,所以,在 gas 上限为 10M 的区块中打包两个 5M gas 买卖,而不是一个 6M gas 的买卖,或许更为有利可图,即便 5M gas 买卖的 gas 价格低于 6M gas 买卖。

假如我以更高的 gas 价格发送相同的买卖,矿工会挑选后一个买卖来替换前一个买卖吗

替换买卖有必要在旧买卖上链之前发送到矿工那里。也便是说,假如你发送了替换买卖,你仍然需求监控你之前发送的同一个 nonce 下的一切买卖的哈希值。

关于 Nonce 的误解

我能够经过 getTransactionCount 得到我的下一笔买卖的 nonce

这取决于你所运用的区块参数。假如你依据最新区块来查询你的买卖记数,就会疏忽你的未打包买卖,并进一步导致你不小心掩盖你的某笔未打包买卖。

我能够经过 getTransactionCount('pending') 得到我的下一笔买卖的 nonce

虽然这在大大都状况下可行,可是你不能保证你的一切未打包买卖都在你所查询的节点的 mempool 中。假如你有许多未打包买卖,你所通讯的节点或许现已丢掉了其间一些买卖,可是这些买卖仍有或许存在于其它当地!

关于 Log 的误解

我能够经过继续调用 getLogs 来有用监控事情

虽然这是一个十分管用的办法(没错,说的便是轮询!),可是遇上链重组就会出问题。假如你要轮询最新区块上的新 log,你不会收到关于区块重组的告诉,也不知道你所看到的事情是否需求从头调整。

我能够经过装置过滤程序来有用监控事情

直到两周前,这还不是一种常见挑选,由于 Infura 不支持根据 http 的过滤程序,MetaMask 默许运用根据 http 的过滤程序,也便是说你的 dApp 有 99% 的用户都运用这种过滤程序(注:我或许有些夸张)。除了新事情之外,过滤程序还会告诉你因区块重组而删去的事情。可是,这就要求你正在与之交互的基础设施和节点坚持在线。假如它们可巧丢掉了过滤程序的状况,你就有或许错失重组事情。

我能够经过 websocket 订阅来有用监控事情

太好了!这样下来,除了要信任你的节点会坚持在线之外,你还要信任你自己会坚持在线,你和节点之间的衔接是牢靠的。我想知道这周你在参与 Zoom 会议时掉线了几回?

现在,我有必要供认,我现已对这个论题有点着迷了,以致于我在 Devcon 5 上就此进行了一场闪电讲演。假如你想了解更多内容,EIP234 很好地论述了这些应战的基本原理,ethereumjs-blockstream 则处理了这一问题。

关于合约的误解

智能合约是不行更改的

兄弟,假如你还有这种主意,你真的 out 了。我在一篇长达 30 页的文章中论述过这一点,真的十分长。

不包括任何 DELEGATECALL 的智能合约便是不行更改的

实践上,合约能够定时调用( CALL)到一个可变地址中,并将成果作为核算的一部分,或许作为更改状况的指令,然后更改正在运转的代码。

那不包括任何 DELEGATECALLCALL 的智能合约,总是不行更改的了吧?

还有 STATICCALL。别忘了 STATICCALL

不包括任何 CALL 的智能合约是不行更改的

你还得扫除一种状况:这个智能合约是经过 CREATE2 布置的,会在其初始码(initcode)中动态载入运转时,并且能够自毁。在这种状况下,「一切者」能够毁掉合约,并运用不同的代码在同一个地址上从头创立这个合约。

不包括任何 CALL 且不经过 CREATE2 布置的智能合约是不行更改的

还得扫除一种状况:这个合约是经过由 CREATE2 布置的合约布置的。因而,你需求追溯整个布置链条,找到开始创立合约的以太坊外部账户,保证没有任何猫腻,并且不存在自毁操作。这篇文章深化探求了这一问题。

关于 ERC20 代币的误解

我就不展开了,这个论题更适合写成一篇完好的文章。在与代币交互时,运用 OpenZeppelin 的 SafeERC20 (你能够在这篇文章中阅览更多相关内容)就好。请记住,在转账时,接收者所收到的代币并不一定等于发送者被扣除的代币。咱们来看下一部分吧。

关于以太币的误解

以太币的总供应量只会添加

咱们都知道,有许多以太币是无法运用的,有的是由于外部账户的私钥丢掉,有的是由于意外发送到全零地址,还有的是由于被卡在合约中无法处理(对不住,我没忍住)。总而言之,这部分以太币仍然存在,可是无法访问。

不过,有一种办法能够毁掉以太币。假如你指令一个合约自毁 selfdestruct 并指定其本身作为资金的接收方,这个合约内的一切以太币都将被毁掉。这就意味着,只需乐意毁掉比区块奖赏更多的以太币,就能够让以太币通缩。

我能够写一个能回绝任何故太币转入的合约

你或许知道,假如你没有声明任何 payable 办法,Solidity 会回绝一切发送到你的合约的以太币转账,避免资金被卡在合约内。可是,咱们也能够在不触发任何代码的状况下,将资金发送到合约内:要么将该合约指定为自毁操作奖赏的接收方,要么将其指定为区块奖赏的接收方。正如 @gorgos 在谈论中指出的那样,能够预先核算出合约布置地址,并在合约布置前将以太币发送到该地址。

便

gist.github.com

版权声明

本文仅代表作者观点,不代表网赚之家本站立场。
本文系作者授权发表,未经许可,不得转载。

评论