github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "math/big" 7 "os" 8 "strconv" 9 10 "github.com/ethereum-optimism/optimism/cannon/mipsevm" 11 "github.com/ethereum-optimism/optimism/op-bindings/predeploys" 12 "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" 13 "github.com/ethereum/go-ethereum/accounts/abi" 14 "github.com/ethereum/go-ethereum/common" 15 "github.com/ethereum/go-ethereum/common/hexutil" 16 "github.com/ethereum/go-ethereum/core/rawdb" 17 "github.com/ethereum/go-ethereum/core/types" 18 "github.com/ethereum/go-ethereum/crypto" 19 "github.com/ethereum/go-ethereum/trie" 20 "github.com/ethereum/go-ethereum/trie/triedb/hashdb" 21 ) 22 23 // ABI types 24 var ( 25 // Plain dynamic dynBytes type 26 dynBytes, _ = abi.NewType("bytes", "", nil) 27 bytesArgs = abi.Arguments{ 28 {Type: dynBytes}, 29 } 30 31 // Plain fixed bytes32 type 32 fixedBytes, _ = abi.NewType("bytes32", "", nil) 33 fixedBytesArgs = abi.Arguments{ 34 {Type: fixedBytes}, 35 } 36 37 // Decoded nonce tuple (nonce, version) 38 decodedNonce, _ = abi.NewType("tuple", "DecodedNonce", []abi.ArgumentMarshaling{ 39 {Name: "nonce", Type: "uint256"}, 40 {Name: "version", Type: "uint256"}, 41 }) 42 decodedNonceArgs = abi.Arguments{ 43 {Name: "encodedNonce", Type: decodedNonce}, 44 } 45 46 // WithdrawalHash slot tuple (bytes32, bytes32) 47 withdrawalSlot, _ = abi.NewType("tuple", "SlotHash", []abi.ArgumentMarshaling{ 48 {Name: "withdrawalHash", Type: "bytes32"}, 49 {Name: "zeroPadding", Type: "bytes32"}, 50 }) 51 withdrawalSlotArgs = abi.Arguments{ 52 {Name: "slotHash", Type: withdrawalSlot}, 53 } 54 55 // Prove withdrawal inputs tuple (bytes32, bytes32, bytes32, bytes32, bytes[]) 56 proveWithdrawalInputs, _ = abi.NewType("tuple", "ProveWithdrawalInputs", []abi.ArgumentMarshaling{ 57 {Name: "worldRoot", Type: "bytes32"}, 58 {Name: "stateRoot", Type: "bytes32"}, 59 {Name: "outputRoot", Type: "bytes32"}, 60 {Name: "withdrawalHash", Type: "bytes32"}, 61 {Name: "proof", Type: "bytes[]"}, 62 }) 63 proveWithdrawalInputsArgs = abi.Arguments{ 64 {Name: "inputs", Type: proveWithdrawalInputs}, 65 } 66 67 // cannonMemoryProof inputs tuple (bytes32, bytes) 68 cannonMemoryProof, _ = abi.NewType("tuple", "CannonMemoryProof", []abi.ArgumentMarshaling{ 69 {Name: "memRoot", Type: "bytes32"}, 70 {Name: "proof", Type: "bytes"}, 71 }) 72 cannonMemoryProofArgs = abi.Arguments{ 73 {Name: "encodedCannonMemoryProof", Type: cannonMemoryProof}, 74 } 75 ) 76 77 func DiffTestUtils() { 78 args := os.Args[2:] 79 variant := args[0] 80 81 // This command requires arguments 82 if len(args) == 0 { 83 panic("Error: No arguments provided") 84 } 85 86 switch variant { 87 case "decodeVersionedNonce": 88 // Parse input arguments 89 input, ok := new(big.Int).SetString(args[1], 10) 90 checkOk(ok) 91 92 // Decode versioned nonce 93 nonce, version := crossdomain.DecodeVersionedNonce(input) 94 95 // ABI encode output 96 packArgs := struct { 97 Nonce *big.Int 98 Version *big.Int 99 }{ 100 nonce, 101 version, 102 } 103 packed, err := decodedNonceArgs.Pack(&packArgs) 104 checkErr(err, "Error encoding output") 105 106 fmt.Print(hexutil.Encode(packed)) 107 case "encodeCrossDomainMessage": 108 // Parse input arguments 109 nonce, ok := new(big.Int).SetString(args[1], 10) 110 checkOk(ok) 111 sender := common.HexToAddress(args[2]) 112 target := common.HexToAddress(args[3]) 113 value, ok := new(big.Int).SetString(args[4], 10) 114 checkOk(ok) 115 gasLimit, ok := new(big.Int).SetString(args[5], 10) 116 checkOk(ok) 117 data := common.FromHex(args[6]) 118 119 // Encode cross domain message 120 encoded, err := encodeCrossDomainMessage(nonce, sender, target, value, gasLimit, data) 121 checkErr(err, "Error encoding cross domain message") 122 123 // Pack encoded cross domain message 124 packed, err := bytesArgs.Pack(&encoded) 125 checkErr(err, "Error encoding output") 126 127 fmt.Print(hexutil.Encode(packed)) 128 case "hashCrossDomainMessage": 129 // Parse input arguments 130 nonce, ok := new(big.Int).SetString(args[1], 10) 131 checkOk(ok) 132 sender := common.HexToAddress(args[2]) 133 target := common.HexToAddress(args[3]) 134 value, ok := new(big.Int).SetString(args[4], 10) 135 checkOk(ok) 136 gasLimit, ok := new(big.Int).SetString(args[5], 10) 137 checkOk(ok) 138 data := common.FromHex(args[6]) 139 140 // Encode cross domain message 141 encoded, err := encodeCrossDomainMessage(nonce, sender, target, value, gasLimit, data) 142 checkErr(err, "Error encoding cross domain message") 143 144 // Hash encoded cross domain message 145 hash := crypto.Keccak256Hash(encoded) 146 147 // Pack hash 148 packed, err := fixedBytesArgs.Pack(&hash) 149 checkErr(err, "Error encoding output") 150 151 fmt.Print(hexutil.Encode(packed)) 152 case "hashDepositTransaction": 153 // Parse input arguments 154 l1BlockHash := common.HexToHash(args[1]) 155 logIndex, ok := new(big.Int).SetString(args[2], 10) 156 checkOk(ok) 157 from := common.HexToAddress(args[3]) 158 to := common.HexToAddress(args[4]) 159 mint, ok := new(big.Int).SetString(args[5], 10) 160 checkOk(ok) 161 value, ok := new(big.Int).SetString(args[6], 10) 162 checkOk(ok) 163 gasLimit, ok := new(big.Int).SetString(args[7], 10) 164 checkOk(ok) 165 data := common.FromHex(args[8]) 166 167 // Create deposit transaction 168 depositTx := makeDepositTx(from, to, value, mint, gasLimit, false, data, l1BlockHash, logIndex) 169 170 // RLP encode deposit transaction 171 encoded, err := types.NewTx(&depositTx).MarshalBinary() 172 checkErr(err, "Error encoding deposit transaction") 173 174 // Hash encoded deposit transaction 175 hash := crypto.Keccak256Hash(encoded) 176 177 // Pack hash 178 packed, err := fixedBytesArgs.Pack(&hash) 179 checkErr(err, "Error encoding output") 180 181 fmt.Print(hexutil.Encode(packed)) 182 case "encodeDepositTransaction": 183 // Parse input arguments 184 from := common.HexToAddress(args[1]) 185 to := common.HexToAddress(args[2]) 186 value, ok := new(big.Int).SetString(args[3], 10) 187 checkOk(ok) 188 mint, ok := new(big.Int).SetString(args[4], 10) 189 checkOk(ok) 190 gasLimit, ok := new(big.Int).SetString(args[5], 10) 191 checkOk(ok) 192 isCreate := args[6] == "true" 193 data := common.FromHex(args[7]) 194 l1BlockHash := common.HexToHash(args[8]) 195 logIndex, ok := new(big.Int).SetString(args[9], 10) 196 checkOk(ok) 197 198 depositTx := makeDepositTx(from, to, value, mint, gasLimit, isCreate, data, l1BlockHash, logIndex) 199 200 // RLP encode deposit transaction 201 encoded, err := types.NewTx(&depositTx).MarshalBinary() 202 checkErr(err, "Failed to RLP encode deposit transaction") 203 // Pack rlp encoded deposit transaction 204 packed, err := bytesArgs.Pack(&encoded) 205 checkErr(err, "Error encoding output") 206 207 fmt.Print(hexutil.Encode(packed)) 208 case "hashWithdrawal": 209 // Parse input arguments 210 nonce, ok := new(big.Int).SetString(args[1], 10) 211 checkOk(ok) 212 sender := common.HexToAddress(args[2]) 213 target := common.HexToAddress(args[3]) 214 value, ok := new(big.Int).SetString(args[4], 10) 215 checkOk(ok) 216 gasLimit, ok := new(big.Int).SetString(args[5], 10) 217 checkOk(ok) 218 data := common.FromHex(args[6]) 219 220 // Hash withdrawal 221 hash, err := hashWithdrawal(nonce, sender, target, value, gasLimit, data) 222 checkErr(err, "Error hashing withdrawal") 223 224 // Pack hash 225 packed, err := fixedBytesArgs.Pack(&hash) 226 checkErr(err, "Error encoding output") 227 228 fmt.Print(hexutil.Encode(packed)) 229 case "hashOutputRootProof": 230 // Parse input arguments 231 version := common.HexToHash(args[1]) 232 stateRoot := common.HexToHash(args[2]) 233 messagePasserStorageRoot := common.HexToHash(args[3]) 234 latestBlockHash := common.HexToHash(args[4]) 235 236 // Hash the output root proof 237 hash, err := hashOutputRootProof(version, stateRoot, messagePasserStorageRoot, latestBlockHash) 238 checkErr(err, "Error hashing output root proof") 239 240 // Pack hash 241 packed, err := fixedBytesArgs.Pack(&hash) 242 checkErr(err, "Error encoding output") 243 244 fmt.Print(hexutil.Encode(packed)) 245 case "getProveWithdrawalTransactionInputs": 246 // Parse input arguments 247 nonce, ok := new(big.Int).SetString(args[1], 10) 248 checkOk(ok) 249 sender := common.HexToAddress(args[2]) 250 target := common.HexToAddress(args[3]) 251 value, ok := new(big.Int).SetString(args[4], 10) 252 checkOk(ok) 253 gasLimit, ok := new(big.Int).SetString(args[5], 10) 254 checkOk(ok) 255 data := common.FromHex(args[6]) 256 257 wdHash, err := hashWithdrawal(nonce, sender, target, value, gasLimit, data) 258 checkErr(err, "Error hashing withdrawal") 259 260 // Compute the storage slot the withdrawalHash will be stored in 261 slot := struct { 262 WithdrawalHash common.Hash 263 ZeroPadding common.Hash 264 }{ 265 WithdrawalHash: wdHash, 266 ZeroPadding: common.Hash{}, 267 } 268 packed, err := withdrawalSlotArgs.Pack(&slot) 269 checkErr(err, "Error packing withdrawal slot") 270 271 // Compute the storage slot the withdrawalHash will be stored in 272 hash := crypto.Keccak256Hash(packed) 273 274 // Create a secure trie for state 275 state, err := trie.NewStateTrie( 276 trie.TrieID(types.EmptyRootHash), 277 trie.NewDatabase(rawdb.NewMemoryDatabase(), &trie.Config{HashDB: hashdb.Defaults}), 278 ) 279 checkErr(err, "Error creating secure trie") 280 281 // Put a "true" bool in the storage slot 282 err = state.UpdateStorage(common.Address{}, hash.Bytes(), []byte{0x01}) 283 checkErr(err, "Error updating storage") 284 285 // Create a secure trie for the world state 286 world, err := trie.NewStateTrie( 287 trie.TrieID(types.EmptyRootHash), 288 trie.NewDatabase(rawdb.NewMemoryDatabase(), &trie.Config{HashDB: hashdb.Defaults}), 289 ) 290 checkErr(err, "Error creating secure trie") 291 292 // Put the put the rlp encoded account in the world trie 293 account := types.StateAccount{ 294 Nonce: 0, 295 Balance: big.NewInt(0), 296 Root: state.Hash(), 297 } 298 writer := new(bytes.Buffer) 299 checkErr(account.EncodeRLP(writer), "Error encoding account") 300 err = world.UpdateStorage(common.Address{}, predeploys.L2ToL1MessagePasserAddr.Bytes(), writer.Bytes()) 301 checkErr(err, "Error updating storage") 302 303 // Get the proof 304 var proof proofList 305 checkErr(state.Prove(predeploys.L2ToL1MessagePasserAddr.Bytes(), &proof), "Error getting proof") 306 307 // Get the output root 308 outputRoot, err := hashOutputRootProof(common.Hash{}, world.Hash(), state.Hash(), common.Hash{}) 309 checkErr(err, "Error hashing output root proof") 310 311 // Pack the output 312 output := struct { 313 WorldRoot common.Hash 314 StateRoot common.Hash 315 OutputRoot common.Hash 316 WithdrawalHash common.Hash 317 Proof proofList 318 }{ 319 WorldRoot: world.Hash(), 320 StateRoot: state.Hash(), 321 OutputRoot: outputRoot, 322 WithdrawalHash: wdHash, 323 Proof: proof, 324 } 325 packed, err = proveWithdrawalInputsArgs.Pack(&output) 326 checkErr(err, "Error encoding output") 327 328 // Print the output 329 fmt.Print(hexutil.Encode(packed[32:])) 330 case "cannonMemoryProof": 331 // <pc, insn, [memAddr, memValue]> 332 mem := mipsevm.NewMemory() 333 if len(args) != 3 && len(args) != 5 { 334 panic("Error: cannonMemoryProofWithProof requires 2 or 4 arguments") 335 } 336 pc, err := strconv.ParseUint(args[1], 10, 32) 337 checkErr(err, "Error decocding addr") 338 insn, err := strconv.ParseUint(args[2], 10, 32) 339 checkErr(err, "Error decocding insn") 340 mem.SetMemory(uint32(pc), uint32(insn)) 341 342 var insnProof, memProof [896]byte 343 if len(args) == 5 { 344 memAddr, err := strconv.ParseUint(args[3], 10, 32) 345 checkErr(err, "Error decocding memAddr") 346 memValue, err := strconv.ParseUint(args[4], 10, 32) 347 checkErr(err, "Error decocding memValue") 348 mem.SetMemory(uint32(memAddr), uint32(memValue)) 349 memProof = mem.MerkleProof(uint32(memAddr)) 350 } 351 insnProof = mem.MerkleProof(uint32(pc)) 352 353 output := struct { 354 MemRoot common.Hash 355 Proof []byte 356 }{ 357 MemRoot: mem.MerkleRoot(), 358 Proof: append(insnProof[:], memProof[:]...), 359 } 360 packed, err := cannonMemoryProofArgs.Pack(&output) 361 checkErr(err, "Error encoding output") 362 fmt.Print(hexutil.Encode(packed[32:])) 363 default: 364 panic(fmt.Errorf("Unknown command: %s", args[0])) 365 } 366 }