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  }