hiro99ma blog

Something technical

btc: 520バイトは1スタックのサイズ上限

2025/02/28

はじめに

Bitcoin の開発をしているといってもすべての仕様を把握しているわけではない。 もちろん把握していると良いのだろうが、私には無理だ。 エラーが起きたりすれば気付くのだが、普通に開発していると出くわさないことも多い。

こうやってブログを書いていると、普段は接しない仕様に出くわしたり、見かけたりする。 今回思いだした仕様は、そういえば 520 とかいうサイズの上限があったなあ、という曖昧なものだ。

520 はスクリプトの PUSH サイズ上限

適当に探してみたのだが行き詰まったので ChatGPT 氏に問い合わせた。 曖昧な条件で探してくれるのは非常に助かる。

Bitcoinトランザクションの何かの上限として510バイトか520バイトがあったような気がしますが、そういう上限はありますか?

いろいろその後も質問したのだが、トランザクションの仕様というよりも Bitcoinスクリプトの設計から来たものだそうだ。

上限らしき数値をいくつか拾ったが、P2TR でも同じだろう。
ただ P2TR は key path と script path があるので、評価しないルートにはこの制限が影響しないことは気をつけた方がよいだろう。

さて、話を戻して。
Constants にスタックにデータを載せる命令が載っている。

というのが命令によるスタックできるサイズの理論的な仕様なのだが、520 バイトが上限なので実質 OP_PUSHDATA4 は使用できない。 segwit では scriptSig は空だが witness にスクリプトを載せるのでルールは同じだろう。

“520” の元

ChatGPT 氏は “520” についての BIP は無いといっていたのだが、 P2SH に関する BIP である BIP-16 の 520-byte limitation on serialized script size がそれだろう。
ただ、なんで 520 になったのかはよくわからないが、互換性に触れているので何か都合があったのだろう。

おわりに

Bitcoin スクリプトの 1スタックには 520 バイトという上限があることが分かった。
まあ、なかなかその上限まであるようなスクリプトを作るのは難しいと思うが、あるにはあるのだ。

他にも 10KB(10 x 1000)バイトというスクリプト自体の上限もあった。
MultiSig だと鍵数に比例して増えるので注意しよう。 たぶんトランザクション自体は作ることができて、アドレスを作って送金し、それを解こうと redeem transaction を展開しようとしてエラーになる、みたいなことになるだろう。
気をつけよう。

おまけ

符号付き?符号無し?

Bitcoin スクリプト内では数値の表現はリトルエンディアンである。
ではその値は符号付きなのだろうか、あるいは符号無しなのだろうか。

私はスクリプトを調べるときにこのページを見ている。

The stacks hold byte vectors.
When used as numbers, byte vectors are interpreted as little-endian variable-length integers with the most significant bit determining the sign of the integer.
Thus 0x81 represents -1.
0x80 is another representation of zero (so called negative 0).
Positive 0 is represented by a null-length vector.
Byte vectors are interpreted as Booleans where False is represented by any representation of zero and True is represented by any representation of non-zero.

最上位ビットが符号を表すので符号付きだ。
ネガティブゼロがあるということは 1の補数? と思ったがそれとも違う(と ChatGPT氏に言われた)。
単に最上位ビットに 1 を立てると負の数になるだけで、ビット反転したりはしない方式とのこと。 例えば -5 を 1バイトで表すと、1の補数なら反転して 0xf5 だがスクリプトでは 0x85 になる。

では OP_PUSHDATA1のサイズ指定はどうなっているのだろうか。
そのルールに従うと 0xef あたりが最大になりそうなのだが。
実装 は単純に unsigned な 1 byte を使っていた。


 < Top page


コメント(Google Formへ飛びます)

GitHub

X/Twitter

Homepage