Appearance
S1C12: Give Me The Block!
1. 問題
mintFlag を呼び出すために、正しい RLP エンコードされたブロックヘッダーを提供する必要があります。コントラクトはブロックヘッダーのタイムスタンプ、難易度などのフィールドを検証します。
2. 原因
コントラクトはライトクライアント方式のブロック検証を実装しています:RLP エンコードされたブロックヘッダーを受け取り、デコード後にブロック番号が許可範囲内(現在のブロック番号 - 256 から現在のブロック番号 - 2)にあるか、および他のフィールドの正当性をチェックします。
3. 解法
- 現在のトランザクションがパックされるのを待ちます(
block.numberを取得します) - 少なくとも2ブロック待ちます
eth_getBlockByNumberを使用して履歴ブロックの完全なヘッダー情報を取得します- そのブロックヘッダーを RLP エンコードします
- 256ブロックのウィンドウ内で送信します
javascript
// ブロックヘッダーを取得して RLP エンコードします
const block = await provider.getBlock(blockNumber);
const rlpEncoded = ethers.utils.RLP.encode([
block.parentHash,
block.sha3Uncles,
block.miner,
block.stateRoot,
block.transactionsRoot,
block.receiptsRoot,
block.logsBloom,
block.difficulty,
block.number,
block.gasLimit,
block.gasUsed,
block.timestamp,
block.extraData,
block.mixHash,
block.nonce,
]);
4. 遭遇した落とし穴
RLP エンコーディング形式: OP Mainnet のブロックヘッダーフィールドエンコーディングはイーサリアムメインネットと同じですが、微妙な違いがあります。cast block の出力形式は RLP フレンドリーな数値形式に変換する必要があります。
5. 落とし穴の原因
RLP は各フィールドに厳格なエンコーディング要件があり、数値型は先行ゼロを除去する必要があります。OP は Bedrock アップグレード後のブロック形式を使用しており、特定のフィールド(difficulty など)は標準イーサリアムと異なる場合があります。
6. 解決方法
cast rlp または JavaScript の ethers.utils.RLP.encode を使用して正しくエンコードします。注意点:
difficultyは OP 上では 0 になる可能性がありますbaseFeePerGasは EIP-1559 以降必須フィールドです(OP は 1559 をサポートしています)- ブロックは
[block.number - 256, block.number - 2]の範囲内である必要があります
7. 技術的ポイント
| ポイント | 説明 |
|---|---|
| RLP エンコーディング | イーサリアムの標準シリアライゼーション形式で、ブロックヘッダーやトランザクションなどに使用されます |
| OP ブロック構造 | Optimism のブロック形式はイーサリアムと異なります(Bedrock アップグレード後) |
| 時間枠制約 | コントラクトはブロックが256ブロック以内(約512秒)であることをチェックし、古すぎるブロックの使用を防ぎます |
blockhash の可用性 | EVM は直近256ブロックのハッシュのみを保存します |