diff --git a/.circleci/config.yml b/.circleci/config.yml index a98a8a8672e0..37b9a4f4bce6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1758,6 +1758,12 @@ workflows: on_changes: cannon,packages/contracts-bedrock/src/cannon uses_artifacts: true requires: ["go-mod-download", "pnpm-monorepo"] + - fuzz-golang: + name: op-e2e-fuzz + package_name: op-e2e + on_changes: op-e2e,packages/contracts-bedrock/src + uses_artifacts: true + requires: ["go-mod-download", "pnpm-monorepo"] - go-test: name: op-heartbeat-tests module: op-heartbeat diff --git a/go.mod b/go.mod index 8975e5fa90e1..0559ae280ba9 100644 --- a/go.mod +++ b/go.mod @@ -227,7 +227,7 @@ require ( rsc.io/tmplfunc v0.0.3 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101315.1-rc.2 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101315.1-rc.3 //replace github.com/ethereum/go-ethereum v1.13.9 => ../op-geth diff --git a/go.sum b/go.sum index 267bdb13b0c9..9683e7685969 100644 --- a/go.sum +++ b/go.sum @@ -175,8 +175,8 @@ github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/ github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= -github.com/ethereum-optimism/op-geth v1.101315.1-rc.2 h1:uUrcs8fGrdDnVELB66GcMZRvwIeJow64DOtF+VFdAzY= -github.com/ethereum-optimism/op-geth v1.101315.1-rc.2/go.mod h1:VXVFzx1mr/JyJac5M4k5W/+0cqHZMkqKsIVDsOyj2rs= +github.com/ethereum-optimism/op-geth v1.101315.1-rc.3 h1:BvmzUehVSo7uuqtApy/h/A5uRDAuU2tJQLgHCWTxAUQ= +github.com/ethereum-optimism/op-geth v1.101315.1-rc.3/go.mod h1:VXVFzx1mr/JyJac5M4k5W/+0cqHZMkqKsIVDsOyj2rs= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240510200259-4be7024d2ba7 h1:e7oXWZwODAMM2TLo9beGDXaX2cCw7uM7qAqamYBHV40= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240510200259-4be7024d2ba7/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= diff --git a/op-bindings/bindings/gaspriceoracle.go b/op-bindings/bindings/gaspriceoracle.go index 7636a7c2f105..00f3194cb6a4 100644 --- a/op-bindings/bindings/gaspriceoracle.go +++ b/op-bindings/bindings/gaspriceoracle.go @@ -30,8 +30,8 @@ var ( // GasPriceOracleMetaData contains all meta data concerning the GasPriceOracle contract. var GasPriceOracleMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DECIMALS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"baseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"baseFeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobBaseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobBaseFeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"gasPrice\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1Fee\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1GasUsed\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isEcotone\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1BaseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"overhead\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"scalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setEcotone\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"}]", - Bin: "0x608060405234801561001057600080fd5b50610fb5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806354fd4d5011610097578063de26c4a111610066578063de26c4a1146101da578063f45e65d8146101ed578063f8206140146101f5578063fe173b97146101cc57600080fd5b806354fd4d501461016657806368d5dca6146101af5780636ef25c3a146101cc578063c5985918146101d257600080fd5b8063313ce567116100d3578063313ce5671461012757806349948e0e1461012e5780634ef6e22414610141578063519b4bd31461015e57600080fd5b80630c18c162146100fa57806322b90ab3146101155780632e0f26251461011f575b600080fd5b6101026101fd565b6040519081526020015b60405180910390f35b61011d61031e565b005b610102600681565b6006610102565b61010261013c366004610b73565b610541565b60005461014e9060ff1681565b604051901515815260200161010c565b610102610565565b6101a26040518060400160405280600581526020017f312e322e3000000000000000000000000000000000000000000000000000000081525081565b60405161010c9190610c42565b6101b76105c6565b60405163ffffffff909116815260200161010c565b48610102565b6101b761064b565b6101026101e8366004610b73565b6106ac565b610102610760565b610102610853565b6000805460ff1615610296576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103199190610cb5565b905090565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663e591b2826040518163ffffffff1660e01b8152600401602060405180830381865afa15801561037d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a19190610cce565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610481576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161028d565b60005460ff1615610514576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161028d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805460ff161561055c57610556826108b4565b92915050565b61055682610958565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103199190610d04565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b6000806106b883610ab4565b60005490915060ff16156106cc5792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074f9190610cb5565b6107599082610d59565b9392505050565b6000805460ff16156107f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f6563617465640000000000000000000000000000000000000000000000000000606482015260840161028d565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102f5573d6000803e3d6000fd5b6000806108c083610ab4565b905060006108cc610565565b6108d461064b565b6108df906010610d71565b63ffffffff166108ef9190610d9d565b905060006108fb610853565b6109036105c6565b63ffffffff166109139190610d9d565b905060006109218284610d59565b61092b9085610d9d565b90506109396006600a610efa565b610944906010610d9d565b61094e9082610f06565b9695505050505050565b60008061096483610ab4565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109eb9190610cb5565b6109f3610565565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a769190610cb5565b610a809085610d59565b610a8a9190610d9d565b610a949190610d9d565b9050610aa26006600a610efa565b610aac9082610f06565b949350505050565b80516000908190815b81811015610b3757848181518110610ad757610ad7610f41565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016600003610b1757610b10600484610d59565b9250610b25565b610b22601084610d59565b92505b80610b2f81610f70565b915050610abd565b50610aac82610440610d59565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610b8557600080fd5b813567ffffffffffffffff80821115610b9d57600080fd5b818401915084601f830112610bb157600080fd5b813581811115610bc357610bc3610b44565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610c0957610c09610b44565b81604052828152876020848701011115610c2257600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b81811015610c6f57858101830151858201604001528201610c53565b81811115610c81576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600060208284031215610cc757600080fd5b5051919050565b600060208284031215610ce057600080fd5b815173ffffffffffffffffffffffffffffffffffffffff8116811461075957600080fd5b600060208284031215610d1657600080fd5b815163ffffffff8116811461075957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115610d6c57610d6c610d2a565b500190565b600063ffffffff80831681851681830481118215151615610d9457610d94610d2a565b02949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610dd557610dd5610d2a565b500290565b600181815b80851115610e3357817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610e1957610e19610d2a565b80851615610e2657918102915b93841c9390800290610ddf565b509250929050565b600082610e4a57506001610556565b81610e5757506000610556565b8160018114610e6d5760028114610e7757610e93565b6001915050610556565b60ff841115610e8857610e88610d2a565b50506001821b610556565b5060208310610133831016604e8410600b8410161715610eb6575081810a610556565b610ec08383610dda565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610ef257610ef2610d2a565b029392505050565b60006107598383610e3b565b600082610f3c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610fa157610fa1610d2a565b506001019056fea164736f6c634300080f000a", + ABI: "[{\"type\":\"function\",\"name\":\"DECIMALS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"baseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"baseFeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobBaseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobBaseFeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"gasPrice\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1Fee\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1FeeUpperBound\",\"inputs\":[{\"name\":\"_unsignedTxSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getL1GasUsed\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isEcotone\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isFjord\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1BaseFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"overhead\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"scalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setEcotone\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setFjord\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"}]", + Bin: "0x608060405234801561001057600080fd5b506117f6806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80636ef25c3a116100b2578063de26c4a111610081578063f45e65d811610066578063f45e65d81461025b578063f820614014610263578063fe173b971461020d57600080fd5b8063de26c4a114610235578063f1c7a58b1461024857600080fd5b80636ef25c3a1461020d5780638e98b10614610213578063960e3a231461021b578063c59859181461022d57600080fd5b806349948e0e11610109578063519b4bd3116100ee578063519b4bd31461019f57806354fd4d50146101a757806368d5dca6146101f057600080fd5b806349948e0e1461016f5780634ef6e2241461018257600080fd5b80630c18c1621461013b57806322b90ab3146101565780632e0f262514610160578063313ce56714610168575b600080fd5b61014361026b565b6040519081526020015b60405180910390f35b61015e61038c565b005b610143600681565b6006610143565b61014361017d3660046112a1565b610515565b60005461018f9060ff1681565b604051901515815260200161014d565b610143610552565b6101e36040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60405161014d9190611370565b6101f86105b3565b60405163ffffffff909116815260200161014d565b48610143565b61015e610638565b60005461018f90610100900460ff1681565b6101f8610832565b6101436102433660046112a1565b610893565b6101436102563660046113e3565b61098d565b610143610a69565b610143610b5c565b6000805460ff1615610304576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038791906113fc565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a4016102fb565b60005460ff16156104e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f616374697665000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60008054610100900460ff16156105355761052f82610bbd565b92915050565b60005460ff16156105495761052f82610bdc565b61052f82610c80565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103879190611415565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146106db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c61670060648201526084016102fb565b60005460ff1661076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e650000000000000060648201526084016102fb565b600054610100900460ff1615610804576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f746976650000000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b60008054610100900460ff16156108da57620f42406108c56108b484610dd4565b516108c090604461146a565b6110f1565b6108d0906010611482565b61052f91906114bf565b60006108e583611150565b60005490915060ff16156108f95792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906113fc565b610986908261146a565b9392505050565b60008054610100900460ff16610a25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f72640000000000000000000060648201526084016102fb565b6000610a3283604461146a565b90506000610a4160ff836114bf565b610a4b908361146a565b610a5690601061146a565b9050610a61816111e0565b949350505050565b6000805460ff1615610afd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f656361746564000000000000000000000000000000000000000000000000000060648201526084016102fb565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600061052f610bcb83610dd4565b51610bd790604461146a565b6111e0565b600080610be883611150565b90506000610bf4610552565b610bfc610832565b610c079060106114fa565b63ffffffff16610c179190611482565b90506000610c23610b5c565b610c2b6105b3565b63ffffffff16610c3b9190611482565b90506000610c49828461146a565b610c539085611482565b9050610c616006600a611646565b610c6c906010611482565b610c7690826114bf565b9695505050505050565b600080610c8c83611150565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1391906113fc565b610d1b610552565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9e91906113fc565b610da8908561146a565b610db29190611482565b610dbc9190611482565b9050610dca6006600a611646565b610a6190826114bf565b6060610f63565b818153600101919050565b600082840393505b838110156109865782810151828201511860001a1590930292600101610dee565b825b60208210610e5b578251610e26601f83610ddb565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190602101610e11565b8115610986578251610e706001840383610ddb565b520160010192915050565b60006001830392505b6101078210610ebc57610eae8360ff16610ea960fd610ea98760081c60e00189610ddb565b610ddb565b935061010682039150610e84565b60078210610ee957610ee28360ff16610ea960078503610ea98760081c60e00189610ddb565b9050610986565b610a618360ff16610ea98560081c8560051b0187610ddb565b610f5b828203610f3f610f2f84600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b81811015611096576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b90911890915284019081830390848410610feb5750611026565b600184019350611fff8211611020578251600081901a600182901a60081b1760029190911a60101b1781036110205750611026565b50610f8f565b838310611034575050611096565b600183039250858311156110525761104f8787888603610e0f565b96505b611066600985016003850160038501610de6565b9150611073878284610e7b565b96505061108b8461108686848601610f02565b610f02565b915050809350610f83565b50506110a88383848851850103610e0f565b925050506040519150618000820180820391508183526020830160005b838110156110dd5782810151828201526020016110c5565b506000920191825250602001604052919050565b60008061110183620cc394611482565b61112b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611652565b905061113b6064620f42406116c6565b81121561052f576109866064620f42406116c6565b80516000908190815b818110156111d35784818151811061117357611173611782565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036111b3576111ac60048461146a565b92506111c1565b6111be60108461146a565b92505b806111cb816117b1565b915050611159565b50610a618261044061146a565b6000806111ec836110f1565b905060006111f8610b5c565b6112006105b3565b63ffffffff166112109190611482565b611218610552565b611220610832565b61122b9060106114fa565b63ffffffff1661123b9190611482565b611245919061146a565b905061125360066002611482565b61125e90600a611646565b6112688284611482565b610a6191906114bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156112b357600080fd5b813567ffffffffffffffff808211156112cb57600080fd5b818401915084601f8301126112df57600080fd5b8135818111156112f1576112f1611272565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561133757611337611272565b8160405282815287602084870101111561135057600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561139d57858101830151858201604001528201611381565b818111156113af576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000602082840312156113f557600080fd5b5035919050565b60006020828403121561140e57600080fd5b5051919050565b60006020828403121561142757600080fd5b815163ffffffff8116811461098657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561147d5761147d61143b565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156114ba576114ba61143b565b500290565b6000826114f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600063ffffffff8083168185168183048111821515161561151d5761151d61143b565b02949350505050565b600181815b8085111561157f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156115655761156561143b565b8085161561157257918102915b93841c939080029061152b565b509250929050565b6000826115965750600161052f565b816115a35750600061052f565b81600181146115b957600281146115c3576115df565b600191505061052f565b60ff8411156115d4576115d461143b565b50506001821b61052f565b5060208310610133831016604e8410600b8410161715611602575081810a61052f565b61160c8383611526565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561163e5761163e61143b565b029392505050565b60006109868383611587565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561168c5761168c61143b565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156116c0576116c061143b565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156117075761170761143b565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156117425761174261143b565b6000871292508782058712848416161561175e5761175e61143b565b878505871281841616156117745761177461143b565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117e2576117e261143b565b506001019056fea164736f6c634300080f000a", } // GasPriceOracleABI is the input ABI used to generate the binding from. @@ -449,6 +449,37 @@ func (_GasPriceOracle *GasPriceOracleCallerSession) GetL1Fee(_data []byte) (*big return _GasPriceOracle.Contract.GetL1Fee(&_GasPriceOracle.CallOpts, _data) } +// GetL1FeeUpperBound is a free data retrieval call binding the contract method 0xf1c7a58b. +// +// Solidity: function getL1FeeUpperBound(uint256 _unsignedTxSize) view returns(uint256) +func (_GasPriceOracle *GasPriceOracleCaller) GetL1FeeUpperBound(opts *bind.CallOpts, _unsignedTxSize *big.Int) (*big.Int, error) { + var out []interface{} + err := _GasPriceOracle.contract.Call(opts, &out, "getL1FeeUpperBound", _unsignedTxSize) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetL1FeeUpperBound is a free data retrieval call binding the contract method 0xf1c7a58b. +// +// Solidity: function getL1FeeUpperBound(uint256 _unsignedTxSize) view returns(uint256) +func (_GasPriceOracle *GasPriceOracleSession) GetL1FeeUpperBound(_unsignedTxSize *big.Int) (*big.Int, error) { + return _GasPriceOracle.Contract.GetL1FeeUpperBound(&_GasPriceOracle.CallOpts, _unsignedTxSize) +} + +// GetL1FeeUpperBound is a free data retrieval call binding the contract method 0xf1c7a58b. +// +// Solidity: function getL1FeeUpperBound(uint256 _unsignedTxSize) view returns(uint256) +func (_GasPriceOracle *GasPriceOracleCallerSession) GetL1FeeUpperBound(_unsignedTxSize *big.Int) (*big.Int, error) { + return _GasPriceOracle.Contract.GetL1FeeUpperBound(&_GasPriceOracle.CallOpts, _unsignedTxSize) +} + // GetL1GasUsed is a free data retrieval call binding the contract method 0xde26c4a1. // // Solidity: function getL1GasUsed(bytes _data) view returns(uint256) @@ -511,6 +542,37 @@ func (_GasPriceOracle *GasPriceOracleCallerSession) IsEcotone() (bool, error) { return _GasPriceOracle.Contract.IsEcotone(&_GasPriceOracle.CallOpts) } +// IsFjord is a free data retrieval call binding the contract method 0x960e3a23. +// +// Solidity: function isFjord() view returns(bool) +func (_GasPriceOracle *GasPriceOracleCaller) IsFjord(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _GasPriceOracle.contract.Call(opts, &out, "isFjord") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsFjord is a free data retrieval call binding the contract method 0x960e3a23. +// +// Solidity: function isFjord() view returns(bool) +func (_GasPriceOracle *GasPriceOracleSession) IsFjord() (bool, error) { + return _GasPriceOracle.Contract.IsFjord(&_GasPriceOracle.CallOpts) +} + +// IsFjord is a free data retrieval call binding the contract method 0x960e3a23. +// +// Solidity: function isFjord() view returns(bool) +func (_GasPriceOracle *GasPriceOracleCallerSession) IsFjord() (bool, error) { + return _GasPriceOracle.Contract.IsFjord(&_GasPriceOracle.CallOpts) +} + // L1BaseFee is a free data retrieval call binding the contract method 0x519b4bd3. // // Solidity: function l1BaseFee() view returns(uint256) @@ -655,3 +717,24 @@ func (_GasPriceOracle *GasPriceOracleSession) SetEcotone() (*types.Transaction, func (_GasPriceOracle *GasPriceOracleTransactorSession) SetEcotone() (*types.Transaction, error) { return _GasPriceOracle.Contract.SetEcotone(&_GasPriceOracle.TransactOpts) } + +// SetFjord is a paid mutator transaction binding the contract method 0x8e98b106. +// +// Solidity: function setFjord() returns() +func (_GasPriceOracle *GasPriceOracleTransactor) SetFjord(opts *bind.TransactOpts) (*types.Transaction, error) { + return _GasPriceOracle.contract.Transact(opts, "setFjord") +} + +// SetFjord is a paid mutator transaction binding the contract method 0x8e98b106. +// +// Solidity: function setFjord() returns() +func (_GasPriceOracle *GasPriceOracleSession) SetFjord() (*types.Transaction, error) { + return _GasPriceOracle.Contract.SetFjord(&_GasPriceOracle.TransactOpts) +} + +// SetFjord is a paid mutator transaction binding the contract method 0x8e98b106. +// +// Solidity: function setFjord() returns() +func (_GasPriceOracle *GasPriceOracleTransactorSession) SetFjord() (*types.Transaction, error) { + return _GasPriceOracle.Contract.SetFjord(&_GasPriceOracle.TransactOpts) +} diff --git a/op-chain-ops/cmd/ecotone-scalar/main.go b/op-chain-ops/cmd/ecotone-scalar/main.go index ad75ba87f5b6..e116d15bf8b4 100644 --- a/op-chain-ops/cmd/ecotone-scalar/main.go +++ b/op-chain-ops/cmd/ecotone-scalar/main.go @@ -59,7 +59,7 @@ func main() { scalar = uint(decoded.BaseFeeScalar) blobScalar = uint(decoded.BlobBaseFeeScalar) } else { - encoded = eth.EncodeScalar(eth.EcostoneScalars{ + encoded = eth.EncodeScalar(eth.EcotoneScalars{ BlobBaseFeeScalar: uint32(blobScalar), BaseFeeScalar: uint32(scalar), }) diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index 369bc54dace6..afdf5839124c 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -493,7 +493,7 @@ func (d *DeployConfig) FeeScalar() [32]byte { if d.GasPriceOracleScalar != 0 { return common.BigToHash(big.NewInt(int64(d.GasPriceOracleScalar))) } - return eth.EncodeScalar(eth.EcostoneScalars{ + return eth.EncodeScalar(eth.EcotoneScalars{ BlobBaseFeeScalar: d.GasPriceOracleBlobBaseFeeScalar, BaseFeeScalar: d.GasPriceOracleBaseFeeScalar, }) diff --git a/op-e2e/Makefile b/op-e2e/Makefile index d730a7c23f89..707227f14dac 100644 --- a/op-e2e/Makefile +++ b/op-e2e/Makefile @@ -64,3 +64,9 @@ clean: rm -r ../.devnet rm -r ../op-program/bin .PHONY: clean + +fuzz: + go test -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./ + go test -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFastLzGethSolidity ./ + go test -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFastLzCgo ./ + diff --git a/op-e2e/actions/fjord_fork_test.go b/op-e2e/actions/fjord_fork_test.go new file mode 100644 index 000000000000..2b80fe6fa420 --- /dev/null +++ b/op-e2e/actions/fjord_fork_test.go @@ -0,0 +1,145 @@ +package actions + +import ( + "context" + "encoding/hex" + "math/big" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/op-bindings/bindings" + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +var ( + fjordGasPriceOracleCodeHash = common.HexToHash("0xa88fa50a2745b15e6794247614b5298483070661adacb8d32d716434ed24c6b2") + // https://basescan.org/tx/0x8debb2fe54200183fb8baa3c6dbd8e6ec2e4f7a4add87416cd60336b8326d16a + txHex = "02f875822105819b8405709fb884057d460082e97f94273ca93a52b817294830ed7572aa591ccfa647fd80881249c58b0021fb3fc080a05bb08ccfd68f83392e446dac64d88a2d28e7072c06502dfabc4a77e77b5c7913a05878d53dd4ebba4f6367e572d524dffcabeec3abb1d8725ee3ac5dc32e1852e3" +) + +func TestFjordNetworkUpgradeTransactions(gt *testing.T) { + t := NewDefaultTesting(gt) + dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + genesisBlock := hexutil.Uint64(0) + fjordOffset := hexutil.Uint64(2) + + dp.DeployConfig.L1CancunTimeOffset = &genesisBlock // can be removed once Cancun on L1 is the default + + // Activate all forks at genesis, and schedule Fjord the block after + dp.DeployConfig.L2GenesisRegolithTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisCanyonTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisFjordTimeOffset = &fjordOffset + require.NoError(t, dp.DeployConfig.Check(), "must have valid config") + + sd := e2eutils.Setup(t, dp, defaultAlloc) + log := testlog.Logger(t, log.LvlDebug) + _, _, _, sequencer, engine, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) + ethCl := engine.EthClient() + + // start op-nodes + sequencer.ActL2PipelineFull(t) + verifier.ActL2PipelineFull(t) + + // Get gas price from oracle + gasPriceOracle, err := bindings.NewGasPriceOracleCaller(predeploys.GasPriceOracleAddr, ethCl) + require.NoError(t, err) + + // Get current implementations addresses (by slot) for L1Block + GasPriceOracle + initialGasPriceOracleAddress, err := ethCl.StorageAt(context.Background(), predeploys.GasPriceOracleAddr, genesis.ImplementationSlot, nil) + require.NoError(t, err) + + sequencer.ActBuildL2ToFjord(t) + + // get latest block + latestBlock, err := ethCl.BlockByNumber(context.Background(), nil) + require.NoError(t, err) + require.Equal(t, sequencer.L2Unsafe().Number, latestBlock.Number().Uint64()) + + transactions := latestBlock.Transactions() + // L1Block: 1 set-L1-info + 1 deploys + 1 upgradeTo + 1 enable fjord on GPO + // See [derive.FjordNetworkUpgradeTransactions] + require.Equal(t, 4, len(transactions)) + + // All transactions are successful + for i := 1; i < 4; i++ { + txn := transactions[i] + receipt, err := ethCl.TransactionReceipt(context.Background(), txn.Hash()) + require.NoError(t, err) + require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status) + require.NotEmpty(t, txn.Data(), "upgrade tx must provide input data") + } + + expectedGasPriceOracleAddress := crypto.CreateAddress(derive.GasPriceOracleFjordDeployerAddress, 0) + + // Gas Price Oracle Proxy is updated + updatedGasPriceOracleAddress, err := ethCl.StorageAt(context.Background(), predeploys.GasPriceOracleAddr, genesis.ImplementationSlot, latestBlock.Number()) + require.NoError(t, err) + require.Equal(t, expectedGasPriceOracleAddress, common.BytesToAddress(updatedGasPriceOracleAddress)) + require.NotEqualf(t, initialGasPriceOracleAddress, updatedGasPriceOracleAddress, "Gas Price Oracle Proxy address should have changed") + verifyCodeHashMatches(t, ethCl, expectedGasPriceOracleAddress, fjordGasPriceOracleCodeHash) + + // Check that Fjord was activated + isFjord, err := gasPriceOracle.IsFjord(nil) + require.NoError(t, err) + require.True(t, isFjord) + + // Check GetL1GasUsed is updated + txData, err := hex.DecodeString(txHex) + require.NoError(t, err) + + gpoL1GasUsed, err := gasPriceOracle.GetL1GasUsed(&bind.CallOpts{}, txData) + require.NoError(t, err) + require.Equal(gt, uint64(1_888), gpoL1GasUsed.Uint64()) + + // Check that GetL1Fee takes into account fast LZ + gpoFee, err := gasPriceOracle.GetL1Fee(&bind.CallOpts{}, txData) + require.NoError(t, err) + + gethFee := fjordL1Cost(t, gasPriceOracle, types.RollupCostData{ + FastLzSize: uint64(types.FlzCompressLen(txData) + 68), + }) + require.Equal(t, gethFee.Uint64(), gpoFee.Uint64()) + + // Check that L1FeeUpperBound works + upperBound, err := gasPriceOracle.GetL1FeeUpperBound(&bind.CallOpts{}, big.NewInt(int64(len(txData)))) + require.NoError(t, err) + + txLen := len(txData) + 68 + flzUpperBound := uint64(txLen + txLen/255 + 16) + + upperBoundCost := fjordL1Cost(t, gasPriceOracle, types.RollupCostData{FastLzSize: flzUpperBound}) + require.Equal(t, upperBoundCost.Uint64(), upperBound.Uint64()) +} + +func fjordL1Cost(t require.TestingT, gasPriceOracle *bindings.GasPriceOracleCaller, rollupCostData types.RollupCostData) *big.Int { + baseFeeScalar, err := gasPriceOracle.BaseFeeScalar(nil) + require.NoError(t, err) + l1BaseFee, err := gasPriceOracle.L1BaseFee(nil) + require.NoError(t, err) + blobBaseFeeScalar, err := gasPriceOracle.BlobBaseFeeScalar(nil) + require.NoError(t, err) + blobBaseFee, err := gasPriceOracle.BlobBaseFee(nil) + require.NoError(t, err) + + costFunc := types.NewL1CostFuncFjord( + l1BaseFee, + blobBaseFee, + new(big.Int).SetUint64(uint64(baseFeeScalar)), + new(big.Int).SetUint64(uint64(blobBaseFeeScalar))) + + fee, _ := costFunc(rollupCostData) + return fee +} diff --git a/op-e2e/actions/l2_sequencer.go b/op-e2e/actions/l2_sequencer.go index c1c93cf74dec..dfd4c80c4062 100644 --- a/op-e2e/actions/l2_sequencer.go +++ b/op-e2e/actions/l2_sequencer.go @@ -175,3 +175,10 @@ func (s *L2Sequencer) ActBuildL2ToEcotone(t Testing) { s.ActL2EndBlock(t) } } +func (s *L2Sequencer) ActBuildL2ToFjord(t Testing) { + require.NotNil(t, s.rollupCfg.FjordTime, "cannot activate FjordTime when it is not scheduled") + for s.L2Unsafe().Time < *s.rollupCfg.FjordTime { + s.ActL2StartBlock(t) + s.ActL2EndBlock(t) + } +} diff --git a/op-e2e/external.go b/op-e2e/external.go index a5225e80b604..e59874393941 100644 --- a/op-e2e/external.go +++ b/op-e2e/external.go @@ -65,7 +65,7 @@ func (eec *ExternalEthClient) Close() error { return nil } -func (er *ExternalRunner) Run(t *testing.T) *ExternalEthClient { +func (er *ExternalRunner) Run(t testing.TB) *ExternalEthClient { if er.BinPath == "" { t.Error("no external bin path set") } diff --git a/op-e2e/external/config.go b/op-e2e/external/config.go index b3134c895b3a..943abe6346f9 100644 --- a/op-e2e/external/config.go +++ b/op-e2e/external/config.go @@ -54,7 +54,7 @@ type TestParms struct { SkipTests map[string]string `json:"skip_tests"` } -func (tp TestParms) SkipIfNecessary(t *testing.T) { +func (tp TestParms) SkipIfNecessary(t testing.TB) { if len(tp.SkipTests) == 0 { return } diff --git a/op-e2e/fastlz/fastlz.c b/op-e2e/fastlz/fastlz.c new file mode 100644 index 000000000000..c8c0fa4faefb --- /dev/null +++ b/op-e2e/fastlz/fastlz.c @@ -0,0 +1,511 @@ +/* + FastLZ - Byte-aligned LZ77 compression library + Copyright (C) 2005-2020 Ariya Hidayat + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + This implementation is taken from the following repository/commit: + https://github.com/ariya/FastLZ/tree/344eb4025f9ae866ebf7a2ec48850f7113a97a42 +*/ + +#include "fastlz.h" + +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 2)) +#define FASTLZ_LIKELY(c) (__builtin_expect(!!(c), 1)) +#define FASTLZ_UNLIKELY(c) (__builtin_expect(!!(c), 0)) +#else +#define FASTLZ_LIKELY(c) (c) +#define FASTLZ_UNLIKELY(c) (c) +#endif + +/* + * Specialize custom 64-bit implementation for speed improvements. + */ +#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) +#define FLZ_ARCH64 +#endif + +/* + * Workaround for DJGPP to find uint8_t, uint16_t, etc. + */ +#if defined(__MSDOS__) && defined(__GNUC__) +#include +#endif + +#if defined(FASTLZ_USE_MEMMOVE) && (FASTLZ_USE_MEMMOVE == 0) + +static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) { + do { + *dest++ = *src++; + } while (--count); +} + +static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) { + return fastlz_memmove(dest, src, count); +} + +#else + +#include + +static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) { + if ((count > 4) && (dest >= src + count)) { + memmove(dest, src, count); + } else { + switch (count) { + default: + do { + *dest++ = *src++; + } while (--count); + break; + case 3: + *dest++ = *src++; + case 2: + *dest++ = *src++; + case 1: + *dest++ = *src++; + case 0: + break; + } + } +} + +static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) { memcpy(dest, src, count); } + +#endif + +#if defined(FLZ_ARCH64) + +static uint32_t flz_readu32(const void* ptr) { return *(const uint32_t*)ptr; } + +static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) { + const uint8_t* start = p; + + if (flz_readu32(p) == flz_readu32(q)) { + p += 4; + q += 4; + } + while (q < r) + if (*p++ != *q++) break; + return p - start; +} + +#endif /* FLZ_ARCH64 */ + +#if !defined(FLZ_ARCH64) + +static uint32_t flz_readu32(const void* ptr) { + const uint8_t* p = (const uint8_t*)ptr; + return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; +} + +static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) { + const uint8_t* start = p; + while (q < r) + if (*p++ != *q++) break; + return p - start; +} + +#endif /* !FLZ_ARCH64 */ + +#define MAX_COPY 32 +#define MAX_LEN 264 /* 256 + 8 */ +#define MAX_L1_DISTANCE 8192 +#define MAX_L2_DISTANCE 8191 +#define MAX_FARDISTANCE (65535 + MAX_L2_DISTANCE - 1) + +#define HASH_LOG 13 +#define HASH_SIZE (1 << HASH_LOG) +#define HASH_MASK (HASH_SIZE - 1) + +static uint16_t flz_hash(uint32_t v) { + uint32_t h = (v * 2654435769LL) >> (32 - HASH_LOG); + return h & HASH_MASK; +} + +/* special case of memcpy: at most MAX_COPY bytes */ +static void flz_smallcopy(uint8_t* dest, const uint8_t* src, uint32_t count) { +#if defined(FLZ_ARCH64) + if (count >= 4) { + const uint32_t* p = (const uint32_t*)src; + uint32_t* q = (uint32_t*)dest; + while (count > 4) { + *q++ = *p++; + count -= 4; + dest += 4; + src += 4; + } + } +#endif + fastlz_memcpy(dest, src, count); +} + +/* special case of memcpy: exactly MAX_COPY bytes */ +static void flz_maxcopy(void* dest, const void* src) { +#if defined(FLZ_ARCH64) + const uint32_t* p = (const uint32_t*)src; + uint32_t* q = (uint32_t*)dest; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; +#else + fastlz_memcpy(dest, src, MAX_COPY); +#endif +} + +static uint8_t* flz_literals(uint32_t runs, const uint8_t* src, uint8_t* dest) { + while (runs >= MAX_COPY) { + *dest++ = MAX_COPY - 1; + flz_maxcopy(dest, src); + src += MAX_COPY; + dest += MAX_COPY; + runs -= MAX_COPY; + } + if (runs > 0) { + *dest++ = runs - 1; + flz_smallcopy(dest, src, runs); + dest += runs; + } + return dest; +} + +static uint8_t* flz1_match(uint32_t len, uint32_t distance, uint8_t* op) { + --distance; + if (FASTLZ_UNLIKELY(len > MAX_LEN - 2)) + while (len > MAX_LEN - 2) { + *op++ = (7 << 5) + (distance >> 8); + *op++ = MAX_LEN - 2 - 7 - 2; + *op++ = (distance & 255); + len -= MAX_LEN - 2; + } + if (len < 7) { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } else { + *op++ = (7 << 5) + (distance >> 8); + *op++ = len - 7; + *op++ = (distance & 255); + } + return op; +} + +#define FASTLZ_BOUND_CHECK(cond) \ + if (FASTLZ_UNLIKELY(!(cond))) return 0; + +int fastlz1_compress(const void* input, int length, void* output) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_start = ip; + const uint8_t* ip_bound = ip + length - 4; /* because readU32 */ + const uint8_t* ip_limit = ip + length - 12 - 1; + uint8_t* op = (uint8_t*)output; + + uint32_t htab[HASH_SIZE]; + uint32_t seq, hash; + + /* initializes hash table */ + for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0; + + /* we start with literal copy */ + const uint8_t* anchor = ip; + ip += 2; + + /* main loop */ + while (FASTLZ_LIKELY(ip < ip_limit)) { + const uint8_t* ref; + uint32_t distance, cmp; + + /* find potential match */ + do { + seq = flz_readu32(ip) & 0xffffff; + hash = flz_hash(seq); + ref = ip_start + htab[hash]; + htab[hash] = ip - ip_start; + distance = ip - ref; + cmp = FASTLZ_LIKELY(distance < MAX_L1_DISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; + ++ip; + } while (seq != cmp); + + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; + --ip; + + if (FASTLZ_LIKELY(ip > anchor)) { + op = flz_literals(ip - anchor, anchor, op); + } + + uint32_t len = flz_cmp(ref + 3, ip + 3, ip_bound); + op = flz1_match(len, distance, op); + + /* update the hash at match boundary */ + ip += len; + seq = flz_readu32(ip); + hash = flz_hash(seq & 0xffffff); + htab[hash] = ip++ - ip_start; + seq >>= 8; + hash = flz_hash(seq); + htab[hash] = ip++ - ip_start; + + anchor = ip; + } + + uint32_t copy = (uint8_t*)input + length - anchor; + op = flz_literals(copy, anchor, op); + + return op - (uint8_t*)output; +} + +int fastlz1_decompress(const void* input, int length, void* output, int maxout) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_limit = ip + length; + const uint8_t* ip_bound = ip_limit - 2; + uint8_t* op = (uint8_t*)output; + uint8_t* op_limit = op + maxout; + uint32_t ctrl = (*ip++) & 31; + + while (1) { + if (ctrl >= 32) { + uint32_t len = (ctrl >> 5) - 1; + uint32_t ofs = (ctrl & 31) << 8; + const uint8_t* ref = op - ofs - 1; + if (len == 7 - 1) { + FASTLZ_BOUND_CHECK(ip <= ip_bound); + len += *ip++; + } + ref -= *ip++; + len += 3; + FASTLZ_BOUND_CHECK(op + len <= op_limit); + FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output); + fastlz_memmove(op, ref, len); + op += len; + } else { + ctrl++; + FASTLZ_BOUND_CHECK(op + ctrl <= op_limit); + FASTLZ_BOUND_CHECK(ip + ctrl <= ip_limit); + fastlz_memcpy(op, ip, ctrl); + ip += ctrl; + op += ctrl; + } + + if (FASTLZ_UNLIKELY(ip > ip_bound)) break; + ctrl = *ip++; + } + + return op - (uint8_t*)output; +} + +static uint8_t* flz2_match(uint32_t len, uint32_t distance, uint8_t* op) { + --distance; + if (distance < MAX_L2_DISTANCE) { + if (len < 7) { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } else { + *op++ = (7 << 5) + (distance >> 8); + for (len -= 7; len >= 255; len -= 255) *op++ = 255; + *op++ = len; + *op++ = (distance & 255); + } + } else { + /* far away, but not yet in the another galaxy... */ + if (len < 7) { + distance -= MAX_L2_DISTANCE; + *op++ = (len << 5) + 31; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } else { + distance -= MAX_L2_DISTANCE; + *op++ = (7 << 5) + 31; + for (len -= 7; len >= 255; len -= 255) *op++ = 255; + *op++ = len; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + } + return op; +} + +int fastlz2_compress(const void* input, int length, void* output) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_start = ip; + const uint8_t* ip_bound = ip + length - 4; /* because readU32 */ + const uint8_t* ip_limit = ip + length - 12 - 1; + uint8_t* op = (uint8_t*)output; + + uint32_t htab[HASH_SIZE]; + uint32_t seq, hash; + + /* initializes hash table */ + for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0; + + /* we start with literal copy */ + const uint8_t* anchor = ip; + ip += 2; + + /* main loop */ + while (FASTLZ_LIKELY(ip < ip_limit)) { + const uint8_t* ref; + uint32_t distance, cmp; + + /* find potential match */ + do { + seq = flz_readu32(ip) & 0xffffff; + hash = flz_hash(seq); + ref = ip_start + htab[hash]; + htab[hash] = ip - ip_start; + distance = ip - ref; + cmp = FASTLZ_LIKELY(distance < MAX_FARDISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; + ++ip; + } while (seq != cmp); + + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; + + --ip; + + /* far, needs at least 5-byte match */ + if (distance >= MAX_L2_DISTANCE) { + if (ref[3] != ip[3] || ref[4] != ip[4]) { + ++ip; + continue; + } + } + + if (FASTLZ_LIKELY(ip > anchor)) { + op = flz_literals(ip - anchor, anchor, op); + } + + uint32_t len = flz_cmp(ref + 3, ip + 3, ip_bound); + op = flz2_match(len, distance, op); + + /* update the hash at match boundary */ + ip += len; + seq = flz_readu32(ip); + hash = flz_hash(seq & 0xffffff); + htab[hash] = ip++ - ip_start; + seq >>= 8; + hash = flz_hash(seq); + htab[hash] = ip++ - ip_start; + + anchor = ip; + } + + uint32_t copy = (uint8_t*)input + length - anchor; + op = flz_literals(copy, anchor, op); + + /* marker for fastlz2 */ + *(uint8_t*)output |= (1 << 5); + + return op - (uint8_t*)output; +} + +int fastlz2_decompress(const void* input, int length, void* output, int maxout) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_limit = ip + length; + const uint8_t* ip_bound = ip_limit - 2; + uint8_t* op = (uint8_t*)output; + uint8_t* op_limit = op + maxout; + uint32_t ctrl = (*ip++) & 31; + + while (1) { + if (ctrl >= 32) { + uint32_t len = (ctrl >> 5) - 1; + uint32_t ofs = (ctrl & 31) << 8; + const uint8_t* ref = op - ofs - 1; + + uint8_t code; + if (len == 7 - 1) do { + FASTLZ_BOUND_CHECK(ip <= ip_bound); + code = *ip++; + len += code; + } while (code == 255); + code = *ip++; + ref -= code; + len += 3; + + /* match from 16-bit distance */ + if (FASTLZ_UNLIKELY(code == 255)) + if (FASTLZ_LIKELY(ofs == (31 << 8))) { + FASTLZ_BOUND_CHECK(ip < ip_bound); + ofs = (*ip++) << 8; + ofs += *ip++; + ref = op - ofs - MAX_L2_DISTANCE - 1; + } + + FASTLZ_BOUND_CHECK(op + len <= op_limit); + FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output); + fastlz_memmove(op, ref, len); + op += len; + } else { + ctrl++; + FASTLZ_BOUND_CHECK(op + ctrl <= op_limit); + FASTLZ_BOUND_CHECK(ip + ctrl <= ip_limit); + fastlz_memcpy(op, ip, ctrl); + ip += ctrl; + op += ctrl; + } + + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; + ctrl = *ip++; + } + + return op - (uint8_t*)output; +} + +int fastlz_compress(const void* input, int length, void* output) { + /* for short block, choose fastlz1 */ + if (length < 65536) return fastlz1_compress(input, length, output); + + /* else... */ + return fastlz2_compress(input, length, output); +} + +int fastlz_decompress(const void* input, int length, void* output, int maxout) { + /* magic identifier for compression level */ + int level = ((*(const uint8_t*)input) >> 5) + 1; + + if (level == 1) return fastlz1_decompress(input, length, output, maxout); + if (level == 2) return fastlz2_decompress(input, length, output, maxout); + + /* unknown level, trigger error */ + return 0; +} + +int fastlz_compress_level(int level, const void* input, int length, void* output) { + if (level == 1) return fastlz1_compress(input, length, output); + if (level == 2) return fastlz2_compress(input, length, output); + + return 0; +} + +#pragma GCC diagnostic pop diff --git a/op-e2e/fastlz/fastlz.go b/op-e2e/fastlz/fastlz.go new file mode 100644 index 000000000000..fc0a43cf3af7 --- /dev/null +++ b/op-e2e/fastlz/fastlz.go @@ -0,0 +1,34 @@ +package fastlz + +// #include +// #include "fastlz.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +// Compress compresses the input data using the FastLZ algorithm. +// The version of FastLZ used is FastLZ level 1 with the implementation from +// this commit: https://github.com/ariya/FastLZ/commit/344eb4025f9ae866ebf7a2ec48850f7113a97a42 +// Which is the same commit that Solady uses: https://github.com/Vectorized/solady/blob/main/src/utils/LibZip.sol#L19 +// Note the FastLZ compression ratio does vary between different versions of the library. +func Compress(input []byte) ([]byte, error) { + length := len(input) + if length == 0 { + return nil, errors.New("no input provided") + } + + result := make([]byte, length*2) + size := C.fastlz_compress(unsafe.Pointer(&input[0]), C.int(length), unsafe.Pointer(&result[0])) + + runtime.KeepAlive(input) + + if size == 0 { + return nil, errors.New("error compressing data") + } + + return result[:size], nil +} diff --git a/op-e2e/fastlz/fastlz.h b/op-e2e/fastlz/fastlz.h new file mode 100644 index 000000000000..4754d647573a --- /dev/null +++ b/op-e2e/fastlz/fastlz.h @@ -0,0 +1,100 @@ +/* + FastLZ - Byte-aligned LZ77 compression library + Copyright (C) 2005-2020 Ariya Hidayat + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + This implementation is taken from the following repository/commit: + https://github.com/ariya/FastLZ/tree/344eb4025f9ae866ebf7a2ec48850f7113a97a42 +*/ + +#ifndef FASTLZ_H +#define FASTLZ_H + +#define FASTLZ_VERSION 0x000500 + +#define FASTLZ_VERSION_MAJOR 0 +#define FASTLZ_VERSION_MINOR 5 +#define FASTLZ_VERSION_REVISION 0 + +#define FASTLZ_VERSION_STRING "0.5.0" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. + + Compression level can be specified in parameter level. At the moment, + only level 1 and level 2 are supported. + Level 1 is the fastest compression and generally useful for short data. + Level 2 is slightly slower but it gives better compression ratio. + + Note that the compressed data, regardless of the level, can always be + decompressed using the function fastlz_decompress below. +*/ + +int fastlz_compress_level(int level, const void* input, int length, void* output); + +/** + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) + will be returned instead. + + The input buffer and the output buffer can not overlap. + + Decompression is memory safe and guaranteed not to write the output buffer + more than what is specified in maxout. + + Note that the decompression will always work, regardless of the + compression level specified in fastlz_compress_level above (when + producing the compressed block). + */ + +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +/** + DEPRECATED. + + This is similar to fastlz_compress_level above, but with the level + automatically chosen. + + This function is deprecated and it will be completely removed in some future + version. +*/ + +int fastlz_compress(const void* input, int length, void* output); + +#if defined(__cplusplus) +} +#endif + +#endif /* FASTLZ_H */ diff --git a/op-e2e/fastlz_test.go b/op-e2e/fastlz_test.go new file mode 100644 index 000000000000..c8b6d8b2e88b --- /dev/null +++ b/op-e2e/fastlz_test.go @@ -0,0 +1,235 @@ +package op_e2e + +import ( + "context" + "encoding/binary" + "fmt" + "math/big" + "testing" + "time" + + "github.com/ethereum-optimism/optimism/op-bindings/bindings" + "github.com/ethereum-optimism/optimism/op-e2e/fastlz" + "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient/simulated" + "github.com/ethereum/go-ethereum/params" + "github.com/stretchr/testify/require" +) + +var ( + // This bytecode and ABI is for a contract, which wraps the LibZip library for easier fuzz testing. + // The source of this contract is here: https://github.com/danyalprout/fastlz/blob/main/src/FastLz.sol#L6-L10 + contract = &bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"fastLz\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"}]", + } + + fastLzBytecode = "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063920a769114610030575b600080fd5b61004361003e366004610374565b610055565b60405190815260200160405180910390f35b600061006082610067565b5192915050565b60606101e0565b818153600101919050565b600082840393505b838110156100a25782810151828201511860001a1590930292600101610081565b9392505050565b825b602082106100d75782516100c0601f8361006e565b5260209290920191601f19909101906021016100ab565b81156100a25782516100ec600184038361006e565b520160010192915050565b60006001830392505b61010782106101385761012a8360ff1661012560fd6101258760081c60e0018961006e565b61006e565b935061010682039150610100565b600782106101655761015e8360ff16610125600785036101258760081c60e0018961006e565b90506100a2565b61017e8360ff166101258560081c8560051b018761006e565b949350505050565b80516101d890838303906101bc90600081901a600182901a60081b1760029190911a60101b17639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b5060405161800038823961800081016020830180600d8551820103826002015b81811015610313576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b9091189091528401908183039084841061026857506102a3565b600184019350611fff821161029d578251600081901a600182901a60081b1760029190911a60101b17810361029d57506102a3565b5061020c565b8383106102b1575050610313565b600183039250858311156102cf576102cc87878886036100a9565b96505b6102e3600985016003850160038501610079565b91506102f08782846100f7565b9650506103088461030386848601610186565b610186565b915050809350610200565b5050617fe061032884848589518601036100a9565b03925050506020820180820383525b81811161034e57617fe08101518152602001610337565b5060008152602001604052919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561038657600080fd5b813567ffffffffffffffff8082111561039e57600080fd5b818401915084601f8301126103b257600080fd5b8135818111156103c4576103c461035e565b604051601f8201601f19908116603f011681019083821181831017156103ec576103ec61035e565b8160405282815287602084870101111561040557600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122000646b2953fc4a6f501bd0456ac52203089443937719e16b3190b7979c39511264736f6c63430008190033" + + seeds = [][]byte{ + // https: //basescan.org/tx/0x5dadeb52979f29fc7a7494c43fdabc5be1d8ff404f3aafe93d729fa8e5d00769 + common.FromHex("0xb9047c02f904788221050883036ee48409c6c87383037f6f941195cf65f83b3a5768f3c496d3a05ad6412c64b78644364c5bb000b90404d123b4d80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000f6476f90447748c19248ccaa31e6b8bfda4eb9d830f5f47df7f0998f7c2123d9e6137761b75d3184efb0f788e3b14516000000000000000000000000000000000000000000000000000044364c5bb000000000000000000000000000f38e53bd45c8225a7c94b513beadaa7afe5d222d0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d6574614d61736b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656852577a743347745961776343347564745657557233454c587261436746434259416b66507331696f48610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd0d83d9e840f8e27d5c2e365fd365ff1c05b2480000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000041e4480d358dbae20880960a0a464d63b06565a0c9f9b1b37aa94b522247b23ce149c81359bf4239d1a879eeb41047ec710c15f5c0f67453da59a383e6abd742971c00000000000000000000000000000000000000000000000000000000000000c001a0b57f0ff8516ea29cb26a44ac5055a5420847d1e16a8e7b03b70f0c02291ff2d5a00ad3771e5f39ccacfff0faa8c5d25ef7a1c179f79e66e828ffddcb994c8b512e"), + // https://basescan.org/tx/0xfaada76a2dac09fc17f5a28d066aaabefc6d82ef6589b211ed8c9f766b070721 + common.FromHex("b87602f873822105528304320f8409cfe5c98252089480c67432656d59144ceff962e8faf8926599bcf888011dfe52d06b633f80c001a08632f069f837aea7a28bab0affee14dda116956bd5a850a355c045d25afedd17a0084b8f273efffe17ece527116053e5781a4915ff89ab9c379f1e62c25b697687"), + // https://basescan.org/tx/0x112864e9b971af6a1dac840018833c5a5a659acc187cfdaba919ad1da013678d + common.FromHex("b8b302f8b0822105308304320f8409cfe5c9827496944ed4e862860bed51a9570b96d89af5e1b0efefed80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000015e10fb0973595fffffc001a02020e39f07917c1a852feb131c857e12478c7e88a20772b91a8bf5cee38c5aeea06055981727f9aaa3471c1af800555b35a77916c154be3f9d02ad1a63029455ab"), + // https://basescan.org/tx/0x6905051352691641888d0c427fb137c5b95afb5870d5169ff014eff1d0952195 + common.FromHex("b87202f86f8221058303dc6c8310db1f84068fa8d7838954409436af2ff952a7355c8045fcd5e88bc9f6c8257f7b8080c001a0b89e7ff3d7694109e73e7f4244e032581670313c36e48e485c9c94b853bd81d2a038ffaf8f10859ce21d1f7f7046c3d08027fb8aa15b69038f6102be97aaa1179a"), + // https://basescan.org/tx/0x6a38e9a26d7202a2268de69d2d47531c1a9829867579a483fb48d78e9e0b080d + common.FromHex("b9049b02f904978221058201618506fc23ac008506fc23ac008306ddd0943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b904243593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006641d67b00000000000000000000000000000000000000000000000000000000000000030a000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000088487bd8c3222d64d1d0b3fa7098dcf9d94d79e000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000006669635d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad000000000000000000000000000000000000000000000000000000006641d78900000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000418661369ca026f92ff88347bd0e3625a7b5ed65071b366368c68ad7c55aed136c18659b34f9246e30a784227a53dd374fbd3d2124696808c678cd987c4e954a681b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000549e5c020c764dbfffff00000000000000000000000000000000000000000000000002e5a629c093a2b600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b088487bd8c3222d64d1d0b3fa7098dcf9d94d79e0027104200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c001a014a3acef764ff6d3bb9bd81e420bfa94171a5734ab997dfbc9b41b653ce018a4a01ff5fccb01ef5c60ba3aef67d4e74f3f47312dd78bfbbff9e5090fbf2d3d62bb"), + } +) + +type testStateGetter struct { + baseFee, blobBaseFee, overhead, scalar *big.Int + baseFeeScalar, blobBaseFeeScalar uint32 +} + +func (sg *testStateGetter) GetState(addr common.Address, slot common.Hash) common.Hash { + buf := common.Hash{} + switch slot { + case types.L1BaseFeeSlot: + sg.baseFee.FillBytes(buf[:]) + case types.OverheadSlot: + sg.overhead.FillBytes(buf[:]) + case types.ScalarSlot: + sg.scalar.FillBytes(buf[:]) + case types.L1BlobBaseFeeSlot: + sg.blobBaseFee.FillBytes(buf[:]) + case types.L1FeeScalarsSlot: + // fetch Ecotone fee sclars + offset := 32 - types.BaseFeeScalarSlotOffset - 4 // todo maybe make scalarSelectSTartPublic + binary.BigEndian.PutUint32(buf[offset:offset+4], sg.baseFeeScalar) + binary.BigEndian.PutUint32(buf[offset+4:offset+8], sg.blobBaseFeeScalar) + default: + panic("unknown slot") + } + return buf +} + +func FuzzFjordCostFunction(f *testing.F) { + for _, seed := range seeds { + f.Add(seed) + } + + cfg := DefaultSystemConfig(f) + s := hexutil.Uint64(0) + cfg.DeployConfig.L2GenesisCanyonTimeOffset = &s + cfg.DeployConfig.L2GenesisDeltaTimeOffset = &s + cfg.DeployConfig.L2GenesisEcotoneTimeOffset = &s + cfg.DeployConfig.L2GenesisFjordTimeOffset = &s + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + opGeth, err := NewOpGeth(f, ctx, &cfg) + require.NoError(f, err) + defer opGeth.Close() + + gpoCaller, err := bindings.NewGasPriceOracleCaller(predeploys.GasPriceOracleAddr, opGeth.L2Client) + require.NoError(f, err) + + isFjord, err := gpoCaller.IsFjord(&bind.CallOpts{}) + require.NoError(f, err) + require.True(f, isFjord) + + _, err = opGeth.AddL2Block(context.Background()) + require.NoError(f, err) + + baseFee, err := gpoCaller.L1BaseFee(&bind.CallOpts{}) + require.NoError(f, err) + require.Greater(f, baseFee.Uint64(), uint64(0)) + + blobBaseFee, err := gpoCaller.BlobBaseFee(&bind.CallOpts{}) + require.NoError(f, err) + require.Greater(f, blobBaseFee.Uint64(), uint64(0)) + + baseFeeScalar, err := gpoCaller.BaseFeeScalar(&bind.CallOpts{}) + require.NoError(f, err) + require.Greater(f, baseFeeScalar, uint32(0)) + + blobBaseFeeScalar, err := gpoCaller.BlobBaseFeeScalar(&bind.CallOpts{}) + require.NoError(f, err) + require.Equal(f, blobBaseFeeScalar, uint32(0)) + + // we can ignore the blobbasefee, as the scalar is set to zero. + feeScaled := big.NewInt(16) + feeScaled.Mul(feeScaled, baseFee) + feeScaled.Mul(feeScaled, big.NewInt(int64(baseFeeScalar))) + + db := &testStateGetter{ + baseFee: baseFee, + blobBaseFee: blobBaseFee, + overhead: big.NewInt(0), // not used for fjord + scalar: big.NewInt(0), // not used for fjord + baseFeeScalar: baseFeeScalar, + blobBaseFeeScalar: blobBaseFeeScalar, + } + + zeroTime := uint64(0) + // create a config where ecotone/fjord upgrades are active + config := ¶ms.ChainConfig{ + Optimism: params.OptimismTestConfig.Optimism, + RegolithTime: &zeroTime, + EcotoneTime: &zeroTime, + FjordTime: &zeroTime, + } + require.True(f, config.IsOptimismEcotone(zeroTime)) + require.True(f, config.IsOptimismFjord(zeroTime)) + costFunc := types.NewL1CostFunc(config, db) + + f.Fuzz(func(t *testing.T, fuzzedData []byte) { + flzSize := types.FlzCompressLen(fuzzedData) + + // Skip transactions that will be clamped to the minimum or less. These will fuzz to different values + // due to the solidity l1BlockGenesis adding 68 extra bytes to account for the signature. + estimatedSize := big.NewInt(int64(flzSize)) + estimatedSize.Mul(estimatedSize, types.L1CostFastlzCoef) + estimatedSize.Add(estimatedSize, types.L1CostIntercept) + + if estimatedSize.Cmp(types.MinTransactionSizeScaled) < 0 { + t.Skip() + return + } + + l1FeeSolidity, err := gpoCaller.GetL1Fee(&bind.CallOpts{}, fuzzedData) + require.NoError(t, err) + + // remove the adjustment + l1FeeSolidity.Mul(l1FeeSolidity, big.NewInt(1e12)) + l1FeeSolidity.Div(l1FeeSolidity, feeScaled) + + totalAdjustment := new(big.Int).Mul(big.NewInt(68), big.NewInt(836_500)) + l1FeeSolidity.Sub(l1FeeSolidity, totalAdjustment) + + l1FeeSolidity.Mul(l1FeeSolidity, feeScaled) + l1FeeSolidity.Div(l1FeeSolidity, big.NewInt(1e12)) + + costData := types.NewRollupCostData(fuzzedData) + + l1FeeGeth := costFunc(costData, zeroTime) + + require.Equal(t, l1FeeGeth.Uint64(), l1FeeSolidity.Uint64(), fmt.Sprintf("fuzzedData: %x", common.Bytes2Hex(fuzzedData))) + }) +} + +func FuzzFastLzGethSolidity(f *testing.F) { + for _, seed := range seeds { + f.Add(seed) + } + + contractAbi, err := contract.GetAbi() + require.NoError(f, err) + + b := simulated.NewBackend(map[common.Address]types.Account{ + predeploys.GasPriceOracleAddr: { + Code: common.FromHex(fastLzBytecode), + }, + }) + defer func() { + require.NoError(f, b.Close()) + }() + + client := b.Client() + + f.Fuzz(func(t *testing.T, data []byte) { + req, err := contractAbi.Pack("fastLz", data) + require.NoError(t, err) + + response, err := client.CallContract(context.Background(), ethereum.CallMsg{ + To: &predeploys.GasPriceOracleAddr, + Data: req, + }, nil) + require.NoError(t, err) + + result, err := contractAbi.Unpack("fastLz", response) + require.NoError(t, err) + + gethCompressedLen := types.FlzCompressLen(data) + require.Equal(t, result[0].(*big.Int).Uint64(), uint64(gethCompressedLen)) + }) +} + +func FuzzFastLzCgo(f *testing.F) { + for _, seed := range seeds { + f.Add(seed) + } + + f.Fuzz(func(t *testing.T, data []byte) { + if len(data) == 0 { + t.Skip() + return + } + + // Our implementation in go-ethereum + compressedLen := types.FlzCompressLen(data) + + out, err := fastlz.Compress(data) + require.NoError(t, err) + require.Equal(t, int(compressedLen), len(out)) + }) +} diff --git a/op-e2e/op_geth.go b/op-e2e/op_geth.go index 01cfcc0aee71..7cea17d43a42 100644 --- a/op-e2e/op_geth.go +++ b/op-e2e/op_geth.go @@ -51,7 +51,7 @@ type OpGeth struct { lgr log.Logger } -func NewOpGeth(t *testing.T, ctx context.Context, cfg *SystemConfig) (*OpGeth, error) { +func NewOpGeth(t testing.TB, ctx context.Context, cfg *SystemConfig) (*OpGeth, error) { logger := testlog.Logger(t, log.LevelCrit) l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs, config.L1Deployments) diff --git a/op-e2e/setup.go b/op-e2e/setup.go index 2e22fd65302a..984b27a9edfe 100644 --- a/op-e2e/setup.go +++ b/op-e2e/setup.go @@ -84,7 +84,7 @@ func newTxMgrConfig(l1Addr string, privKey *ecdsa.PrivateKey) txmgr.CLIConfig { } } -func DefaultSystemConfig(t *testing.T) SystemConfig { +func DefaultSystemConfig(t testing.TB) SystemConfig { config.ExternalL2TestParms.SkipIfNecessary(t) secrets, err := e2eutils.DefaultMnemonicConfig.Secrets() @@ -161,7 +161,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig { } } -func writeDefaultJWT(t *testing.T) string { +func writeDefaultJWT(t testing.TB) string { // Sadly the geth node config cannot load JWT secret from memory, it has to be a file jwtPath := path.Join(t.TempDir(), "jwt_secret") if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(testingJWTSecret[:])), 0o600); err != nil { diff --git a/op-e2e/system_test.go b/op-e2e/system_test.go index afffad714bc9..97375be97d69 100644 --- a/op-e2e/system_test.go +++ b/op-e2e/system_test.go @@ -1211,6 +1211,18 @@ func TestFees(t *testing.T) { cfg.DeployConfig.L2GenesisEcotoneTimeOffset = new(hexutil.Uint64) testFees(t, cfg) }) + t.Run("fjord", func(t *testing.T) { + InitParallel(t) + cfg := DefaultSystemConfig(t) + cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7)) + + cfg.DeployConfig.L2GenesisRegolithTimeOffset = new(hexutil.Uint64) + cfg.DeployConfig.L2GenesisCanyonTimeOffset = new(hexutil.Uint64) + cfg.DeployConfig.L2GenesisDeltaTimeOffset = new(hexutil.Uint64) + cfg.DeployConfig.L2GenesisEcotoneTimeOffset = new(hexutil.Uint64) + cfg.DeployConfig.L2GenesisFjordTimeOffset = new(hexutil.Uint64) + testFees(t, cfg) + }) } func testFees(t *testing.T, cfg SystemConfig) { @@ -1352,11 +1364,25 @@ func testFees(t *testing.T, cfg SystemConfig) { require.NoError(t, err) require.Equal(t, sys.RollupConfig.IsEcotone(header.Time), gpoEcotone, "GPO and chain must have same ecotone view") + gpoFjord, err := gpoContract.IsFjord(nil) + require.NoError(t, err) + require.Equal(t, sys.RollupConfig.IsFjord(header.Time), gpoFjord, "GPO and chain must have same fjord view") + gpoL1Fee, err := gpoContract.GetL1Fee(&bind.CallOpts{}, bytes) require.Nil(t, err) adjustedGPOFee := gpoL1Fee - if sys.RollupConfig.IsRegolith(header.Time) { + if sys.RollupConfig.IsFjord(header.Time) { + // The fastlz size of the transaction is 102 bytes + require.Equal(t, uint64(102), tx.RollupCostData().FastLzSize) + // Which results in both the fjord cost function and GPO using the minimum value for the fastlz regression: + // Geth Linear Regression: -42.5856 + 102 * 0.8365 = 42.7374 + // GPO Linear Regression: -42.5856 + 170 * 0.8365 = 99.6194 + // The additional 68 (170 vs. 102) is due to the GPO adding 68 bytes to account for the signature. + require.Greater(t, types.MinTransactionSize.Uint64(), uint64(99)) + // Because of this, we don't need to do any adjustment as the GPO and cost func are both bounded to the minimum value. + // However, if the fastlz regression output is ever larger than the minimum, this will require an adjustment. + } else if sys.RollupConfig.IsRegolith(header.Time) { // if post-regolith, adjust the GPO fee by removing the overhead it adds because of signature data artificialGPOOverhead := big.NewInt(68 * 16) // it adds 68 bytes to cover signature and RLP data l1BaseFee := big.NewInt(7) // we assume the L1 basefee is the minimum, 7 diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index 0be6198374be..c65198bcec73 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -108,6 +108,14 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex } } + if ba.rollupCfg.IsFjordActivationBlock(nextL2Time) { + fjord, err := FjordNetworkUpgradeTransactions() + if err != nil { + return nil, NewCriticalError(fmt.Errorf("failed to build fjord network upgrade txs: %w", err)) + } + upgradeTxs = append(upgradeTxs, fjord...) + } + l1InfoTx, err := L1InfoDepositBytes(ba.rollupCfg, sysConfig, seqNumber, l1Info, nextL2Time) if err != nil { return nil, NewCriticalError(fmt.Errorf("failed to create l1InfoTx: %w", err)) diff --git a/op-node/rollup/derive/fjord_upgrade_transactions.go b/op-node/rollup/derive/fjord_upgrade_transactions.go new file mode 100644 index 000000000000..93f7595dd1d8 --- /dev/null +++ b/op-node/rollup/derive/fjord_upgrade_transactions.go @@ -0,0 +1,90 @@ +package derive + +import ( + "math/big" + + "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + // Gas Price Oracle Parameters + deployFjordGasPriceOracleSource = UpgradeDepositSource{Intent: "Fjord: Gas Price Oracle Deployment"} + GasPriceOracleFjordDeployerAddress = common.HexToAddress("0x4210000000000000000000000000000000000002") + // Fjord GPO Deployment bytecode generated from: + // 1. git checkout 52abfb507342191ae1f960b443ae8aec7598755c + // 2. pnpm clean && pnpm install && pnpm build + // 3. jq -r ".bytecode.object" packages/contracts-bedrock/forge-artifacts/GasPriceOracle.sol/GasPriceOracle.json + // https://github.com/ethereum-optimism/specs/blob/2dd412ce42171b4041e826fd6b8defacc88e8f56/specs/fjord/derivation.md#gaspriceoracle-deployment + gasPriceOracleFjordDeploymentBytecode = common.FromHex("0x608060405234801561001057600080fd5b506117f6806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80636ef25c3a116100b2578063de26c4a111610081578063f45e65d811610066578063f45e65d81461025b578063f820614014610263578063fe173b971461020d57600080fd5b8063de26c4a114610235578063f1c7a58b1461024857600080fd5b80636ef25c3a1461020d5780638e98b10614610213578063960e3a231461021b578063c59859181461022d57600080fd5b806349948e0e11610109578063519b4bd3116100ee578063519b4bd31461019f57806354fd4d50146101a757806368d5dca6146101f057600080fd5b806349948e0e1461016f5780634ef6e2241461018257600080fd5b80630c18c1621461013b57806322b90ab3146101565780632e0f262514610160578063313ce56714610168575b600080fd5b61014361026b565b6040519081526020015b60405180910390f35b61015e61038c565b005b610143600681565b6006610143565b61014361017d3660046112a1565b610515565b60005461018f9060ff1681565b604051901515815260200161014d565b610143610552565b6101e36040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60405161014d9190611370565b6101f86105b3565b60405163ffffffff909116815260200161014d565b48610143565b61015e610638565b60005461018f90610100900460ff1681565b6101f8610832565b6101436102433660046112a1565b610893565b6101436102563660046113e3565b61098d565b610143610a69565b610143610b5c565b6000805460ff1615610304576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038791906113fc565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a4016102fb565b60005460ff16156104e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f616374697665000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60008054610100900460ff16156105355761052f82610bbd565b92915050565b60005460ff16156105495761052f82610bdc565b61052f82610c80565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103879190611415565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146106db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c61670060648201526084016102fb565b60005460ff1661076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e650000000000000060648201526084016102fb565b600054610100900460ff1615610804576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f746976650000000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b60008054610100900460ff16156108da57620f42406108c56108b484610dd4565b516108c090604461146a565b6110f1565b6108d0906010611482565b61052f91906114bf565b60006108e583611150565b60005490915060ff16156108f95792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906113fc565b610986908261146a565b9392505050565b60008054610100900460ff16610a25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f72640000000000000000000060648201526084016102fb565b6000610a3283604461146a565b90506000610a4160ff836114bf565b610a4b908361146a565b610a5690601061146a565b9050610a61816111e0565b949350505050565b6000805460ff1615610afd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f656361746564000000000000000000000000000000000000000000000000000060648201526084016102fb565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600061052f610bcb83610dd4565b51610bd790604461146a565b6111e0565b600080610be883611150565b90506000610bf4610552565b610bfc610832565b610c079060106114fa565b63ffffffff16610c179190611482565b90506000610c23610b5c565b610c2b6105b3565b63ffffffff16610c3b9190611482565b90506000610c49828461146a565b610c539085611482565b9050610c616006600a611646565b610c6c906010611482565b610c7690826114bf565b9695505050505050565b600080610c8c83611150565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1391906113fc565b610d1b610552565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9e91906113fc565b610da8908561146a565b610db29190611482565b610dbc9190611482565b9050610dca6006600a611646565b610a6190826114bf565b6060610f63565b818153600101919050565b600082840393505b838110156109865782810151828201511860001a1590930292600101610dee565b825b60208210610e5b578251610e26601f83610ddb565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190602101610e11565b8115610986578251610e706001840383610ddb565b520160010192915050565b60006001830392505b6101078210610ebc57610eae8360ff16610ea960fd610ea98760081c60e00189610ddb565b610ddb565b935061010682039150610e84565b60078210610ee957610ee28360ff16610ea960078503610ea98760081c60e00189610ddb565b9050610986565b610a618360ff16610ea98560081c8560051b0187610ddb565b610f5b828203610f3f610f2f84600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b81811015611096576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b90911890915284019081830390848410610feb5750611026565b600184019350611fff8211611020578251600081901a600182901a60081b1760029190911a60101b1781036110205750611026565b50610f8f565b838310611034575050611096565b600183039250858311156110525761104f8787888603610e0f565b96505b611066600985016003850160038501610de6565b9150611073878284610e7b565b96505061108b8461108686848601610f02565b610f02565b915050809350610f83565b50506110a88383848851850103610e0f565b925050506040519150618000820180820391508183526020830160005b838110156110dd5782810151828201526020016110c5565b506000920191825250602001604052919050565b60008061110183620cc394611482565b61112b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611652565b905061113b6064620f42406116c6565b81121561052f576109866064620f42406116c6565b80516000908190815b818110156111d35784818151811061117357611173611782565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036111b3576111ac60048461146a565b92506111c1565b6111be60108461146a565b92505b806111cb816117b1565b915050611159565b50610a618261044061146a565b6000806111ec836110f1565b905060006111f8610b5c565b6112006105b3565b63ffffffff166112109190611482565b611218610552565b611220610832565b61122b9060106114fa565b63ffffffff1661123b9190611482565b611245919061146a565b905061125360066002611482565b61125e90600a611646565b6112688284611482565b610a6191906114bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156112b357600080fd5b813567ffffffffffffffff808211156112cb57600080fd5b818401915084601f8301126112df57600080fd5b8135818111156112f1576112f1611272565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561133757611337611272565b8160405282815287602084870101111561135057600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561139d57858101830151858201604001528201611381565b818111156113af576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000602082840312156113f557600080fd5b5035919050565b60006020828403121561140e57600080fd5b5051919050565b60006020828403121561142757600080fd5b815163ffffffff8116811461098657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561147d5761147d61143b565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156114ba576114ba61143b565b500290565b6000826114f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600063ffffffff8083168185168183048111821515161561151d5761151d61143b565b02949350505050565b600181815b8085111561157f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156115655761156561143b565b8085161561157257918102915b93841c939080029061152b565b509250929050565b6000826115965750600161052f565b816115a35750600061052f565b81600181146115b957600281146115c3576115df565b600191505061052f565b60ff8411156115d4576115d461143b565b50506001821b61052f565b5060208310610133831016604e8410600b8410161715611602575081810a61052f565b61160c8383611526565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561163e5761163e61143b565b029392505050565b60006109868383611587565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561168c5761168c61143b565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156116c0576116c061143b565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156117075761170761143b565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156117425761174261143b565b6000871292508782058712848416161561175e5761175e61143b565b878505871281841616156117745761177461143b565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117e2576117e261143b565b506001019056fea164736f6c634300080f000a") + + // Update GasPricePriceOracle Proxy Parameters + updateFjordGasPriceOracleSource = UpgradeDepositSource{Intent: "Fjord: Gas Price Oracle Proxy Update"} + fjordGasPriceOracleAddress = common.HexToAddress("0xa919894851548179A0750865e7974DA599C0Fac7") + + // Enable Fjord Parameters + enableFjordSource = UpgradeDepositSource{Intent: "Fjord: Gas Price Oracle Set Fjord"} + enableFjordInput = crypto.Keccak256([]byte("setFjord()"))[:4] +) + +// FjordNetworkUpgradeTransactions returns the transactions required to upgrade the Fjord network. +func FjordNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { + upgradeTxns := make([]hexutil.Bytes, 0, 3) + + // Deploy Gas Price Oracle transaction + deployGasPriceOracle, err := types.NewTx(&types.DepositTx{ + SourceHash: deployFjordGasPriceOracleSource.SourceHash(), + From: GasPriceOracleFjordDeployerAddress, + To: nil, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 1_450_000, + IsSystemTransaction: false, + Data: gasPriceOracleFjordDeploymentBytecode, + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, deployGasPriceOracle) + + updateGasPriceOracleProxy, err := types.NewTx(&types.DepositTx{ + SourceHash: updateFjordGasPriceOracleSource.SourceHash(), + From: common.Address{}, + To: &predeploys.GasPriceOracleAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 50_000, + IsSystemTransaction: false, + Data: upgradeToCalldata(fjordGasPriceOracleAddress), + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, updateGasPriceOracleProxy) + + enableFjord, err := types.NewTx(&types.DepositTx{ + SourceHash: enableFjordSource.SourceHash(), + From: L1InfoDepositerAddress, + To: &predeploys.GasPriceOracleAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 90_000, + IsSystemTransaction: false, + Data: enableFjordInput, + }).MarshalBinary() + + if err != nil { + return nil, err + } + + upgradeTxns = append(upgradeTxns, enableFjord) + + return upgradeTxns, nil +} diff --git a/op-node/rollup/derive/fjord_upgrade_transactions_test.go b/op-node/rollup/derive/fjord_upgrade_transactions_test.go new file mode 100644 index 000000000000..07da4ce46204 --- /dev/null +++ b/op-node/rollup/derive/fjord_upgrade_transactions_test.go @@ -0,0 +1,59 @@ +package derive + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestFjordSourcesMatchSpec(t *testing.T) { + for _, test := range []struct { + source UpgradeDepositSource + expectedHash string + }{ + { + source: deployFjordGasPriceOracleSource, + expectedHash: "0x86122c533fdcb89b16d8713174625e44578a89751d96c098ec19ab40a51a8ea3", + }, + { + source: updateFjordGasPriceOracleSource, + expectedHash: "0x1e6bb0c28bfab3dc9b36ffb0f721f00d6937f33577606325692db0965a7d58c6", + }, + { + source: enableFjordSource, + expectedHash: "0xbac7bb0d5961cad209a345408b0280a0d4686b1b20665e1b0f9cdafd73b19b6b", + }, + } { + require.Equal(t, common.HexToHash(test.expectedHash), test.source.SourceHash()) + } +} + +func TestFjordNetworkTransactions(t *testing.T) { + upgradeTxns, err := FjordNetworkUpgradeTransactions() + require.NoError(t, err) + require.Len(t, upgradeTxns, 3) + + deployGasPriceOracleSender, deployGasPriceOracle := toDepositTxn(t, upgradeTxns[0]) + require.Equal(t, deployGasPriceOracleSender, common.HexToAddress("0x4210000000000000000000000000000000000002")) + require.Equal(t, deployFjordGasPriceOracleSource.SourceHash(), deployGasPriceOracle.SourceHash()) + require.Nil(t, deployGasPriceOracle.To()) + require.Equal(t, uint64(1_450_000), deployGasPriceOracle.Gas()) + require.Equal(t, gasPriceOracleFjordDeploymentBytecode, deployGasPriceOracle.Data()) + + updateGasPriceOracleSender, updateGasPriceOracle := toDepositTxn(t, upgradeTxns[1]) + require.Equal(t, updateGasPriceOracleSender, common.Address{}) + require.Equal(t, updateFjordGasPriceOracleSource.SourceHash(), updateGasPriceOracle.SourceHash()) + require.NotNil(t, updateGasPriceOracle.To()) + require.Equal(t, *updateGasPriceOracle.To(), common.HexToAddress("0x420000000000000000000000000000000000000F")) + require.Equal(t, uint64(50_000), updateGasPriceOracle.Gas()) + require.Equal(t, common.FromHex("0x3659cfe6000000000000000000000000a919894851548179A0750865e7974DA599C0Fac7"), updateGasPriceOracle.Data()) + + gpoSetFjordSender, gpoSetFjord := toDepositTxn(t, upgradeTxns[2]) + require.Equal(t, gpoSetFjordSender, common.HexToAddress("0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001")) + require.Equal(t, enableFjordSource.SourceHash(), gpoSetFjord.SourceHash()) + require.NotNil(t, gpoSetFjord.To()) + require.Equal(t, *gpoSetFjord.To(), common.HexToAddress("0x420000000000000000000000000000000000000F")) + require.Equal(t, uint64(90_000), gpoSetFjord.Gas()) + require.Equal(t, common.FromHex("0x8e98b106"), gpoSetFjord.Data()) +} diff --git a/op-node/rollup/driver/sequencer.go b/op-node/rollup/driver/sequencer.go index 1ee5038d2b4b..b46db64b1a0e 100644 --- a/op-node/rollup/driver/sequencer.go +++ b/op-node/rollup/driver/sequencer.go @@ -101,6 +101,12 @@ func (d *Sequencer) StartBuildingBlock(ctx context.Context) error { d.log.Info("Sequencing Ecotone upgrade block") } + // For the Fjord activation block we shouldn't include any sequencer transactions. + if d.rollupCfg.IsFjordActivationBlock(uint64(attrs.Timestamp)) { + attrs.NoTxPool = true + d.log.Info("Sequencing Fjord upgrade block") + } + d.log.Debug("prepared attributes for new block", "num", l2Head.Number+1, "time", uint64(attrs.Timestamp), "origin", l1Origin, "origin_time", l1Origin.Time, "noTxPool", attrs.NoTxPool) diff --git a/op-node/rollup/types.go b/op-node/rollup/types.go index 22b3faf999d3..ef675bd91589 100644 --- a/op-node/rollup/types.go +++ b/op-node/rollup/types.go @@ -407,6 +407,14 @@ func (c *Config) IsFjord(timestamp uint64) bool { return c.FjordTime != nil && timestamp >= *c.FjordTime } +// IsFjordActivationBlock returns whether the specified block is the first block subject to the +// Fjord upgrade. +func (c *Config) IsFjordActivationBlock(l2BlockTime uint64) bool { + return c.IsFjord(l2BlockTime) && + l2BlockTime >= c.BlockTime && + !c.IsFjord(l2BlockTime-c.BlockTime) +} + // IsInterop returns true if the Interop hardfork is active at or past the given timestamp. func (c *Config) IsInterop(timestamp uint64) bool { return c.InteropTime != nil && timestamp >= *c.InteropTime diff --git a/op-node/rollup/types_test.go b/op-node/rollup/types_test.go index 6ba4323622ba..aa09d1f5aeef 100644 --- a/op-node/rollup/types_test.go +++ b/op-node/rollup/types_test.go @@ -180,21 +180,87 @@ func TestRandomConfigDescription(t *testing.T) { }) } -// TestRegolithActivation tests the activation condition of the Regolith upgrade. -func TestRegolithActivation(t *testing.T) { - config := randConfig() - config.RegolithTime = nil - require.False(t, config.IsRegolith(0), "false if nil time, even if checking 0") - require.False(t, config.IsRegolith(123456), "false if nil time") - config.RegolithTime = new(uint64) - require.True(t, config.IsRegolith(0), "true at zero") - require.True(t, config.IsRegolith(123456), "true for any") - x := uint64(123) - config.RegolithTime = &x - require.False(t, config.IsRegolith(0)) - require.False(t, config.IsRegolith(122)) - require.True(t, config.IsRegolith(123)) - require.True(t, config.IsRegolith(124)) +// TestActivations tests the activation condition of the various upgrades. +func TestActivations(t *testing.T) { + for _, test := range []struct { + name string + setUpgradeTime func(t *uint64, c *Config) + checkEnabled func(t uint64, c *Config) bool + }{ + { + name: "Regolith", + setUpgradeTime: func(t *uint64, c *Config) { + c.RegolithTime = t + }, + checkEnabled: func(t uint64, c *Config) bool { + return c.IsRegolith(t) + }, + }, + { + name: "Canyon", + setUpgradeTime: func(t *uint64, c *Config) { + c.CanyonTime = t + }, + checkEnabled: func(t uint64, c *Config) bool { + return c.IsCanyon(t) + }, + }, + { + name: "Delta", + setUpgradeTime: func(t *uint64, c *Config) { + c.DeltaTime = t + }, + checkEnabled: func(t uint64, c *Config) bool { + return c.IsDelta(t) + }, + }, + { + name: "Ecotone", + setUpgradeTime: func(t *uint64, c *Config) { + c.EcotoneTime = t + }, + checkEnabled: func(t uint64, c *Config) bool { + return c.IsEcotone(t) + }, + }, + { + name: "Fjord", + setUpgradeTime: func(t *uint64, c *Config) { + c.FjordTime = t + }, + checkEnabled: func(t uint64, c *Config) bool { + return c.IsFjord(t) + }, + }, + { + name: "Interop", + setUpgradeTime: func(t *uint64, c *Config) { + c.InteropTime = t + }, + checkEnabled: func(t uint64, c *Config) bool { + return c.IsInterop(t) + }, + }, + } { + tt := test + t.Run(fmt.Sprintf("TestActivations_%s", tt.name), func(t *testing.T) { + config := randConfig() + test.setUpgradeTime(nil, config) + require.False(t, tt.checkEnabled(0, config), "false if nil time, even if checking 0") + require.False(t, tt.checkEnabled(123456, config), "false if nil time") + + test.setUpgradeTime(new(uint64), config) + require.True(t, tt.checkEnabled(0, config), "true at zero") + require.True(t, tt.checkEnabled(123456, config), "true for any") + + x := uint64(123) + test.setUpgradeTime(&x, config) + require.False(t, tt.checkEnabled(0, config)) + require.False(t, tt.checkEnabled(122, config)) + require.True(t, tt.checkEnabled(123, config)) + require.True(t, tt.checkEnabled(124, config)) + }) + } } type mockL2Client struct { diff --git a/op-service/eth/types.go b/op-service/eth/types.go index 9f153684e947..81a95fc968f8 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -393,45 +393,45 @@ const ( L1ScalarEcotone = byte(1) ) -type EcostoneScalars struct { +type EcotoneScalars struct { BlobBaseFeeScalar uint32 BaseFeeScalar uint32 } -func (sysCfg *SystemConfig) EcotoneScalars() (EcostoneScalars, error) { +func (sysCfg *SystemConfig) EcotoneScalars() (EcotoneScalars, error) { if err := CheckEcotoneL1SystemConfigScalar(sysCfg.Scalar); err != nil { if errors.Is(err, ErrBedrockScalarPaddingNotEmpty) { // L2 spec mandates we set baseFeeScalar to MaxUint32 if there are non-zero bytes in // the padding area. - return EcostoneScalars{BlobBaseFeeScalar: 0, BaseFeeScalar: math.MaxUint32}, nil + return EcotoneScalars{BlobBaseFeeScalar: 0, BaseFeeScalar: math.MaxUint32}, nil } - return EcostoneScalars{}, err + return EcotoneScalars{}, err } return DecodeScalar(sysCfg.Scalar) } // DecodeScalar decodes the blobBaseFeeScalar and baseFeeScalar from a 32-byte scalar value. // It uses the first byte to determine the scalar format. -func DecodeScalar(scalar [32]byte) (EcostoneScalars, error) { +func DecodeScalar(scalar [32]byte) (EcotoneScalars, error) { switch scalar[0] { case L1ScalarBedrock: - return EcostoneScalars{ + return EcotoneScalars{ BlobBaseFeeScalar: 0, BaseFeeScalar: binary.BigEndian.Uint32(scalar[28:32]), }, nil case L1ScalarEcotone: - return EcostoneScalars{ + return EcotoneScalars{ BlobBaseFeeScalar: binary.BigEndian.Uint32(scalar[24:28]), BaseFeeScalar: binary.BigEndian.Uint32(scalar[28:32]), }, nil default: - return EcostoneScalars{}, fmt.Errorf("unexpected system config scalar: %x", scalar) + return EcotoneScalars{}, fmt.Errorf("unexpected system config scalar: %x", scalar) } } -// EncodeScalar encodes the EcostoneScalars into a 32-byte scalar value +// EncodeScalar encodes the EcotoneScalars into a 32-byte scalar value // for the Ecotone serialization format. -func EncodeScalar(scalars EcostoneScalars) (scalar [32]byte) { +func EncodeScalar(scalars EcotoneScalars) (scalar [32]byte) { scalar[0] = L1ScalarEcotone binary.BigEndian.PutUint32(scalar[24:28], scalars.BlobBaseFeeScalar) binary.BigEndian.PutUint32(scalar[28:32], scalars.BaseFeeScalar) diff --git a/op-service/eth/types_test.go b/op-service/eth/types_test.go index 53a21332701c..f62c14691a16 100644 --- a/op-service/eth/types_test.go +++ b/op-service/eth/types_test.go @@ -59,7 +59,7 @@ func TestEcotoneScalars(t *testing.T) { func FuzzEncodeScalar(f *testing.F) { f.Fuzz(func(t *testing.T, blobBaseFeeScalar uint32, baseFeeScalar uint32) { - encoded := EncodeScalar(EcostoneScalars{BlobBaseFeeScalar: blobBaseFeeScalar, BaseFeeScalar: baseFeeScalar}) + encoded := EncodeScalar(EcotoneScalars{BlobBaseFeeScalar: blobBaseFeeScalar, BaseFeeScalar: baseFeeScalar}) scalars, err := DecodeScalar(encoded) require.NoError(t, err) require.Equal(t, blobBaseFeeScalar, scalars.BlobBaseFeeScalar)