アルゴリズムとかオーダーとか

仕事で勉強したことなどをまとめてます

EthereumのsendTransaction時のvalidationエラー一覧

truffleを使ってContractをデプロイしようとした時などによく目にするエラーメッセージ

insufficient funds for gas * price + value

exceeds block gas limit

などのエラーはnodeがtransaction poolに新しくtransactionを追加する際のチェックに通らなかった時に発生します。
今回は、sendTransaction時に発生するこれらのvalidation erroについて調べたことをまとめます。
なお、これらのエラーが出た場合はtransaction poolに入らないため、そもそもtransactionは発行されていません。なのでetherを消費することもありません。

なお、go-ethereumの実装を参考にしていますので、他のethereum実装では違う可能性があります。

invalid sender

transactionに付与された署名が無効の場合に発生する。
基本的にweb3.jsなどのツールを使ってtransactionを発行している場合は発生しないはず。

nonce too low

current blockに格納されているnonceよりも小さいnonceが指定されていた場合に発生する。
web3.eth.sendTransactionでnonceを指定してる場合は注意が必要。基本的にnonceは自動でインクリメントされて送られるのでわざわざ手動で指定する必要はないはず。。。
ちなみにnonceはaccountごとに連番を付与する仕様となっています。なので、accountが違えばnonceの値も違いますし、連番でないといけないため、以前の値より+10のnonceを指定した場合は、間のnonceを埋めるtransactionが発行されるまでそのtransactionはblockに取り込まれません。

transaction underpriced

gasPriceがnodeの設定された最小値よりも小さい時に発生する。
default設定のgasPriceの最小値は1なので、gasPrice=0とかしない限り発生しないかも。

このエラーはnodeのpoolが満杯の時にも発生する可能性があります。
nodeのpoolが満杯の場合は一番安いtransactionのgasPriceと比較され、それよりも安い場合にやはりこのエラーが発生します。
なので、gasPriceに十分な額を指定しているのにこのエラーが発生する場合は、時間をおいてから再度実行するといいかもしれません。

replacement transaction underpriced

すでにpendingTransactionに取り込まれているtransactionを置き換えようとした時に、以前のtransactionより小さいgasPriceが指定されていた場合に発生する。
nodeはfromとnonceが同値のtransactionが送られてきた場合、同じtransactionとみなして古いものを新しいものに置き換えようとします。この時に、新しく送られてきたtransactionのgasPriceとpoolに取り込まれている古いtransactionのgasPriceを比較し、gasPriceが高い時だけ新しいtransactionに置き換えます。
多分滅多に見ないエラーメッセージだと思います。(僕はまだ見たことがない。。。)

insufficient funds for gas * price + value

fromが保持しているetherがtransactionで設定されたgas limit * gas priceよりも少ない時に発生する。
結構よく見るエラーです。保持etherが足りない場合に表示されます。実際に使用されるgas量ではなく、transactionに設定されたgas limitを元に計算されることに注意してください。このエラーはtransactionのgas limitかgas priceを調整するか、transactionを発行するaccountの保持しているether量を増やすと解消されます。

intrinsic gas too low

transactionに設定されているgas limitが最小値よりも小さい時に発生する。
必要となるgas limitの最小値は、transactionの種類とdata部のbyte数によって決定されます。
transactionの種類で必要とする最小値は以下のどちらか。

  • Contract creation するとき: 53000
  • それ以外: 21000

さらに、transactionのdata部に何らかのデータを入れている場合はbyte数に応じてgas量が加算されます。
byteデータで加算されるgas量はそのbyteの値が0かそれ以外かで違います。

  • 0の時: 4 gas
  • それ以外: 68 gas

(i.e. uint(1)をの場合、32byteデータで0が31個と1が1個になるので、 31 * 4 + 1 * 68 = 192 gasが加算されます)
これらを元に計算されたgas量がそのtransactionで最低必要になるgas limitです。なお、Contractを実行する時に必要になるgasはさらにここから加算されていくためもっと多くなります。

ちなみにtruffle develop(=testrpc / ganache)ではこのエラーメッセージはbase fee exceeds gas limitになってるようです。

exceeds block gas limit

transactionに設定されたgas limitが現在のblockに設定されたgas limitより大きい場合に発生する。
これも結構よく見ます。特にテストのためにropstenにデプロイする時によく発生します。ropstenのblock gas limitはだいたい4700000あたりで張り付いてるのですぐに超えちゃったりします。

negative value

transactionのvalue(=ether)がマイナスの場合に発生する。
基本的に発生することはないと思うのですが、RPCでtransactionを作成した場合に発生する可能性はあるみたいです。(と言ってもオーバーフローした時なので相当量のetherを指定しないとおきないんじゃないかなぁ?)

oversized data

transactionの格納されているdataが32KB以上の場合に発生する。
このエラーはDOS攻撃対策のためのエラーです。transactionのdata部に格納されたbyte数が32KBを超えている場合にエラーとなります。
現状のEthereumではこのエラーが発生する前に、gas limit制限に引っかかるため今の所は発生することはなさそうです。
設定を自由にいじれる private nodeだと発生しちゃったりするのかな?僕は見たことないです。

// ErrOversizedData is returned if the input data of a transaction is greater
// than some meaningful limit a user might use. This is not a consensus error
// making the transaction invalid, rather a DOS protection.

というコメントがついていたので、go-ethereum特有のチェックみたいですね。

まとめ

実際に調べてみると、見たことのないエラーもたくさんあって驚きました。特にoversized dataみたいに、transactionのdataサイズでも制限がかかっているなんて知らなかったです。Ethereumはgas limitでしか制限かけてないんだとばかり思っていたので。。。