Commit 49d54c30 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into jm/fix-slither-fail-mode

parents a1d11074 edb6603f
......@@ -137,7 +137,7 @@ func newMiniL2BlockWithNumberParent(numTx int, number *big.Int, parent common.Ha
Difficulty: common.Big0,
Number: big.NewInt(100),
}, nil, nil, nil, trie.NewStackTrie(nil))
l1InfoTx, err := derive.L1InfoDeposit(0, l1Block, eth.SystemConfig{}, false)
l1InfoTx, err := derive.L1InfoDeposit(0, eth.BlockToInfo(l1Block), eth.SystemConfig{}, false)
if err != nil {
panic(err)
}
......@@ -517,7 +517,7 @@ func TestChannelBuilder_OutputFramesMaxFrameIndex(t *testing.T) {
Difficulty: common.Big0,
Number: common.Big0,
}, nil, nil, nil, trie.NewStackTrie(nil))
l1InfoTx, _ := derive.L1InfoDeposit(0, lBlock, eth.SystemConfig{}, false)
l1InfoTx, _ := derive.L1InfoDeposit(0, eth.BlockToInfo(lBlock), eth.SystemConfig{}, false)
txs := []*types.Transaction{types.NewTx(l1InfoTx)}
a := types.NewBlock(&types.Header{
Number: big.NewInt(0),
......
......@@ -41,7 +41,7 @@ type ResourceMeteringResourceConfig struct {
// SystemConfigMetaData contains all meta data concerning the SystemConfig contract.
var SystemConfigMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"_config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"enumSystemConfig.UpdateType\",\"name\":\"updateType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ConfigUpdate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"UNSAFE_BLOCK_SIGNER_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERSION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batcherHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"_config\",\"type\":\"tuple\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumGasLimit\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resourceConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_batcherHash\",\"type\":\"bytes32\"}],\"name\":\"setBatcherHash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setGasConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"}],\"name\":\"setGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxResourceLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"elasticityMultiplier\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"minimumBaseFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"systemTxMaxGas\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"maximumBaseFee\",\"type\":\"uint128\"}],\"internalType\":\"structResourceMetering.ResourceConfig\",\"name\":\"_config\",\"type\":\"tuple\"}],\"name\":\"setResourceConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_unsafeBlockSigner\",\"type\":\"address\"}],\"name\":\"setUnsafeBlockSigner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unsafeBlockSigner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
Bin: "0x60e06040523480156200001157600080fd5b50604051620022c8380380620022c883398101604081905262000034916200084f565b6001608052600260a052600060c052620000548787878787878762000061565b5050505050505062000a4f565b600054610100900460ff1615808015620000825750600054600160ff909116105b80620000b257506200009f306200027060201b62000adf1760201c565b158015620000b2575060005460ff166001145b6200011b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156200013f576000805461ff0019166101001790555b620001496200027f565b6200015488620002e7565b606587905560668690556067859055606880546001600160401b0319166001600160401b038616179055620001a7837f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b620001b28262000366565b620001bc620006b1565b6001600160401b0316846001600160401b031610156200021f5760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640162000112565b801562000266576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b6001600160a01b03163b151590565b600054610100900460ff16620002db5760405162461bcd60e51b815260206004820152602b6024820152600080516020620022a883398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000112565b620002e5620006de565b565b620002f162000745565b6001600160a01b038116620003585760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000112565b6200036381620007a1565b50565b8060a001516001600160801b0316816060015163ffffffff161115620003f55760405162461bcd60e51b815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d617820626173650000000000000000000000606482015260840162000112565b6000816040015160ff16116200045c5760405162461bcd60e51b815260206004820152602560248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f722063616e6e6f74604482015264020626520360dc1b606482015260840162000112565b606854608082015182516001600160401b03909216916200047e91906200099e565b63ffffffff161115620004d45760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640162000112565b6000816020015160ff1611620005455760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201526e06965722063616e6e6f74206265203608c1b606482015260840162000112565b8051602082015163ffffffff82169160ff9091169062000567908290620009c9565b620005739190620009fb565b63ffffffff1614620005ee5760405162461bcd60e51b815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d6974000000000000000000606482015260840162000112565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff96871664ffffffffff199095169490941764010000000060ff948516021764ffffffffff60281b191665010000000000939092169290920263ffffffff60301b19161766010000000000009185169190910217600160501b600160f01b0319166a01000000000000000000009390941692909202600160701b600160f01b03191692909217600160701b6001600160801b0390921691909102179055565b606954600090620006d99063ffffffff6a010000000000000000000082048116911662000a2a565b905090565b600054610100900460ff166200073a5760405162461bcd60e51b815260206004820152602b6024820152600080516020620022a883398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000112565b620002e533620007a1565b6033546001600160a01b03163314620002e55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000112565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200080b57600080fd5b919050565b805163ffffffff811681146200080b57600080fd5b805160ff811681146200080b57600080fd5b80516001600160801b03811681146200080b57600080fd5b60008060008060008060008789036101808112156200086d57600080fd5b6200087889620007f3565b60208a015160408b015160608c015160808d0151939b50919950975095506001600160401b038082168214620008ad57600080fd5b819550620008be60a08c01620007f3565b945060c060bf1984011215620008d357600080fd5b604051925060c08301915082821081831117156200090157634e487b7160e01b600052604160045260246000fd5b506040526200091360c08a0162000810565b81526200092360e08a0162000825565b6020820152620009376101008a0162000825565b60408201526200094b6101208a0162000810565b60608201526200095f6101408a0162000810565b6080820152620009736101608a0162000837565b60a08201528091505092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b600063ffffffff808316818516808303821115620009c057620009c062000988565b01949350505050565b600063ffffffff80841680620009ef57634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600063ffffffff8083168185168183048111821515161562000a215762000a2162000988565b02949350505050565b60006001600160401b03828116848216808303821115620009c057620009c062000988565b60805160a05160c05161182962000a7f600039600061056e015260006105450152600061051c01526118296000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c8063b40a817c116100cd578063f2fde38b11610081578063f68016b711610066578063f68016b7146103f7578063f975e9251461040b578063ffa1ad741461041e57600080fd5b8063f2fde38b146103db578063f45e65d8146103ee57600080fd5b8063c9b26f61116100b2578063c9b26f611461028b578063cc731b021461029e578063e81b2c6d146103d257600080fd5b8063b40a817c14610265578063c71973f61461027857600080fd5b80634f16540b11610124578063715018a611610109578063715018a61461022c5780638da5cb5b14610234578063935f029e1461025257600080fd5b80634f16540b146101f057806354fd4d501461021757600080fd5b80630c18c1621461015657806318d13918146101725780631fd19ee1146101875780634add321d146101cf575b600080fd5b61015f60655481565b6040519081526020015b60405180910390f35b610185610180366004611307565b610426565b005b7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08545b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d76104ea565b60405167ffffffffffffffff9091168152602001610169565b61015f7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b61021f610515565b60405161016991906113a3565b6101856105b8565b60335473ffffffffffffffffffffffffffffffffffffffff166101aa565b6101856102603660046113b6565b6105cc565b6101856102733660046113f0565b610665565b610185610286366004611548565b610750565b610185610299366004611564565b610764565b6103626040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b6040516101699190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b61015f60675481565b6101856103e9366004611307565b610794565b61015f60665481565b6068546101d79067ffffffffffffffff1681565b61018561041936600461157d565b610848565b61015f600081565b61042e610afb565b610456817f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516104de91906113a3565b60405180910390a35050565b6069546000906105109063ffffffff6a010000000000000000000082048116911661161f565b905090565b60606105407f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105697f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105927f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6040516020016105a49392919061164b565b604051602081830303815290604052905090565b6105c0610afb565b6105ca6000610cb9565b565b6105d4610afb565b606582905560668190556040805160208101849052908101829052600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050600160007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be8360405161065891906113a3565b60405180910390a3505050565b61066d610afb565b6106756104ea565b67ffffffffffffffff168167ffffffffffffffff1610156106f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064015b60405180910390fd5b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831690811790915560408051602080820193909352815180820390930183528101905260026104ad565b610758610afb565b61076181610d30565b50565b61076c610afb565b60678190556040805160208082018490528251808303909101815290820190915260006104ad565b61079c610afb565b73ffffffffffffffffffffffffffffffffffffffff811661083f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106ee565b61076181610cb9565b600054610100900460ff16158080156108685750600054600160ff909116105b806108825750303b158015610882575060005460ff166001145b61090e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016106ee565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561096c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6109746111a4565b61097d88610794565b606587905560668690556067859055606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff86161790557f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c088390556109ed82610d30565b6109f56104ea565b67ffffffffffffffff168467ffffffffffffffff161015610a72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b8015610ad557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60335473ffffffffffffffffffffffffffffffffffffffff1633146105ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ee565b606081600003610bbf57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115610be95780610bd3816116c1565b9150610be29050600a83611728565b9150610bc3565b60008167ffffffffffffffff811115610c0457610c0461140b565b6040519080825280601f01601f191660200182016040528015610c2e576020820181803683370190505b5090505b8415610cb157610c4360018361173c565b9150610c50600a86611753565b610c5b906030611767565b60f81b818381518110610c7057610c7061177f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610caa600a86611728565b9450610c32565b949350505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115610de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d61782062617365000000000000000000000060648201526084016106ee565b6000816040015160ff1611610e77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f722063616e6e6f7460448201527f206265203000000000000000000000000000000000000000000000000000000060648201526084016106ee565b6068546080820151825167ffffffffffffffff90921691610e9891906117ae565b63ffffffff161115610f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b6000816020015160ff1611610f9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f742062652030000000000000000000000000000000000060648201526084016106ee565b8051602082015163ffffffff82169160ff90911690610fbd9082906117cd565b610fc791906117f0565b63ffffffff161461105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d697400000000000000000060648201526084016106ee565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b600054610100900460ff1661123b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca600054610100900460ff166112d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca33610cb9565b803573ffffffffffffffffffffffffffffffffffffffff8116811461130257600080fd5b919050565b60006020828403121561131957600080fd5b611322826112de565b9392505050565b60005b8381101561134457818101518382015260200161132c565b83811115611353576000848401525b50505050565b60008151808452611371816020860160208601611329565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113226020830184611359565b600080604083850312156113c957600080fd5b50508035926020909101359150565b803567ffffffffffffffff8116811461130257600080fd5b60006020828403121561140257600080fd5b611322826113d8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b803563ffffffff8116811461130257600080fd5b803560ff8116811461130257600080fd5b80356fffffffffffffffffffffffffffffffff8116811461130257600080fd5b600060c0828403121561149157600080fd5b60405160c0810181811067ffffffffffffffff821117156114db577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040529050806114ea8361143a565b81526114f86020840161144e565b60208201526115096040840161144e565b604082015261151a6060840161143a565b606082015261152b6080840161143a565b608082015261153c60a0840161145f565b60a08201525092915050565b600060c0828403121561155a57600080fd5b611322838361147f565b60006020828403121561157657600080fd5b5035919050565b6000806000806000806000610180888a03121561159957600080fd5b6115a2886112de565b96506020880135955060408801359450606088013593506115c5608089016113d8565b92506115d360a089016112de565b91506115e28960c08a0161147f565b905092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600067ffffffffffffffff808316818516808303821115611642576116426115f0565b01949350505050565b6000845161165d818460208901611329565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611699816001850160208a01611329565b600192019182015283516116b4816002840160208801611329565b0160020195945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036116f2576116f26115f0565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611737576117376116f9565b500490565b60008282101561174e5761174e6115f0565b500390565b600082611762576117626116f9565b500690565b6000821982111561177a5761177a6115f0565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818516808303821115611642576116426115f0565b600063ffffffff808416806117e4576117e46116f9565b92169190910492915050565b600063ffffffff80831681851681830481118215151615611813576118136115f0565b0294935050505056fea164736f6c634300080f000a496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069",
Bin: "0x60e06040523480156200001157600080fd5b50604051620022d2380380620022d2833981016040819052620000349162000859565b6001608052600360a052600060c052620000548787878787878762000061565b5050505050505062000a59565b600054610100900460ff1615808015620000825750600054600160ff909116105b80620000b257506200009f306200027060201b62000adf1760201c565b158015620000b2575060005460ff166001145b6200011b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156200013f576000805461ff0019166101001790555b620001496200027f565b6200015488620002e7565b606587905560668690556067859055606880546001600160401b0319166001600160401b038616179055620001a7837f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b620001b28262000366565b620001bc620006bb565b6001600160401b0316846001600160401b031610156200021f5760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640162000112565b801562000266576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b6001600160a01b03163b151590565b600054610100900460ff16620002db5760405162461bcd60e51b815260206004820152602b6024820152600080516020620022b283398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000112565b620002e5620006e8565b565b620002f16200074f565b6001600160a01b038116620003585760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000112565b6200036381620007ab565b50565b8060a001516001600160801b0316816060015163ffffffff161115620003f55760405162461bcd60e51b815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d617820626173650000000000000000000000606482015260840162000112565b6001816040015160ff1611620004665760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201526e65206c6172676572207468616e203160881b606482015260840162000112565b606854608082015182516001600160401b0390921691620004889190620009a8565b63ffffffff161115620004de5760405162461bcd60e51b815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640162000112565b6000816020015160ff16116200054f5760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201526e06965722063616e6e6f74206265203608c1b606482015260840162000112565b8051602082015163ffffffff82169160ff9091169062000571908290620009d3565b6200057d919062000a05565b63ffffffff1614620005f85760405162461bcd60e51b815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d6974000000000000000000606482015260840162000112565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff96871664ffffffffff199095169490941764010000000060ff948516021764ffffffffff60281b191665010000000000939092169290920263ffffffff60301b19161766010000000000009185169190910217600160501b600160f01b0319166a01000000000000000000009390941692909202600160701b600160f01b03191692909217600160701b6001600160801b0390921691909102179055565b606954600090620006e39063ffffffff6a010000000000000000000082048116911662000a34565b905090565b600054610100900460ff16620007445760405162461bcd60e51b815260206004820152602b6024820152600080516020620022b283398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000112565b620002e533620007ab565b6033546001600160a01b03163314620002e55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000112565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200081557600080fd5b919050565b805163ffffffff811681146200081557600080fd5b805160ff811681146200081557600080fd5b80516001600160801b03811681146200081557600080fd5b60008060008060008060008789036101808112156200087757600080fd5b6200088289620007fd565b60208a015160408b015160608c015160808d0151939b50919950975095506001600160401b038082168214620008b757600080fd5b819550620008c860a08c01620007fd565b945060c060bf1984011215620008dd57600080fd5b604051925060c08301915082821081831117156200090b57634e487b7160e01b600052604160045260246000fd5b506040526200091d60c08a016200081a565b81526200092d60e08a016200082f565b6020820152620009416101008a016200082f565b6040820152620009556101208a016200081a565b6060820152620009696101408a016200081a565b60808201526200097d6101608a0162000841565b60a08201528091505092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b600063ffffffff808316818516808303821115620009ca57620009ca62000992565b01949350505050565b600063ffffffff80841680620009f957634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600063ffffffff8083168185168183048111821515161562000a2b5762000a2b62000992565b02949350505050565b60006001600160401b03828116848216808303821115620009ca57620009ca62000992565b60805160a05160c05161182962000a89600039600061056e015260006105450152600061051c01526118296000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c8063b40a817c116100cd578063f2fde38b11610081578063f68016b711610066578063f68016b7146103f7578063f975e9251461040b578063ffa1ad741461041e57600080fd5b8063f2fde38b146103db578063f45e65d8146103ee57600080fd5b8063c9b26f61116100b2578063c9b26f611461028b578063cc731b021461029e578063e81b2c6d146103d257600080fd5b8063b40a817c14610265578063c71973f61461027857600080fd5b80634f16540b11610124578063715018a611610109578063715018a61461022c5780638da5cb5b14610234578063935f029e1461025257600080fd5b80634f16540b146101f057806354fd4d501461021757600080fd5b80630c18c1621461015657806318d13918146101725780631fd19ee1146101875780634add321d146101cf575b600080fd5b61015f60655481565b6040519081526020015b60405180910390f35b610185610180366004611307565b610426565b005b7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08545b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d76104ea565b60405167ffffffffffffffff9091168152602001610169565b61015f7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b61021f610515565b60405161016991906113a3565b6101856105b8565b60335473ffffffffffffffffffffffffffffffffffffffff166101aa565b6101856102603660046113b6565b6105cc565b6101856102733660046113f0565b610665565b610185610286366004611548565b610750565b610185610299366004611564565b610764565b6103626040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b6040516101699190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b61015f60675481565b6101856103e9366004611307565b610794565b61015f60665481565b6068546101d79067ffffffffffffffff1681565b61018561041936600461157d565b610848565b61015f600081565b61042e610afb565b610456817f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516104de91906113a3565b60405180910390a35050565b6069546000906105109063ffffffff6a010000000000000000000082048116911661161f565b905090565b60606105407f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105697f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105927f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6040516020016105a49392919061164b565b604051602081830303815290604052905090565b6105c0610afb565b6105ca6000610cb9565b565b6105d4610afb565b606582905560668190556040805160208101849052908101829052600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050600160007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be8360405161065891906113a3565b60405180910390a3505050565b61066d610afb565b6106756104ea565b67ffffffffffffffff168167ffffffffffffffff1610156106f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064015b60405180910390fd5b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831690811790915560408051602080820193909352815180820390930183528101905260026104ad565b610758610afb565b61076181610d30565b50565b61076c610afb565b60678190556040805160208082018490528251808303909101815290820190915260006104ad565b61079c610afb565b73ffffffffffffffffffffffffffffffffffffffff811661083f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106ee565b61076181610cb9565b600054610100900460ff16158080156108685750600054600160ff909116105b806108825750303b158015610882575060005460ff166001145b61090e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016106ee565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561096c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6109746111a4565b61097d88610794565b606587905560668690556067859055606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff86161790557f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c088390556109ed82610d30565b6109f56104ea565b67ffffffffffffffff168467ffffffffffffffff161015610a72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b8015610ad557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60335473ffffffffffffffffffffffffffffffffffffffff1633146105ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ee565b606081600003610bbf57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115610be95780610bd3816116c1565b9150610be29050600a83611728565b9150610bc3565b60008167ffffffffffffffff811115610c0457610c0461140b565b6040519080825280601f01601f191660200182016040528015610c2e576020820181803683370190505b5090505b8415610cb157610c4360018361173c565b9150610c50600a86611753565b610c5b906030611767565b60f81b818381518110610c7057610c7061177f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610caa600a86611728565b9450610c32565b949350505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115610de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d61782062617365000000000000000000000060648201526084016106ee565b6001816040015160ff1611610e77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e2031000000000000000000000000000000000060648201526084016106ee565b6068546080820151825167ffffffffffffffff90921691610e9891906117ae565b63ffffffff161115610f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b6000816020015160ff1611610f9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f742062652030000000000000000000000000000000000060648201526084016106ee565b8051602082015163ffffffff82169160ff90911690610fbd9082906117cd565b610fc791906117f0565b63ffffffff161461105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d697400000000000000000060648201526084016106ee565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b600054610100900460ff1661123b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca600054610100900460ff166112d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca33610cb9565b803573ffffffffffffffffffffffffffffffffffffffff8116811461130257600080fd5b919050565b60006020828403121561131957600080fd5b611322826112de565b9392505050565b60005b8381101561134457818101518382015260200161132c565b83811115611353576000848401525b50505050565b60008151808452611371816020860160208601611329565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113226020830184611359565b600080604083850312156113c957600080fd5b50508035926020909101359150565b803567ffffffffffffffff8116811461130257600080fd5b60006020828403121561140257600080fd5b611322826113d8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b803563ffffffff8116811461130257600080fd5b803560ff8116811461130257600080fd5b80356fffffffffffffffffffffffffffffffff8116811461130257600080fd5b600060c0828403121561149157600080fd5b60405160c0810181811067ffffffffffffffff821117156114db577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040529050806114ea8361143a565b81526114f86020840161144e565b60208201526115096040840161144e565b604082015261151a6060840161143a565b606082015261152b6080840161143a565b608082015261153c60a0840161145f565b60a08201525092915050565b600060c0828403121561155a57600080fd5b611322838361147f565b60006020828403121561157657600080fd5b5035919050565b6000806000806000806000610180888a03121561159957600080fd5b6115a2886112de565b96506020880135955060408801359450606088013593506115c5608089016113d8565b92506115d360a089016112de565b91506115e28960c08a0161147f565b905092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600067ffffffffffffffff808316818516808303821115611642576116426115f0565b01949350505050565b6000845161165d818460208901611329565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611699816001850160208a01611329565b600192019182015283516116b4816002840160208801611329565b0160020195945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036116f2576116f26115f0565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611737576117376116f9565b500490565b60008282101561174e5761174e6115f0565b500390565b600082611762576117626116f9565b500690565b6000821982111561177a5761177a6115f0565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818516808303821115611642576116426115f0565b600063ffffffff808416806117e4576117e46116f9565b92169190910492915050565b600063ffffffff80831681851681830481118215151615611813576118136115f0565b0294935050505056fea164736f6c634300080f000a496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069",
}
// SystemConfigABI is the input ABI used to generate the binding from.
......
......@@ -13,7 +13,7 @@ const SystemConfigStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\
var SystemConfigStorageLayout = new(solc.StorageLayout)
var SystemConfigDeployedBin = "0x608060405234801561001057600080fd5b50600436106101515760003560e01c8063b40a817c116100cd578063f2fde38b11610081578063f68016b711610066578063f68016b7146103f7578063f975e9251461040b578063ffa1ad741461041e57600080fd5b8063f2fde38b146103db578063f45e65d8146103ee57600080fd5b8063c9b26f61116100b2578063c9b26f611461028b578063cc731b021461029e578063e81b2c6d146103d257600080fd5b8063b40a817c14610265578063c71973f61461027857600080fd5b80634f16540b11610124578063715018a611610109578063715018a61461022c5780638da5cb5b14610234578063935f029e1461025257600080fd5b80634f16540b146101f057806354fd4d501461021757600080fd5b80630c18c1621461015657806318d13918146101725780631fd19ee1146101875780634add321d146101cf575b600080fd5b61015f60655481565b6040519081526020015b60405180910390f35b610185610180366004611307565b610426565b005b7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08545b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d76104ea565b60405167ffffffffffffffff9091168152602001610169565b61015f7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b61021f610515565b60405161016991906113a3565b6101856105b8565b60335473ffffffffffffffffffffffffffffffffffffffff166101aa565b6101856102603660046113b6565b6105cc565b6101856102733660046113f0565b610665565b610185610286366004611548565b610750565b610185610299366004611564565b610764565b6103626040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b6040516101699190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b61015f60675481565b6101856103e9366004611307565b610794565b61015f60665481565b6068546101d79067ffffffffffffffff1681565b61018561041936600461157d565b610848565b61015f600081565b61042e610afb565b610456817f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516104de91906113a3565b60405180910390a35050565b6069546000906105109063ffffffff6a010000000000000000000082048116911661161f565b905090565b60606105407f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105697f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105927f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6040516020016105a49392919061164b565b604051602081830303815290604052905090565b6105c0610afb565b6105ca6000610cb9565b565b6105d4610afb565b606582905560668190556040805160208101849052908101829052600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050600160007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be8360405161065891906113a3565b60405180910390a3505050565b61066d610afb565b6106756104ea565b67ffffffffffffffff168167ffffffffffffffff1610156106f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064015b60405180910390fd5b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831690811790915560408051602080820193909352815180820390930183528101905260026104ad565b610758610afb565b61076181610d30565b50565b61076c610afb565b60678190556040805160208082018490528251808303909101815290820190915260006104ad565b61079c610afb565b73ffffffffffffffffffffffffffffffffffffffff811661083f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106ee565b61076181610cb9565b600054610100900460ff16158080156108685750600054600160ff909116105b806108825750303b158015610882575060005460ff166001145b61090e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016106ee565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561096c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6109746111a4565b61097d88610794565b606587905560668690556067859055606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff86161790557f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c088390556109ed82610d30565b6109f56104ea565b67ffffffffffffffff168467ffffffffffffffff161015610a72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b8015610ad557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60335473ffffffffffffffffffffffffffffffffffffffff1633146105ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ee565b606081600003610bbf57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115610be95780610bd3816116c1565b9150610be29050600a83611728565b9150610bc3565b60008167ffffffffffffffff811115610c0457610c0461140b565b6040519080825280601f01601f191660200182016040528015610c2e576020820181803683370190505b5090505b8415610cb157610c4360018361173c565b9150610c50600a86611753565b610c5b906030611767565b60f81b818381518110610c7057610c7061177f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610caa600a86611728565b9450610c32565b949350505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115610de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d61782062617365000000000000000000000060648201526084016106ee565b6000816040015160ff1611610e77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f722063616e6e6f7460448201527f206265203000000000000000000000000000000000000000000000000000000060648201526084016106ee565b6068546080820151825167ffffffffffffffff90921691610e9891906117ae565b63ffffffff161115610f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b6000816020015160ff1611610f9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f742062652030000000000000000000000000000000000060648201526084016106ee565b8051602082015163ffffffff82169160ff90911690610fbd9082906117cd565b610fc791906117f0565b63ffffffff161461105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d697400000000000000000060648201526084016106ee565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b600054610100900460ff1661123b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca600054610100900460ff166112d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca33610cb9565b803573ffffffffffffffffffffffffffffffffffffffff8116811461130257600080fd5b919050565b60006020828403121561131957600080fd5b611322826112de565b9392505050565b60005b8381101561134457818101518382015260200161132c565b83811115611353576000848401525b50505050565b60008151808452611371816020860160208601611329565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113226020830184611359565b600080604083850312156113c957600080fd5b50508035926020909101359150565b803567ffffffffffffffff8116811461130257600080fd5b60006020828403121561140257600080fd5b611322826113d8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b803563ffffffff8116811461130257600080fd5b803560ff8116811461130257600080fd5b80356fffffffffffffffffffffffffffffffff8116811461130257600080fd5b600060c0828403121561149157600080fd5b60405160c0810181811067ffffffffffffffff821117156114db577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040529050806114ea8361143a565b81526114f86020840161144e565b60208201526115096040840161144e565b604082015261151a6060840161143a565b606082015261152b6080840161143a565b608082015261153c60a0840161145f565b60a08201525092915050565b600060c0828403121561155a57600080fd5b611322838361147f565b60006020828403121561157657600080fd5b5035919050565b6000806000806000806000610180888a03121561159957600080fd5b6115a2886112de565b96506020880135955060408801359450606088013593506115c5608089016113d8565b92506115d360a089016112de565b91506115e28960c08a0161147f565b905092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600067ffffffffffffffff808316818516808303821115611642576116426115f0565b01949350505050565b6000845161165d818460208901611329565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611699816001850160208a01611329565b600192019182015283516116b4816002840160208801611329565b0160020195945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036116f2576116f26115f0565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611737576117376116f9565b500490565b60008282101561174e5761174e6115f0565b500390565b600082611762576117626116f9565b500690565b6000821982111561177a5761177a6115f0565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818516808303821115611642576116426115f0565b600063ffffffff808416806117e4576117e46116f9565b92169190910492915050565b600063ffffffff80831681851681830481118215151615611813576118136115f0565b0294935050505056fea164736f6c634300080f000a"
var SystemConfigDeployedBin = "0x608060405234801561001057600080fd5b50600436106101515760003560e01c8063b40a817c116100cd578063f2fde38b11610081578063f68016b711610066578063f68016b7146103f7578063f975e9251461040b578063ffa1ad741461041e57600080fd5b8063f2fde38b146103db578063f45e65d8146103ee57600080fd5b8063c9b26f61116100b2578063c9b26f611461028b578063cc731b021461029e578063e81b2c6d146103d257600080fd5b8063b40a817c14610265578063c71973f61461027857600080fd5b80634f16540b11610124578063715018a611610109578063715018a61461022c5780638da5cb5b14610234578063935f029e1461025257600080fd5b80634f16540b146101f057806354fd4d501461021757600080fd5b80630c18c1621461015657806318d13918146101725780631fd19ee1146101875780634add321d146101cf575b600080fd5b61015f60655481565b6040519081526020015b60405180910390f35b610185610180366004611307565b610426565b005b7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08545b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d76104ea565b60405167ffffffffffffffff9091168152602001610169565b61015f7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b61021f610515565b60405161016991906113a3565b6101856105b8565b60335473ffffffffffffffffffffffffffffffffffffffff166101aa565b6101856102603660046113b6565b6105cc565b6101856102733660046113f0565b610665565b610185610286366004611548565b610750565b610185610299366004611564565b610764565b6103626040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b6040516101699190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b61015f60675481565b6101856103e9366004611307565b610794565b61015f60665481565b6068546101d79067ffffffffffffffff1681565b61018561041936600461157d565b610848565b61015f600081565b61042e610afb565b610456817f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0855565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516104de91906113a3565b60405180910390a35050565b6069546000906105109063ffffffff6a010000000000000000000082048116911661161f565b905090565b60606105407f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105697f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6105927f0000000000000000000000000000000000000000000000000000000000000000610b7c565b6040516020016105a49392919061164b565b604051602081830303815290604052905090565b6105c0610afb565b6105ca6000610cb9565b565b6105d4610afb565b606582905560668190556040805160208101849052908101829052600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529050600160007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be8360405161065891906113a3565b60405180910390a3505050565b61066d610afb565b6106756104ea565b67ffffffffffffffff168167ffffffffffffffff1610156106f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064015b60405180910390fd5b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831690811790915560408051602080820193909352815180820390930183528101905260026104ad565b610758610afb565b61076181610d30565b50565b61076c610afb565b60678190556040805160208082018490528251808303909101815290820190915260006104ad565b61079c610afb565b73ffffffffffffffffffffffffffffffffffffffff811661083f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106ee565b61076181610cb9565b600054610100900460ff16158080156108685750600054600160ff909116105b806108825750303b158015610882575060005460ff166001145b61090e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016106ee565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561096c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6109746111a4565b61097d88610794565b606587905560668690556067859055606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff86161790557f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c088390556109ed82610d30565b6109f56104ea565b67ffffffffffffffff168467ffffffffffffffff161015610a72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b8015610ad557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60335473ffffffffffffffffffffffffffffffffffffffff1633146105ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ee565b606081600003610bbf57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115610be95780610bd3816116c1565b9150610be29050600a83611728565b9150610bc3565b60008167ffffffffffffffff811115610c0457610c0461140b565b6040519080825280601f01601f191660200182016040528015610c2e576020820181803683370190505b5090505b8415610cb157610c4360018361173c565b9150610c50600a86611753565b610c5b906030611767565b60f81b818381518110610c7057610c7061177f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610caa600a86611728565b9450610c32565b949350505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115610de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d61782062617365000000000000000000000060648201526084016106ee565b6001816040015160ff1611610e77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e2031000000000000000000000000000000000060648201526084016106ee565b6068546080820151825167ffffffffffffffff90921691610e9891906117ae565b63ffffffff161115610f06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f770060448201526064016106ee565b6000816020015160ff1611610f9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f742062652030000000000000000000000000000000000060648201526084016106ee565b8051602082015163ffffffff82169160ff90911690610fbd9082906117cd565b610fc791906117f0565b63ffffffff161461105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d697400000000000000000060648201526084016106ee565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b600054610100900460ff1661123b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca600054610100900460ff166112d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106ee565b6105ca33610cb9565b803573ffffffffffffffffffffffffffffffffffffffff8116811461130257600080fd5b919050565b60006020828403121561131957600080fd5b611322826112de565b9392505050565b60005b8381101561134457818101518382015260200161132c565b83811115611353576000848401525b50505050565b60008151808452611371816020860160208601611329565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113226020830184611359565b600080604083850312156113c957600080fd5b50508035926020909101359150565b803567ffffffffffffffff8116811461130257600080fd5b60006020828403121561140257600080fd5b611322826113d8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b803563ffffffff8116811461130257600080fd5b803560ff8116811461130257600080fd5b80356fffffffffffffffffffffffffffffffff8116811461130257600080fd5b600060c0828403121561149157600080fd5b60405160c0810181811067ffffffffffffffff821117156114db577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040529050806114ea8361143a565b81526114f86020840161144e565b60208201526115096040840161144e565b604082015261151a6060840161143a565b606082015261152b6080840161143a565b608082015261153c60a0840161145f565b60a08201525092915050565b600060c0828403121561155a57600080fd5b611322838361147f565b60006020828403121561157657600080fd5b5035919050565b6000806000806000806000610180888a03121561159957600080fd5b6115a2886112de565b96506020880135955060408801359450606088013593506115c5608089016113d8565b92506115d360a089016112de565b91506115e28960c08a0161147f565b905092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600067ffffffffffffffff808316818516808303821115611642576116426115f0565b01949350505050565b6000845161165d818460208901611329565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611699816001850160208a01611329565b600192019182015283516116b4816002840160208801611329565b0160020195945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036116f2576116f26115f0565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611737576117376116f9565b500490565b60008282101561174e5761174e6115f0565b500390565b600082611762576117626116f9565b500690565b6000821982111561177a5761177a6115f0565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818516808303821115611642576116426115f0565b600063ffffffff808416806117e4576117e46116f9565b92169190910492915050565b600063ffffffff80831681851681830481118215151615611813576118136115f0565b0294935050505056fea164736f6c634300080f000a"
func init() {
if err := json.Unmarshal([]byte(SystemConfigStorageLayoutJSON), SystemConfigStorageLayout); err != nil {
......
......@@ -41,6 +41,40 @@ func NewSentMessageFromJSON(path string) ([]*SentMessage, error) {
return j, nil
}
// decodeWitnessCalldata abi decodes the calldata encoded in the input witness
// file. It errors if the 4 byte selector is not specifically for `passMessageToL1`.
// It also errors if the abi decoding fails.
func decodeWitnessCalldata(msg []byte) ([]byte, error) {
abi, err := bindings.LegacyMessagePasserMetaData.GetAbi()
if err != nil {
panic("should always be able to get message passer abi")
}
if size := len(msg); size < 4 {
return nil, fmt.Errorf("message too short: %d", size)
}
method, err := abi.MethodById(msg[:4])
if err != nil {
return nil, err
}
if method.Sig != "passMessageToL1(bytes)" {
return nil, fmt.Errorf("unknown method: %s", method.Name)
}
out, err := method.Inputs.Unpack(msg[4:])
if err != nil {
return nil, err
}
cast, ok := out[0].([]byte)
if !ok {
panic("should always be able to cast type []byte")
}
return cast, nil
}
// ReadWitnessData will read messages and addresses from a raw l2geth state
// dump file.
func ReadWitnessData(path string) ([]*SentMessage, OVMETHAddresses, error) {
......@@ -72,30 +106,18 @@ func ReadWitnessData(path string) ([]*SentMessage, OVMETHAddresses, error) {
msg = "0x" + msg
}
abi, err := bindings.LegacyMessagePasserMetaData.GetAbi()
if err != nil {
return nil, nil, fmt.Errorf("failed to get abi: %w", err)
}
msgB := hexutil.MustDecode(msg)
method, err := abi.MethodById(msgB[:4])
if err != nil {
return nil, nil, fmt.Errorf("failed to get method: %w", err)
}
out, err := method.Inputs.Unpack(msgB[4:])
// Skip any errors
calldata, err := decodeWitnessCalldata(msgB)
if err != nil {
return nil, nil, fmt.Errorf("failed to unpack: %w", err)
}
cast, ok := out[0].([]byte)
if !ok {
return nil, nil, fmt.Errorf("failed to cast to bytes")
log.Warn("cannot decode witness calldata", "err", err)
continue
}
witnesses = append(witnesses, &SentMessage{
Who: common.HexToAddress(splits[1]),
Msg: cast,
Msg: calldata,
})
case "ETH":
addresses[common.HexToAddress(splits[1])] = true
......
package crossdomain
import (
"context"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
......@@ -41,3 +51,163 @@ func TestRead(t *testing.T) {
common.HexToAddress("0x6340d44c5174588B312F545eEC4a42f8a514eF50"): true,
}, addresses)
}
// TestDecodeWitnessCallData tests that the witness data is parsed correctly
// from an input bytes slice.
func TestDecodeWitnessCallData(t *testing.T) {
tests := []struct {
name string
err bool
msg []byte
want []byte
}{
{
name: "too-small",
err: true,
msg: common.FromHex("0x0000"),
},
{
name: "unknown-selector",
err: true,
msg: common.FromHex("0x00000000"),
},
{
name: "wrong-selector",
err: true,
// 0x54fd4d50 is the selector for `version()`
msg: common.FromHex("0x54fd4d50"),
},
{
name: "invalid-calldata-only-selector",
err: true,
// 0xcafa81dc is the selector for `passMessageToL1(bytes)`
msg: common.FromHex("0xcafa81dc"),
},
{
name: "invalid-calldata-invalid-bytes",
err: true,
// 0xcafa81dc is the selector for passMessageToL1(bytes)
msg: common.FromHex("0xcafa81dc0000"),
},
{
name: "valid-calldata",
msg: common.FromHex(
"0xcafa81dc" +
"0000000000000000000000000000000000000000000000000000000000000020" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"1234000000000000000000000000000000000000000000000000000000000000",
),
want: common.FromHex("0x1234"),
},
}
for _, tt := range tests {
test := tt
t.Run(test.name, func(t *testing.T) {
if test.err {
_, err := decodeWitnessCalldata(test.msg)
require.Error(t, err)
} else {
want, err := decodeWitnessCalldata(test.msg)
require.NoError(t, err)
require.Equal(t, test.want, want)
}
})
}
}
// TestMessagePasserSafety ensures that the LegacyMessagePasser contract reverts when it is called
// with incorrect calldata. The function signature is correct but the calldata is not abi encoded
// correctly. It is expected the solidity reverts when it cannot abi decode the calldata correctly.
// Only a call to `passMessageToL1` with abi encoded `bytes` will result in the `successfulMessages`
// mapping being updated.
func TestMessagePasserSafety(t *testing.T) {
testKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
opts, err := bind.NewKeyedTransactorWithChainID(testKey, big.NewInt(1337))
require.NoError(t, err)
backend := backends.NewSimulatedBackend(
core.GenesisAlloc{testAddr: {Balance: big.NewInt(10000000000000000)}},
30_000_000,
)
defer backend.Close()
// deploy the LegacyMessagePasser contract
addr, tx, contract, err := bindings.DeployLegacyMessagePasser(opts, backend)
require.NoError(t, err)
backend.Commit()
_, err = bind.WaitMined(context.Background(), backend, tx)
require.NoError(t, err)
// ensure that it deployed
code, err := backend.CodeAt(context.Background(), addr, nil)
require.NoError(t, err)
require.True(t, len(code) > 0)
// dummy message
msg := []byte{0x00, 0x01, 0x02, 0x03}
// call `passMessageToL1`
msgTx, err := contract.PassMessageToL1(opts, msg)
require.NoError(t, err)
// ensure that the receipt is successful
backend.Commit()
msgReceipt, err := bind.WaitMined(context.Background(), backend, msgTx)
require.NoError(t, err)
require.Equal(t, msgReceipt.Status, types.ReceiptStatusSuccessful)
// check for the data in the `successfulMessages` mapping
data := make([]byte, len(msg)+len(testAddr))
copy(data[:], msg)
copy(data[len(msg):], testAddr.Bytes())
digest := crypto.Keccak256Hash(data)
contains, err := contract.SentMessages(&bind.CallOpts{}, digest)
require.NoError(t, err)
require.True(t, contains)
// build a transaction with improperly formatted calldata
nonce, err := backend.NonceAt(context.Background(), testAddr, nil)
require.NoError(t, err)
// append msg without abi encoding it
selector := crypto.Keccak256([]byte("passMessageToL1(bytes)"))[0:4]
require.Equal(t, selector, hexutil.MustDecode("0xcafa81dc"))
calldata := append(selector, msg...)
faultyTransaction, err := opts.Signer(testAddr, types.NewTx(&types.DynamicFeeTx{
ChainID: big.NewInt(1337),
Nonce: nonce,
GasTipCap: msgTx.GasTipCap(),
GasFeeCap: msgTx.GasFeeCap(),
Gas: msgTx.Gas() * 2,
To: msgTx.To(),
Data: calldata,
}))
require.NoError(t, err)
err = backend.SendTransaction(context.Background(), faultyTransaction)
require.NoError(t, err)
// the transaction should revert
backend.Commit()
badReceipt, err := bind.WaitMined(context.Background(), backend, faultyTransaction)
require.NoError(t, err)
require.Equal(t, badReceipt.Status, types.ReceiptStatusFailed)
// test the transaction calldata against the abi unpacking
abi, err := bindings.LegacyMessagePasserMetaData.GetAbi()
require.NoError(t, err)
method, err := abi.MethodById(selector)
require.NoError(t, err)
require.Equal(t, method.Name, "passMessageToL1")
// the faulty transaction has the correct 4 byte selector but doesn't
// have abi encoded bytes following it
require.Equal(t, faultyTransaction.Data()[:4], selector)
_, err = method.Inputs.Unpack(faultyTransaction.Data()[4:])
require.Error(t, err)
// the original transaction has the correct 4 byte selector and abi encoded bytes
_, err = method.Inputs.Unpack(msgTx.Data()[4:])
require.NoError(t, err)
}
......@@ -100,7 +100,7 @@ func NewOpGeth(t *testing.T, ctx context.Context, cfg *SystemConfig) (*OpGeth, e
SystemConfig: rollupGenesis.SystemConfig,
L1ChainConfig: l1Genesis.Config,
L2ChainConfig: l2Genesis.Config,
L1Head: l1Block,
L1Head: eth.BlockToInfo(l1Block),
L2Head: genesisPayload,
}, nil
}
......
......@@ -5,10 +5,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
var _ BlockInfo = (&types.Block{})
type BlockInfo interface {
Hash() common.Hash
ParentHash() common.Hash
......@@ -21,6 +20,10 @@ type BlockInfo interface {
BaseFee() *big.Int
ReceiptHash() common.Hash
GasUsed() uint64
// HeaderRLP returns the RLP of the block header as per consensus rules
// Returns an error if the header RLP could not be written
HeaderRLP() ([]byte, error)
}
func InfoToL1BlockRef(info BlockInfo) L1BlockRef {
......@@ -44,6 +47,19 @@ func ToBlockID(b NumberAndHash) BlockID {
}
}
// blockInfo is a conversion type of types.Block turning it into a BlockInfo
type blockInfo struct{ *types.Block }
func (b blockInfo) HeaderRLP() ([]byte, error) {
return rlp.EncodeToBytes(b.Header())
}
func BlockToInfo(b *types.Block) BlockInfo {
return blockInfo{b}
}
var _ BlockInfo = (*blockInfo)(nil)
// headerBlockInfo is a conversion type of types.Header turning it into a
// BlockInfo.
type headerBlockInfo struct{ *types.Header }
......@@ -84,6 +100,10 @@ func (h headerBlockInfo) GasUsed() uint64 {
return h.Header.GasUsed
}
func (h headerBlockInfo) HeaderRLP() ([]byte, error) {
return rlp.EncodeToBytes(h.Header)
}
// HeaderBlockInfo returns h as a BlockInfo implementation.
func HeaderBlockInfo(h *types.Header) BlockInfo {
return headerBlockInfo{h}
......
package eth
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
// EncodeReceipts encodes a list of receipts into raw receipts. Some non-consensus meta-data may be lost.
func EncodeReceipts(elems []*types.Receipt) ([]hexutil.Bytes, error) {
out := make([]hexutil.Bytes, len(elems))
for i, el := range elems {
dat, err := el.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("failed to marshal receipt %d: %w", i, err)
}
out[i] = dat
}
return out, nil
}
// DecodeRawReceipts decodes receipts and adds additional blocks metadata.
// The contract-deployment addresses are not set however (high cost, depends on nonce values, unused by op-node).
func DecodeRawReceipts(block BlockID, rawReceipts []hexutil.Bytes, txHashes []common.Hash) ([]*types.Receipt, error) {
result := make([]*types.Receipt, len(rawReceipts))
totalIndex := uint(0)
prevCumulativeGasUsed := uint64(0)
for i, r := range rawReceipts {
var x types.Receipt
if err := x.UnmarshalBinary(r); err != nil {
return nil, fmt.Errorf("failed to decode receipt %d: %w", i, err)
}
x.TxHash = txHashes[i]
x.BlockHash = block.Hash
x.BlockNumber = new(big.Int).SetUint64(block.Number)
x.TransactionIndex = uint(i)
x.GasUsed = x.CumulativeGasUsed - prevCumulativeGasUsed
// contract address meta-data is not computed.
prevCumulativeGasUsed = x.CumulativeGasUsed
for _, l := range x.Logs {
l.BlockNumber = block.Number
l.TxHash = x.TxHash
l.TxIndex = uint(i)
l.BlockHash = block.Hash
l.Index = totalIndex
totalIndex += 1
}
result[i] = &x
}
return result, nil
}
package eth
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
// EncodeTransactions encodes a list of transactions into opaque transactions.
func EncodeTransactions(elems []*types.Transaction) ([]hexutil.Bytes, error) {
out := make([]hexutil.Bytes, len(elems))
for i, el := range elems {
dat, err := el.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("failed to marshal tx %d: %w", i, err)
}
out[i] = dat
}
return out, nil
}
// DecodeTransactions decodes a list of opaque transactions into transactions.
func DecodeTransactions(data []hexutil.Bytes) ([]*types.Transaction, error) {
dest := make([]*types.Transaction, len(data))
for i := range dest {
var x types.Transaction
if err := x.UnmarshalBinary(data[i]); err != nil {
return nil, fmt.Errorf("failed to unmarshal tx %d: %w", i, err)
}
dest[i] = &x
}
return dest, nil
}
// TransactionsToHashes computes the transaction-hash for every transaction in the input.
func TransactionsToHashes(elems []*types.Transaction) []common.Hash {
out := make([]common.Hash, len(elems))
for i, el := range elems {
out[i] = el.Hash()
}
return out
}
......@@ -54,7 +54,8 @@ type GossipSetupConfigurables interface {
PeerScoringParams() *pubsub.PeerScoreParams
TopicScoringParams() *pubsub.TopicScoreParams
BanPeers() bool
ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option
// ConfigureGossip creates configuration options to apply to the GossipSub setup
ConfigureGossip(rollupCfg *rollup.Config) []pubsub.Option
PeerBandScorer() *BandScoreThresholds
}
......@@ -124,7 +125,10 @@ func BuildMsgIdFn(cfg *rollup.Config) pubsub.MsgIdFunction {
}
}
func (p *Config) ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option {
func (p *Config) ConfigureGossip(rollupCfg *rollup.Config) []pubsub.Option {
params := BuildGlobalGossipParams(rollupCfg)
// override with CLI changes
params.D = p.MeshD
params.Dlo = p.MeshDLo
params.Dhi = p.MeshDHi
......@@ -132,6 +136,7 @@ func (p *Config) ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option
// in the future we may add more advanced options like scoring and PX / direct-mesh / episub
return []pubsub.Option{
pubsub.WithGossipSubParams(params),
pubsub.WithFloodPublish(p.FloodPublish),
}
}
......@@ -157,7 +162,6 @@ func NewGossipSub(p2pCtx context.Context, h host.Host, g ConnectionGater, cfg *r
if err != nil {
return nil, err
}
params := BuildGlobalGossipParams(cfg)
gossipOpts := []pubsub.Option{
pubsub.WithMaxMessageSize(maxGossipSize),
pubsub.WithMessageIdFn(BuildMsgIdFn(cfg)),
......@@ -170,11 +174,10 @@ func NewGossipSub(p2pCtx context.Context, h host.Host, g ConnectionGater, cfg *r
pubsub.WithSeenMessagesTTL(seenMessagesTTL),
pubsub.WithPeerExchange(false),
pubsub.WithBlacklist(denyList),
pubsub.WithGossipSubParams(params),
pubsub.WithEventTracer(&gossipTracer{m: m}),
}
gossipOpts = append(gossipOpts, ConfigurePeerScoring(h, g, gossipConf, m, log)...)
gossipOpts = append(gossipOpts, gossipConf.ConfigureGossip(&params)...)
gossipOpts = append(gossipOpts, gossipConf.ConfigureGossip(cfg)...)
return pubsub.NewGossipSub(p2pCtx, h, gossipOpts...)
}
......
......@@ -62,8 +62,10 @@ func (p *Prepared) Discovery(log log.Logger, rollupCfg *rollup.Config, tcpPort u
return p.LocalNode, p.UDPv5, nil
}
func (p *Prepared) ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option {
return nil
func (p *Prepared) ConfigureGossip(rollupCfg *rollup.Config) []pubsub.Option {
return []pubsub.Option{
pubsub.WithGossipSubParams(BuildGlobalGossipParams(rollupCfg)),
}
}
func (p *Prepared) PeerScoringParams() *pubsub.PeerScoreParams {
......
......@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/binary"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
......@@ -45,71 +46,135 @@ type L1BlockInfo struct {
L1FeeScalar eth.Bytes32
}
//+---------+--------------------------+
//| Bytes | Field |
//+---------+--------------------------+
//| 4 | Function signature |
//| 24 | Padding for Number |
//| 8 | Number |
//| 24 | Padding for Time |
//| 8 | Time |
//| 32 | BaseFee |
//| 32 | BlockHash |
//| 24 | Padding for SequenceNumber|
//| 8 | SequenceNumber |
//| 12 | Padding for BatcherAddr |
//| 20 | BatcherAddr |
//| 32 | L1FeeOverhead |
//| 32 | L1FeeScalar |
//+---------+--------------------------+
func (info *L1BlockInfo) MarshalBinary() ([]byte, error) {
data := make([]byte, L1InfoLen)
offset := 0
copy(data[offset:4], L1InfoFuncBytes4)
offset += 4
binary.BigEndian.PutUint64(data[offset+24:offset+32], info.Number)
offset += 32
binary.BigEndian.PutUint64(data[offset+24:offset+32], info.Time)
offset += 32
writer := bytes.NewBuffer(make([]byte, 0, L1InfoLen))
writer.Write(L1InfoFuncBytes4)
if err := writeSolidityABIUint64(writer, info.Number); err != nil {
return nil, err
}
if err := writeSolidityABIUint64(writer, info.Time); err != nil {
return nil, err
}
// Ensure that the baseFee is not too large.
if info.BaseFee.BitLen() > 256 {
return nil, fmt.Errorf("base fee exceeds 256 bits: %d", info.BaseFee)
}
info.BaseFee.FillBytes(data[offset : offset+32])
offset += 32
copy(data[offset:offset+32], info.BlockHash.Bytes())
offset += 32
binary.BigEndian.PutUint64(data[offset+24:offset+32], info.SequenceNumber)
offset += 32
copy(data[offset+12:offset+32], info.BatcherAddr[:])
offset += 32
copy(data[offset:offset+32], info.L1FeeOverhead[:])
offset += 32
copy(data[offset:offset+32], info.L1FeeScalar[:])
return data, nil
var baseFeeBuf [32]byte
info.BaseFee.FillBytes(baseFeeBuf[:])
writer.Write(baseFeeBuf[:])
writer.Write(info.BlockHash.Bytes())
if err := writeSolidityABIUint64(writer, info.SequenceNumber); err != nil {
return nil, err
}
var addrPadding [12]byte
writer.Write(addrPadding[:])
writer.Write(info.BatcherAddr.Bytes())
writer.Write(info.L1FeeOverhead[:])
writer.Write(info.L1FeeScalar[:])
return writer.Bytes(), nil
}
func (info *L1BlockInfo) UnmarshalBinary(data []byte) error {
if len(data) != L1InfoLen {
return fmt.Errorf("data is unexpected length: %d", len(data))
}
reader := bytes.NewReader(data)
funcSignature := make([]byte, 4)
if _, err := io.ReadFull(reader, funcSignature); err != nil || !bytes.Equal(funcSignature, L1InfoFuncBytes4) {
return fmt.Errorf("data does not match L1 info function signature: 0x%x", funcSignature)
}
if blockNumber, err := readSolidityABIUint64(reader); err != nil {
return err
} else {
info.Number = blockNumber
}
if blockTime, err := readSolidityABIUint64(reader); err != nil {
return err
} else {
info.Time = blockTime
}
var baseFeeBytes [32]byte
if _, err := io.ReadFull(reader, baseFeeBytes[:]); err != nil {
return fmt.Errorf("expected BaseFee length to be 32 bytes, but got %x", baseFeeBytes)
}
info.BaseFee = new(big.Int).SetBytes(baseFeeBytes[:])
var blockHashBytes [32]byte
if _, err := io.ReadFull(reader, blockHashBytes[:]); err != nil {
return fmt.Errorf("expected BlockHash length to be 32 bytes, but got %x", blockHashBytes)
}
info.BlockHash.SetBytes(blockHashBytes[:])
if sequenceNumber, err := readSolidityABIUint64(reader); err != nil {
return err
} else {
info.SequenceNumber = sequenceNumber
}
var addrPadding [12]byte
if _, err := io.ReadFull(reader, addrPadding[:]); err != nil {
return fmt.Errorf("expected addrPadding length to be 12 bytes, but got %x", addrPadding)
}
if _, err := io.ReadFull(reader, info.BatcherAddr[:]); err != nil {
return fmt.Errorf("expected BatcherAddr length to be 20 bytes, but got %x", info.BatcherAddr)
}
if _, err := io.ReadFull(reader, info.L1FeeOverhead[:]); err != nil {
return fmt.Errorf("expected L1FeeOverhead length to be 32 bytes, but got %x", info.L1FeeOverhead)
}
if _, err := io.ReadFull(reader, info.L1FeeScalar[:]); err != nil {
return fmt.Errorf("expected L1FeeScalar length to be 32 bytes, but got %x", info.L1FeeScalar)
}
return nil
}
func writeSolidityABIUint64(w io.Writer, num uint64) error {
var padding [24]byte
offset := 4
if !bytes.Equal(data[0:offset], L1InfoFuncBytes4) {
return fmt.Errorf("data does not match L1 info function signature: 0x%x", data[offset:4])
}
info.Number = binary.BigEndian.Uint64(data[offset+24 : offset+32])
if !bytes.Equal(data[offset:offset+24], padding[:]) {
return fmt.Errorf("l1 info number exceeds uint64 bounds: %x", data[offset:offset+32])
}
offset += 32
info.Time = binary.BigEndian.Uint64(data[offset+24 : offset+32])
if !bytes.Equal(data[offset:offset+24], padding[:]) {
return fmt.Errorf("l1 info time exceeds uint64 bounds: %x", data[offset:offset+32])
}
offset += 32
info.BaseFee = new(big.Int).SetBytes(data[offset : offset+32])
offset += 32
info.BlockHash.SetBytes(data[offset : offset+32])
offset += 32
info.SequenceNumber = binary.BigEndian.Uint64(data[offset+24 : offset+32])
if !bytes.Equal(data[offset:offset+24], padding[:]) {
return fmt.Errorf("l1 info sequence number exceeds uint64 bounds: %x", data[offset:offset+32])
}
offset += 32
info.BatcherAddr.SetBytes(data[offset+12 : offset+32])
offset += 32
copy(info.L1FeeOverhead[:], data[offset:offset+32])
offset += 32
copy(info.L1FeeScalar[:], data[offset:offset+32])
if _, err := w.Write(padding[:]); err != nil {
return err
}
if err := binary.Write(w, binary.BigEndian, num); err != nil {
return err
}
return nil
}
func readSolidityABIUint64(r io.Reader) (uint64, error) {
var (
padding, readPadding [24]byte
num uint64
)
if _, err := io.ReadFull(r, readPadding[:]); err != nil || !bytes.Equal(readPadding[:], padding[:]) {
return 0, fmt.Errorf("L1BlockInfo number exceeds uint64 bounds: %x", readPadding[:])
}
if err := binary.Read(r, binary.BigEndian, &num); err != nil {
return 0, fmt.Errorf("L1BlockInfo expected number length to be 8 bytes")
}
return num, nil
}
// L1InfoDepositTxData is the inverse of L1InfoDeposit, to see where the L2 chain is derived from
func L1InfoDepositTxData(data []byte) (L1BlockInfo, error) {
var info L1BlockInfo
......
......@@ -15,7 +15,7 @@ import (
func RandomL2Block(rng *rand.Rand, txCount int) (*types.Block, []*types.Receipt) {
l1Block := types.NewBlock(testutils.RandomHeader(rng),
nil, nil, nil, trie.NewStackTrie(nil))
l1InfoTx, err := derive.L1InfoDeposit(0, l1Block, eth.SystemConfig{}, testutils.RandomBool(rng))
l1InfoTx, err := derive.L1InfoDeposit(0, eth.BlockToInfo(l1Block), eth.SystemConfig{}, testutils.RandomBool(rng))
if err != nil {
panic("L1InfoDeposit: " + err.Error())
}
......
......@@ -219,7 +219,7 @@ func (n numberID) CheckID(id eth.BlockID) error {
return nil
}
func (s *EthClient) headerCall(ctx context.Context, method string, id rpcBlockID) (*HeaderInfo, error) {
func (s *EthClient) headerCall(ctx context.Context, method string, id rpcBlockID) (eth.BlockInfo, error) {
var header *rpcHeader
err := s.client.CallContext(ctx, &header, method, id.Arg(), false) // headers are just blocks without txs
if err != nil {
......@@ -239,7 +239,7 @@ func (s *EthClient) headerCall(ctx context.Context, method string, id rpcBlockID
return info, nil
}
func (s *EthClient) blockCall(ctx context.Context, method string, id rpcBlockID) (*HeaderInfo, types.Transactions, error) {
func (s *EthClient) blockCall(ctx context.Context, method string, id rpcBlockID) (eth.BlockInfo, types.Transactions, error) {
var block *rpcBlock
err := s.client.CallContext(ctx, &block, method, id.Arg(), true)
if err != nil {
......@@ -292,7 +292,7 @@ func (s *EthClient) ChainID(ctx context.Context) (*big.Int, error) {
func (s *EthClient) InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) {
if header, ok := s.headersCache.Get(hash); ok {
return header.(*HeaderInfo), nil
return header.(eth.BlockInfo), nil
}
return s.headerCall(ctx, "eth_getBlockByHash", hashID(hash))
}
......@@ -310,7 +310,7 @@ func (s *EthClient) InfoByLabel(ctx context.Context, label eth.BlockLabel) (eth.
func (s *EthClient) InfoAndTxsByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, types.Transactions, error) {
if header, ok := s.headersCache.Get(hash); ok {
if txs, ok := s.transactionsCache.Get(hash); ok {
return header.(*HeaderInfo), txs.(types.Transactions), nil
return header.(eth.BlockInfo), txs.(types.Transactions), nil
}
}
return s.blockCall(ctx, "eth_getBlockByHash", hashID(hash))
......@@ -356,10 +356,7 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e
if v, ok := s.receiptsCache.Get(blockHash); ok {
job = v.(*receiptsFetchingJob)
} else {
txHashes := make([]common.Hash, len(txs))
for i := 0; i < len(txs); i++ {
txHashes[i] = txs[i].Hash()
}
txHashes := eth.TransactionsToHashes(txs)
job = NewReceiptsFetchingJob(s, s.client, s.maxBatchSize, eth.ToBlockID(info), info.ReceiptHash(), txHashes)
s.receiptsCache.Add(blockHash, job)
}
......
......@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
......@@ -420,29 +419,7 @@ func (job *receiptsFetchingJob) runAltMethod(ctx context.Context, m ReceiptsFetc
err = job.client.CallContext(ctx, &rawReceipts, "debug_getRawReceipts", job.block.Hash)
if err == nil {
if len(rawReceipts) == len(job.txHashes) {
result = make([]*types.Receipt, len(rawReceipts))
totalIndex := uint(0)
prevCumulativeGasUsed := uint64(0)
for i, r := range rawReceipts {
var x types.Receipt
_ = x.UnmarshalBinary(r) // safe to ignore, we verify receipts against the receipts hash later
x.TxHash = job.txHashes[i]
x.BlockHash = job.block.Hash
x.BlockNumber = new(big.Int).SetUint64(job.block.Number)
x.TransactionIndex = uint(i)
x.GasUsed = x.CumulativeGasUsed - prevCumulativeGasUsed
// contract address meta-data is not computed.
prevCumulativeGasUsed = x.CumulativeGasUsed
for _, l := range x.Logs {
l.BlockNumber = job.block.Number
l.TxHash = x.TxHash
l.TxIndex = uint(i)
l.BlockHash = job.block.Hash
l.Index = totalIndex
totalIndex += 1
}
result[i] = &x
}
result, err = eth.DecodeRawReceipts(job.block, rawReceipts, job.txHashes)
} else {
err = fmt.Errorf("got %d raw receipts, but expected %d", len(rawReceipts), len(job.txHashes))
}
......
......@@ -6,6 +6,7 @@ import (
"math/big"
"strings"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
"github.com/ethereum/go-ethereum/common"
......@@ -33,69 +34,57 @@ type CallContextFn func(ctx context.Context, result any, method string, args ...
//
// This way we minimize RPC calls, enable batching, and can choose to verify what the RPC gives us.
// HeaderInfo contains all the header-info required to implement the eth.BlockInfo interface,
// used in the rollup state-transition, with pre-computed block hash.
type HeaderInfo struct {
// headerInfo is a conversion type of types.Header turning it into a
// BlockInfo, but using a cached hash value.
type headerInfo struct {
hash common.Hash
parentHash common.Hash
coinbase common.Address
root common.Hash
number uint64
time uint64
mixDigest common.Hash // a.k.a. the randomness field post-merge.
baseFee *big.Int
txHash common.Hash
receiptHash common.Hash
gasUsed uint64
// withdrawalsRoot was added in Shapella and is thus optional
withdrawalsRoot *common.Hash
*types.Header
}
var _ eth.BlockInfo = (*HeaderInfo)(nil)
var _ eth.BlockInfo = (*headerInfo)(nil)
func (info *HeaderInfo) Hash() common.Hash {
return info.hash
func (h headerInfo) Hash() common.Hash {
return h.hash
}
func (info *HeaderInfo) ParentHash() common.Hash {
return info.parentHash
func (h headerInfo) ParentHash() common.Hash {
return h.Header.ParentHash
}
func (info *HeaderInfo) Coinbase() common.Address {
return info.coinbase
func (h headerInfo) Coinbase() common.Address {
return h.Header.Coinbase
}
func (info *HeaderInfo) Root() common.Hash {
return info.root
func (h headerInfo) Root() common.Hash {
return h.Header.Root
}
func (info *HeaderInfo) NumberU64() uint64 {
return info.number
func (h headerInfo) NumberU64() uint64 {
return h.Header.Number.Uint64()
}
func (info *HeaderInfo) Time() uint64 {
return info.time
func (h headerInfo) Time() uint64 {
return h.Header.Time
}
func (info *HeaderInfo) MixDigest() common.Hash {
return info.mixDigest
func (h headerInfo) MixDigest() common.Hash {
return h.Header.MixDigest
}
func (info *HeaderInfo) BaseFee() *big.Int {
return info.baseFee
func (h headerInfo) BaseFee() *big.Int {
return h.Header.BaseFee
}
func (info *HeaderInfo) ID() eth.BlockID {
return eth.BlockID{Hash: info.hash, Number: info.number}
func (h headerInfo) ReceiptHash() common.Hash {
return h.Header.ReceiptHash
}
func (info *HeaderInfo) ReceiptHash() common.Hash {
return info.receiptHash
func (h headerInfo) GasUsed() uint64 {
return h.Header.GasUsed
}
func (info *HeaderInfo) GasUsed() uint64 {
return info.gasUsed
func (h headerInfo) HeaderRLP() ([]byte, error) {
return rlp.EncodeToBytes(h.Header)
}
type rpcHeader struct {
......@@ -149,7 +138,12 @@ func (hdr *rpcHeader) checkPostMerge() error {
}
func (hdr *rpcHeader) computeBlockHash() common.Hash {
gethHeader := types.Header{
gethHeader := hdr.createGethHeader()
return gethHeader.Hash()
}
func (hdr *rpcHeader) createGethHeader() *types.Header {
return &types.Header{
ParentHash: hdr.ParentHash,
UncleHash: hdr.UncleHash,
Coinbase: hdr.Coinbase,
......@@ -168,10 +162,9 @@ func (hdr *rpcHeader) computeBlockHash() common.Hash {
BaseFee: (*big.Int)(hdr.BaseFee),
WithdrawalsHash: hdr.WithdrawalsRoot,
}
return gethHeader.Hash()
}
func (hdr *rpcHeader) Info(trustCache bool, mustBePostMerge bool) (*HeaderInfo, error) {
func (hdr *rpcHeader) Info(trustCache bool, mustBePostMerge bool) (eth.BlockInfo, error) {
if mustBePostMerge {
if err := hdr.checkPostMerge(); err != nil {
return nil, err
......@@ -182,22 +175,7 @@ func (hdr *rpcHeader) Info(trustCache bool, mustBePostMerge bool) (*HeaderInfo,
return nil, fmt.Errorf("failed to verify block hash: computed %s but RPC said %s", computed, hdr.Hash)
}
}
info := HeaderInfo{
hash: hdr.Hash,
parentHash: hdr.ParentHash,
coinbase: hdr.Coinbase,
root: hdr.Root,
number: uint64(hdr.Number),
time: uint64(hdr.Time),
mixDigest: hdr.MixDigest,
baseFee: (*big.Int)(hdr.BaseFee),
txHash: hdr.TxHash,
receiptHash: hdr.ReceiptHash,
gasUsed: uint64(hdr.GasUsed),
withdrawalsRoot: hdr.WithdrawalsRoot,
}
return &info, nil
return &headerInfo{hdr.Hash, hdr.createGethHeader()}, nil
}
type rpcBlock struct {
......@@ -215,7 +193,7 @@ func (block *rpcBlock) verify() error {
return nil
}
func (block *rpcBlock) Info(trustCache bool, mustBePostMerge bool) (*HeaderInfo, types.Transactions, error) {
func (block *rpcBlock) Info(trustCache bool, mustBePostMerge bool) (eth.BlockInfo, types.Transactions, error) {
if mustBePostMerge {
if err := block.checkPostMerge(); err != nil {
return nil, nil, err
......
package testutils
import (
"errors"
"math/big"
"math/rand"
......@@ -22,6 +23,7 @@ type MockBlockInfo struct {
InfoBaseFee *big.Int
InfoReceiptRoot common.Hash
InfoGasUsed uint64
InfoHeaderRLP []byte
}
func (l *MockBlockInfo) Hash() common.Hash {
......@@ -68,6 +70,13 @@ func (l *MockBlockInfo) ID() eth.BlockID {
return eth.BlockID{Hash: l.InfoHash, Number: l.InfoNum}
}
func (l *MockBlockInfo) HeaderRLP() ([]byte, error) {
if l.InfoHeaderRLP == nil {
return nil, errors.New("header rlp not available")
}
return l.InfoHeaderRLP, nil
}
func (l *MockBlockInfo) BlockRef() eth.L1BlockRef {
return eth.L1BlockRef{
Hash: l.InfoHash,
......
......@@ -4,7 +4,9 @@ import (
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-program/client/l1/test"
"github.com/stretchr/testify/require"
)
......@@ -13,59 +15,59 @@ var _ Oracle = (*CachingOracle)(nil)
func TestCachingOracle_HeaderByBlockHash(t *testing.T) {
rng := rand.New(rand.NewSource(1))
stub := newStubOracle(t)
stub := test.NewStubOracle(t)
oracle := NewCachingOracle(stub)
block := testutils.RandomBlockInfo(rng)
// Initial call retrieves from the stub
stub.blocks[block.Hash()] = block
stub.Blocks[block.Hash()] = block
result := oracle.HeaderByBlockHash(block.Hash())
require.Equal(t, block, result)
// Later calls should retrieve from cache
delete(stub.blocks, block.Hash())
delete(stub.Blocks, block.Hash())
result = oracle.HeaderByBlockHash(block.Hash())
require.Equal(t, block, result)
}
func TestCachingOracle_TransactionsByBlockHash(t *testing.T) {
rng := rand.New(rand.NewSource(1))
stub := newStubOracle(t)
stub := test.NewStubOracle(t)
oracle := NewCachingOracle(stub)
block, _ := testutils.RandomBlock(rng, 3)
// Initial call retrieves from the stub
stub.blocks[block.Hash()] = block
stub.txs[block.Hash()] = block.Transactions()
stub.Blocks[block.Hash()] = eth.BlockToInfo(block)
stub.Txs[block.Hash()] = block.Transactions()
actualBlock, actualTxs := oracle.TransactionsByBlockHash(block.Hash())
require.Equal(t, block, actualBlock)
require.Equal(t, eth.BlockToInfo(block), actualBlock)
require.Equal(t, block.Transactions(), actualTxs)
// Later calls should retrieve from cache
delete(stub.blocks, block.Hash())
delete(stub.txs, block.Hash())
delete(stub.Blocks, block.Hash())
delete(stub.Txs, block.Hash())
actualBlock, actualTxs = oracle.TransactionsByBlockHash(block.Hash())
require.Equal(t, block, actualBlock)
require.Equal(t, eth.BlockToInfo(block), actualBlock)
require.Equal(t, block.Transactions(), actualTxs)
}
func TestCachingOracle_ReceiptsByBlockHash(t *testing.T) {
rng := rand.New(rand.NewSource(1))
stub := newStubOracle(t)
stub := test.NewStubOracle(t)
oracle := NewCachingOracle(stub)
block, rcpts := testutils.RandomBlock(rng, 3)
// Initial call retrieves from the stub
stub.blocks[block.Hash()] = block
stub.rcpts[block.Hash()] = rcpts
stub.Blocks[block.Hash()] = eth.BlockToInfo(block)
stub.Rcpts[block.Hash()] = rcpts
actualBlock, actualRcpts := oracle.ReceiptsByBlockHash(block.Hash())
require.Equal(t, block, actualBlock)
require.Equal(t, eth.BlockToInfo(block), actualBlock)
require.EqualValues(t, rcpts, actualRcpts)
// Later calls should retrieve from cache
delete(stub.blocks, block.Hash())
delete(stub.rcpts, block.Hash())
delete(stub.Blocks, block.Hash())
delete(stub.Rcpts, block.Hash())
actualBlock, actualRcpts = oracle.ReceiptsByBlockHash(block.Hash())
require.Equal(t, block, actualBlock)
require.Equal(t, eth.BlockToInfo(block), actualBlock)
require.EqualValues(t, rcpts, actualRcpts)
}
......@@ -7,9 +7,9 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-program/client/l1/test"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
......@@ -24,8 +24,8 @@ var head = blockNum(1000)
func TestInfoByHash(t *testing.T) {
client, oracle := newClient(t)
hash := common.HexToHash("0xAABBCC")
expected := &sources.HeaderInfo{}
oracle.blocks[hash] = expected
expected := &testutils.MockBlockInfo{}
oracle.Blocks[hash] = expected
info, err := client.InfoByHash(context.Background(), hash)
require.NoError(t, err)
......@@ -35,8 +35,8 @@ func TestInfoByHash(t *testing.T) {
func TestL1BlockRefByHash(t *testing.T) {
client, oracle := newClient(t)
hash := common.HexToHash("0xAABBCC")
header := &sources.HeaderInfo{}
oracle.blocks[hash] = header
header := &testutils.MockBlockInfo{}
oracle.Blocks[hash] = header
expected := eth.InfoToL1BlockRef(header)
ref, err := client.L1BlockRefByHash(context.Background(), hash)
......@@ -47,12 +47,12 @@ func TestL1BlockRefByHash(t *testing.T) {
func TestFetchReceipts(t *testing.T) {
client, oracle := newClient(t)
hash := common.HexToHash("0xAABBCC")
expectedInfo := &sources.HeaderInfo{}
expectedInfo := &testutils.MockBlockInfo{}
expectedReceipts := types.Receipts{
&types.Receipt{},
}
oracle.blocks[hash] = expectedInfo
oracle.rcpts[hash] = expectedReceipts
oracle.Blocks[hash] = expectedInfo
oracle.Rcpts[hash] = expectedReceipts
info, rcpts, err := client.FetchReceipts(context.Background(), hash)
require.NoError(t, err)
......@@ -63,12 +63,12 @@ func TestFetchReceipts(t *testing.T) {
func TestInfoAndTxsByHash(t *testing.T) {
client, oracle := newClient(t)
hash := common.HexToHash("0xAABBCC")
expectedInfo := &sources.HeaderInfo{}
expectedInfo := &testutils.MockBlockInfo{}
expectedTxs := types.Transactions{
&types.Transaction{},
}
oracle.blocks[hash] = expectedInfo
oracle.txs[hash] = expectedTxs
oracle.Blocks[hash] = expectedInfo
oracle.Txs[hash] = expectedTxs
info, txs, err := client.InfoAndTxsByHash(context.Background(), hash)
require.NoError(t, err)
......@@ -120,7 +120,7 @@ func TestL1BlockRefByNumber(t *testing.T) {
t.Run("ParentOfHead", func(t *testing.T) {
client, oracle := newClient(t)
parent := blockNum(head.NumberU64() - 1)
oracle.blocks[parent.Hash()] = parent
oracle.Blocks[parent.Hash()] = parent
ref, err := client.L1BlockRefByNumber(context.Background(), parent.NumberU64())
require.NoError(t, err)
......@@ -132,7 +132,7 @@ func TestL1BlockRefByNumber(t *testing.T) {
blocks := []eth.BlockInfo{block}
for i := 0; i < 10; i++ {
block = blockNum(block.NumberU64() - 1)
oracle.blocks[block.Hash()] = block
oracle.Blocks[block.Hash()] = block
blocks = append(blocks, block)
}
......@@ -144,9 +144,9 @@ func TestL1BlockRefByNumber(t *testing.T) {
})
}
func newClient(t *testing.T) (*OracleL1Client, *stubOracle) {
stub := newStubOracle(t)
stub.blocks[head.Hash()] = head
func newClient(t *testing.T) (*OracleL1Client, *test.StubOracle) {
stub := test.NewStubOracle(t)
stub.Blocks[head.Hash()] = head
client := NewOracleL1Client(testlog.Logger(t, log.LvlDebug), stub, head.Hash())
return client, stub
}
......
package l1
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-program/preimage"
)
type BlockHeaderHint common.Hash
var _ preimage.Hint = BlockHeaderHint{}
func (l BlockHeaderHint) Hint() string {
return "l1-block-header " + (common.Hash)(l).String()
}
type TransactionsHint common.Hash
var _ preimage.Hint = TransactionsHint{}
func (l TransactionsHint) Hint() string {
return "l1-transactions " + (common.Hash)(l).String()
}
type ReceiptsHint common.Hash
var _ preimage.Hint = ReceiptsHint{}
func (l ReceiptsHint) Hint() string {
return "l1-receipts " + (common.Hash)(l).String()
}
package l1
import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
)
type Oracle interface {
......@@ -16,3 +22,67 @@ type Oracle interface {
// ReceiptsByBlockHash retrieves the receipts from the block with the given hash.
ReceiptsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Receipts)
}
// PreimageOracle implements Oracle using by interfacing with the pure preimage.Oracle
// to fetch pre-images to decode into the requested data.
type PreimageOracle struct {
oracle preimage.Oracle
hint preimage.Hinter
}
var _ Oracle = (*PreimageOracle)(nil)
func NewPreimageOracle(raw preimage.Oracle, hint preimage.Hinter) *PreimageOracle {
return &PreimageOracle{
oracle: raw,
hint: hint,
}
}
func (p *PreimageOracle) headerByBlockHash(blockHash common.Hash) *types.Header {
p.hint.Hint(BlockHeaderHint(blockHash))
headerRlp := p.oracle.Get(preimage.Keccak256Key(blockHash))
var header types.Header
if err := rlp.DecodeBytes(headerRlp, &header); err != nil {
panic(fmt.Errorf("invalid block header %s: %w", blockHash, err))
}
return &header
}
func (p *PreimageOracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo {
return eth.HeaderBlockInfo(p.headerByBlockHash(blockHash))
}
func (p *PreimageOracle) TransactionsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Transactions) {
header := p.headerByBlockHash(blockHash)
p.hint.Hint(TransactionsHint(blockHash))
opaqueTxs := mpt.ReadTrie(header.TxHash, func(key common.Hash) []byte {
return p.oracle.Get(preimage.Keccak256Key(key))
})
txs, err := eth.DecodeTransactions(opaqueTxs)
if err != nil {
panic(fmt.Errorf("failed to decode list of txs: %w", err))
}
return eth.HeaderBlockInfo(header), txs
}
func (p *PreimageOracle) ReceiptsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Receipts) {
info, txs := p.TransactionsByBlockHash(blockHash)
p.hint.Hint(ReceiptsHint(blockHash))
opaqueReceipts := mpt.ReadTrie(info.ReceiptHash(), func(key common.Hash) []byte {
return p.oracle.Get(preimage.Keccak256Key(key))
})
txHashes := eth.TransactionsToHashes(txs)
receipts, err := eth.DecodeRawReceipts(eth.ToBlockID(info), opaqueReceipts, txHashes)
if err != nil {
panic(fmt.Errorf("bad receipts data for block %s: %w", blockHash, err))
}
return info, receipts
}
package l1
import (
"encoding/json"
"fmt"
"math/rand"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
)
// testBlock tests that the given block with receipts can be passed through the preimage oracle.
func testBlock(t *testing.T, block *types.Block, receipts []*types.Receipt) {
// Prepare the pre-images
preimages := make(map[common.Hash][]byte)
hdrBytes, err := rlp.EncodeToBytes(block.Header())
require.NoError(t, err)
preimages[preimage.Keccak256Key(block.Hash()).PreimageKey()] = hdrBytes
opaqueTxs, err := eth.EncodeTransactions(block.Transactions())
require.NoError(t, err)
_, txsNodes := mpt.WriteTrie(opaqueTxs)
for _, p := range txsNodes {
preimages[preimage.Keccak256Key(crypto.Keccak256Hash(p)).PreimageKey()] = p
}
opaqueReceipts, err := eth.EncodeReceipts(receipts)
require.NoError(t, err)
_, receiptNodes := mpt.WriteTrie(opaqueReceipts)
for _, p := range receiptNodes {
preimages[preimage.Keccak256Key(crypto.Keccak256Hash(p)).PreimageKey()] = p
}
// Prepare a raw mock pre-image oracle that will serve the pre-image data and handle hints
var hints mock.Mock
po := &PreimageOracle{
oracle: preimage.OracleFn(func(key preimage.Key) []byte {
v, ok := preimages[key.PreimageKey()]
require.True(t, ok, "preimage must exist")
return v
}),
hint: preimage.HinterFn(func(v preimage.Hint) {
hints.MethodCalled("hint", v.Hint())
}),
}
// Check if block-headers work
hints.On("hint", BlockHeaderHint(block.Hash()).Hint()).Once().Return()
gotHeader := po.HeaderByBlockHash(block.Hash())
hints.AssertExpectations(t)
got, err := json.MarshalIndent(gotHeader, " ", " ")
require.NoError(t, err)
expected, err := json.MarshalIndent(block.Header(), " ", " ")
require.NoError(t, err)
require.Equal(t, expected, got, "expecting matching headers")
// Check if blocks with txs work
hints.On("hint", BlockHeaderHint(block.Hash()).Hint()).Once().Return()
hints.On("hint", TransactionsHint(block.Hash()).Hint()).Once().Return()
inf, gotTxs := po.TransactionsByBlockHash(block.Hash())
hints.AssertExpectations(t)
require.Equal(t, inf.Hash(), block.Hash())
expectedTxs := block.Transactions()
require.Equal(t, len(expectedTxs), len(gotTxs), "expecting equal tx list length")
for i, tx := range gotTxs {
require.Equalf(t, tx.Hash(), expectedTxs[i].Hash(), "expecting tx %d to match", i)
}
// Check if blocks with receipts work
hints.On("hint", BlockHeaderHint(block.Hash()).Hint()).Once().Return()
hints.On("hint", TransactionsHint(block.Hash()).Hint()).Once().Return()
hints.On("hint", ReceiptsHint(block.Hash()).Hint()).Once().Return()
inf, gotReceipts := po.ReceiptsByBlockHash(block.Hash())
hints.AssertExpectations(t)
require.Equal(t, inf.Hash(), block.Hash())
require.Equal(t, len(receipts), len(gotReceipts), "expecting equal tx list length")
for i, r := range gotReceipts {
require.Equalf(t, r.TxHash, expectedTxs[i].Hash(), "expecting receipt to match tx %d", i)
}
}
func TestPreimageOracleBlockByHash(t *testing.T) {
rng := rand.New(rand.NewSource(123))
for i := 0; i < 10; i++ {
block, receipts := testutils.RandomBlock(rng, 10)
t.Run(fmt.Sprintf("block_%d", i), func(t *testing.T) {
testBlock(t, block, receipts)
})
}
}
package l1
package test
import (
"testing"
......@@ -8,45 +8,45 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)
type stubOracle struct {
type StubOracle struct {
t *testing.T
// blocks maps block hash to eth.BlockInfo
blocks map[common.Hash]eth.BlockInfo
// Blocks maps block hash to eth.BlockInfo
Blocks map[common.Hash]eth.BlockInfo
// txs maps block hash to transactions
txs map[common.Hash]types.Transactions
// Txs maps block hash to transactions
Txs map[common.Hash]types.Transactions
// rcpts maps Block hash to receipts
rcpts map[common.Hash]types.Receipts
// Rcpts maps Block hash to receipts
Rcpts map[common.Hash]types.Receipts
}
func newStubOracle(t *testing.T) *stubOracle {
return &stubOracle{
func NewStubOracle(t *testing.T) *StubOracle {
return &StubOracle{
t: t,
blocks: make(map[common.Hash]eth.BlockInfo),
txs: make(map[common.Hash]types.Transactions),
rcpts: make(map[common.Hash]types.Receipts),
Blocks: make(map[common.Hash]eth.BlockInfo),
Txs: make(map[common.Hash]types.Transactions),
Rcpts: make(map[common.Hash]types.Receipts),
}
}
func (o stubOracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo {
info, ok := o.blocks[blockHash]
func (o StubOracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo {
info, ok := o.Blocks[blockHash]
if !ok {
o.t.Fatalf("unknown block %s", blockHash)
}
return info
}
func (o stubOracle) TransactionsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Transactions) {
txs, ok := o.txs[blockHash]
func (o StubOracle) TransactionsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Transactions) {
txs, ok := o.Txs[blockHash]
if !ok {
o.t.Fatalf("unknown txs %s", blockHash)
}
return o.HeaderByBlockHash(blockHash), txs
}
func (o stubOracle) ReceiptsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Receipts) {
rcpts, ok := o.rcpts[blockHash]
func (o StubOracle) ReceiptsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Receipts) {
rcpts, ok := o.Rcpts[blockHash]
if !ok {
o.t.Fatalf("unknown rcpts %s", blockHash)
}
......
......@@ -5,6 +5,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-program/client/l2/test"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
......@@ -13,55 +14,55 @@ import (
var _ Oracle = (*CachingOracle)(nil)
func TestBlockByHash(t *testing.T) {
stub, _ := newStubOracle(t)
stub, _ := test.NewStubOracle(t)
oracle := NewCachingOracle(stub)
rng := rand.New(rand.NewSource(1))
block, _ := testutils.RandomBlock(rng, 1)
// Initial call retrieves from the stub
stub.blocks[block.Hash()] = block
stub.Blocks[block.Hash()] = block
actual := oracle.BlockByHash(block.Hash())
require.Equal(t, block, actual)
// Later calls should retrieve from cache
delete(stub.blocks, block.Hash())
delete(stub.Blocks, block.Hash())
actual = oracle.BlockByHash(block.Hash())
require.Equal(t, block, actual)
}
func TestNodeByHash(t *testing.T) {
stub, stateStub := newStubOracle(t)
stub, stateStub := test.NewStubOracle(t)
oracle := NewCachingOracle(stub)
node := []byte{12, 3, 4}
hash := common.Hash{0xaa}
// Initial call retrieves from the stub
stateStub.data[hash] = node
stateStub.Data[hash] = node
actual := oracle.NodeByHash(hash)
require.Equal(t, node, actual)
// Later calls should retrieve from cache
delete(stateStub.data, hash)
delete(stateStub.Data, hash)
actual = oracle.NodeByHash(hash)
require.Equal(t, node, actual)
}
func TestCodeByHash(t *testing.T) {
stub, stateStub := newStubOracle(t)
stub, stateStub := test.NewStubOracle(t)
oracle := NewCachingOracle(stub)
node := []byte{12, 3, 4}
hash := common.Hash{0xaa}
// Initial call retrieves from the stub
stateStub.code[hash] = node
stateStub.Code[hash] = node
actual := oracle.CodeByHash(hash)
require.Equal(t, node, actual)
// Later calls should retrieve from cache
delete(stateStub.code, hash)
delete(stateStub.Code, hash)
actual = oracle.CodeByHash(hash)
require.Equal(t, node, actual)
}
......@@ -4,6 +4,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-program/client/l2/test"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
......@@ -27,7 +28,7 @@ var _ ethdb.KeyValueStore = (*OracleKeyValueStore)(nil)
func TestGet(t *testing.T) {
t.Run("IncorrectLengthKey", func(t *testing.T) {
oracle := newStubStateOracle(t)
oracle := test.NewStubStateOracle(t)
db := NewOracleBackedDB(oracle)
val, err := db.Get([]byte{1, 2, 3})
require.ErrorIs(t, err, ErrInvalidKeyLength)
......@@ -35,13 +36,13 @@ func TestGet(t *testing.T) {
})
t.Run("KeyWithCodePrefix", func(t *testing.T) {
oracle := newStubStateOracle(t)
oracle := test.NewStubStateOracle(t)
db := NewOracleBackedDB(oracle)
key := common.HexToHash("0x12345678")
prefixedKey := append(rawdb.CodePrefix, key.Bytes()...)
expected := []byte{1, 2, 3}
oracle.code[key] = expected
oracle.Code[key] = expected
val, err := db.Get(prefixedKey)
require.NoError(t, err)
......@@ -49,13 +50,13 @@ func TestGet(t *testing.T) {
})
t.Run("NormalKeyThatHappensToStartWithCodePrefix", func(t *testing.T) {
oracle := newStubStateOracle(t)
oracle := test.NewStubStateOracle(t)
db := NewOracleBackedDB(oracle)
key := make([]byte, common.HashLength)
copy(rawdb.CodePrefix, key)
println(key[0])
expected := []byte{1, 2, 3}
oracle.data[common.BytesToHash(key)] = expected
oracle.Data[common.BytesToHash(key)] = expected
val, err := db.Get(key)
require.NoError(t, err)
......@@ -65,8 +66,8 @@ func TestGet(t *testing.T) {
t.Run("KnownKey", func(t *testing.T) {
key := common.HexToHash("0xAA4488")
expected := []byte{2, 6, 3, 8}
oracle := newStubStateOracle(t)
oracle.data[key] = expected
oracle := test.NewStubStateOracle(t)
oracle.Data[key] = expected
db := NewOracleBackedDB(oracle)
val, err := db.Get(key.Bytes())
require.NoError(t, err)
......@@ -76,7 +77,7 @@ func TestGet(t *testing.T) {
func TestPut(t *testing.T) {
t.Run("NewKey", func(t *testing.T) {
oracle := newStubStateOracle(t)
oracle := test.NewStubStateOracle(t)
db := NewOracleBackedDB(oracle)
key := common.HexToHash("0xAA4488")
value := []byte{2, 6, 3, 8}
......@@ -88,7 +89,7 @@ func TestPut(t *testing.T) {
require.Equal(t, value, actual)
})
t.Run("ReplaceKey", func(t *testing.T) {
oracle := newStubStateOracle(t)
oracle := test.NewStubStateOracle(t)
db := NewOracleBackedDB(oracle)
key := common.HexToHash("0xAA4488")
value1 := []byte{2, 6, 3, 8}
......@@ -109,16 +110,13 @@ func TestSupportsStateDBOperations(t *testing.T) {
realDb := rawdb.NewDatabase(memorydb.New())
genesisBlock := l2Genesis.MustCommit(realDb)
loader := &kvStateOracle{
t: t,
source: realDb,
}
loader := test.NewKvStateOracle(t, realDb)
assertStateDataAvailable(t, NewOracleBackedDB(loader), l2Genesis, genesisBlock)
}
func TestUpdateState(t *testing.T) {
l2Genesis := createGenesis()
oracle := newStubStateOracle(t)
oracle := test.NewStubStateOracle(t)
db := rawdb.NewDatabase(NewOracleBackedDB(oracle))
genesisBlock := l2Genesis.MustCommit(db)
......
......@@ -8,7 +8,9 @@ import (
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-program/client/l2/engineapi"
"github.com/ethereum-optimism/optimism/op-program/client/l2/engineapi/test"
l2test "github.com/ethereum-optimism/optimism/op-program/client/l2/test"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
......@@ -142,13 +144,16 @@ func setupOracleBackedChainWithLowerHead(t *testing.T, blockCount int, headBlock
return blocks, chain
}
func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.ChainConfig, []*types.Block, *stubBlockOracle) {
func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.ChainConfig, []*types.Block, *l2test.StubBlockOracle) {
deployConfig := &genesis.DeployConfig{
L1ChainID: 900,
L2ChainID: 901,
L2BlockTime: 2,
FundDevAccounts: true,
L2GenesisBlockGasLimit: 30_000_000,
// Arbitrary non-zero difficulty in genesis.
// This is slightly weird for a chain starting post-merge but it happens so need to make sure it works
L2GenesisBlockDifficulty: (*hexutil.Big)(big.NewInt(100)),
}
l1Genesis, err := genesis.NewL1Genesis(deployConfig)
require.NoError(t, err)
......@@ -167,7 +172,7 @@ func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.Cha
genesisBlock := l2Genesis.MustCommit(db)
blocks, _ := core.GenerateChain(chainCfg, genesisBlock, consensus, db, blockCount, func(i int, gen *core.BlockGen) {})
blocks = append([]*types.Block{genesisBlock}, blocks...)
oracle := newStubOracleWithBlocks(t, blocks[:headBlockNumber+1], db)
oracle := l2test.NewStubOracleWithBlocks(t, blocks[:headBlockNumber+1], db)
return chainCfg, blocks, oracle
}
......
......@@ -207,7 +207,7 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV1(ctx context.Context, state *eth.Forkc
// Block is known locally, just sanity check that the beacon client does not
// attempt to push us back to before the merge.
// Note: Differs from op-geth implementation as pre-merge blocks are never supported here
if block.Difficulty().BitLen() > 0 {
if block.Difficulty().BitLen() > 0 && block.NumberU64() > 0 {
return STATUS_INVALID, errors.New("pre-merge blocks not supported")
}
valid := func(id *engine.PayloadID) *eth.ForkchoiceUpdatedResult {
......
package l2
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-program/preimage"
)
type BlockHeaderHint common.Hash
var _ preimage.Hint = BlockHeaderHint{}
func (l BlockHeaderHint) Hint() string {
return "l2-block-header " + (common.Hash)(l).String()
}
type TransactionsHint common.Hash
var _ preimage.Hint = TransactionsHint{}
func (l TransactionsHint) Hint() string {
return "l2-transactions " + (common.Hash)(l).String()
}
type CodeHint common.Hash
var _ preimage.Hint = CodeHint{}
func (l CodeHint) Hint() string {
return "l2-code " + (common.Hash)(l).String()
}
type StateNodeHint common.Hash
var _ preimage.Hint = StateNodeHint{}
func (l StateNodeHint) Hint() string {
return "l2-state-node " + (common.Hash)(l).String()
}
package l2
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
)
// StateOracle defines the high-level API used to retrieve L2 state data pre-images
......@@ -26,3 +33,55 @@ type Oracle interface {
// BlockByHash retrieves the block with the given hash.
BlockByHash(blockHash common.Hash) *types.Block
}
// PreimageOracle implements Oracle using by interfacing with the pure preimage.Oracle
// to fetch pre-images to decode into the requested data.
type PreimageOracle struct {
oracle preimage.Oracle
hint preimage.Hinter
}
var _ Oracle = (*PreimageOracle)(nil)
func NewPreimageOracle(raw preimage.Oracle, hint preimage.Hinter) *PreimageOracle {
return &PreimageOracle{
oracle: raw,
hint: hint,
}
}
func (p *PreimageOracle) headerByBlockHash(blockHash common.Hash) *types.Header {
p.hint.Hint(BlockHeaderHint(blockHash))
headerRlp := p.oracle.Get(preimage.Keccak256Key(blockHash))
var header types.Header
if err := rlp.DecodeBytes(headerRlp, &header); err != nil {
panic(fmt.Errorf("invalid block header %s: %w", blockHash, err))
}
return &header
}
func (p *PreimageOracle) BlockByHash(blockHash common.Hash) *types.Block {
header := p.headerByBlockHash(blockHash)
p.hint.Hint(TransactionsHint(blockHash))
opaqueTxs := mpt.ReadTrie(header.TxHash, func(key common.Hash) []byte {
return p.oracle.Get(preimage.Keccak256Key(key))
})
txs, err := eth.DecodeTransactions(opaqueTxs)
if err != nil {
panic(fmt.Errorf("failed to decode list of txs: %w", err))
}
return types.NewBlockWithHeader(header).WithBody(txs, nil)
}
func (p *PreimageOracle) NodeByHash(nodeHash common.Hash) []byte {
p.hint.Hint(StateNodeHint(nodeHash))
return p.oracle.Get(preimage.Keccak256Key(nodeHash))
}
func (p *PreimageOracle) CodeByHash(codeHash common.Hash) []byte {
p.hint.Hint(CodeHint(codeHash))
return p.oracle.Get(preimage.Keccak256Key(codeHash))
}
package l2
import (
"fmt"
"math/rand"
"testing"
"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/rlp"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
)
func mockPreimageOracle(t *testing.T) (po *PreimageOracle, hintsMock *mock.Mock, preimages map[common.Hash][]byte) {
// Prepare the pre-images
preimages = make(map[common.Hash][]byte)
hintsMock = new(mock.Mock)
po = &PreimageOracle{
oracle: preimage.OracleFn(func(key preimage.Key) []byte {
v, ok := preimages[key.PreimageKey()]
require.True(t, ok, "preimage must exist")
return v
}),
hint: preimage.HinterFn(func(v preimage.Hint) {
hintsMock.MethodCalled("hint", v.Hint())
}),
}
return po, hintsMock, preimages
}
// testBlock tests that the given block can be passed through the preimage oracle.
func testBlock(t *testing.T, block *types.Block) {
po, hints, preimages := mockPreimageOracle(t)
hdrBytes, err := rlp.EncodeToBytes(block.Header())
require.NoError(t, err)
preimages[preimage.Keccak256Key(block.Hash()).PreimageKey()] = hdrBytes
opaqueTxs, err := eth.EncodeTransactions(block.Transactions())
require.NoError(t, err)
_, txsNodes := mpt.WriteTrie(opaqueTxs)
for _, p := range txsNodes {
preimages[preimage.Keccak256Key(crypto.Keccak256Hash(p)).PreimageKey()] = p
}
// Prepare a raw mock pre-image oracle that will serve the pre-image data and handle hints
// Check if blocks with txs work
hints.On("hint", BlockHeaderHint(block.Hash()).Hint()).Once().Return()
hints.On("hint", TransactionsHint(block.Hash()).Hint()).Once().Return()
gotBlock := po.BlockByHash(block.Hash())
hints.AssertExpectations(t)
require.Equal(t, gotBlock.Hash(), block.Hash())
expectedTxs := block.Transactions()
require.Equal(t, len(expectedTxs), len(gotBlock.Transactions()), "expecting equal tx list length")
for i, tx := range gotBlock.Transactions() {
require.Equalf(t, tx.Hash(), expectedTxs[i].Hash(), "expecting tx %d to match", i)
}
}
func TestPreimageOracleBlockByHash(t *testing.T) {
rng := rand.New(rand.NewSource(123))
for i := 0; i < 10; i++ {
block, _ := testutils.RandomBlock(rng, 10)
t.Run(fmt.Sprintf("block_%d", i), func(t *testing.T) {
testBlock(t, block)
})
}
}
func TestPreimageOracleNodeByHash(t *testing.T) {
rng := rand.New(rand.NewSource(123))
for i := 0; i < 10; i++ {
t.Run(fmt.Sprintf("node_%d", i), func(t *testing.T) {
po, hints, preimages := mockPreimageOracle(t)
node := make([]byte, 123)
rng.Read(node)
h := crypto.Keccak256Hash(node)
preimages[preimage.Keccak256Key(h).PreimageKey()] = node
hints.On("hint", StateNodeHint(h).Hint()).Once().Return()
gotNode := po.NodeByHash(h)
hints.AssertExpectations(t)
require.Equal(t, hexutil.Bytes(node), hexutil.Bytes(gotNode), "node matches")
})
}
}
func TestPreimageOracleCodeByHash(t *testing.T) {
rng := rand.New(rand.NewSource(123))
for i := 0; i < 10; i++ {
t.Run(fmt.Sprintf("code_%d", i), func(t *testing.T) {
po, hints, preimages := mockPreimageOracle(t)
node := make([]byte, 123)
rng.Read(node)
h := crypto.Keccak256Hash(node)
preimages[preimage.Keccak256Key(h).PreimageKey()] = node
hints.On("hint", CodeHint(h).Hint()).Once().Return()
gotNode := po.CodeByHash(h)
hints.AssertExpectations(t)
require.Equal(t, hexutil.Bytes(node), hexutil.Bytes(gotNode), "code matches")
})
}
}
package l2
package test
import (
"testing"
......@@ -9,84 +9,97 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
)
type stubBlockOracle struct {
// Same as l2.StateOracle but need to use our own copy to avoid dependency loops
type stateOracle interface {
NodeByHash(nodeHash common.Hash) []byte
CodeByHash(codeHash common.Hash) []byte
}
type StubBlockOracle struct {
t *testing.T
blocks map[common.Hash]*types.Block
StateOracle
Blocks map[common.Hash]*types.Block
stateOracle
}
func newStubOracle(t *testing.T) (*stubBlockOracle, *stubStateOracle) {
stateOracle := newStubStateOracle(t)
blockOracle := stubBlockOracle{
func NewStubOracle(t *testing.T) (*StubBlockOracle, *StubStateOracle) {
stateOracle := NewStubStateOracle(t)
blockOracle := StubBlockOracle{
t: t,
blocks: make(map[common.Hash]*types.Block),
StateOracle: stateOracle,
Blocks: make(map[common.Hash]*types.Block),
stateOracle: stateOracle,
}
return &blockOracle, stateOracle
}
func newStubOracleWithBlocks(t *testing.T, chain []*types.Block, db ethdb.Database) *stubBlockOracle {
func NewStubOracleWithBlocks(t *testing.T, chain []*types.Block, db ethdb.Database) *StubBlockOracle {
blocks := make(map[common.Hash]*types.Block, len(chain))
for _, block := range chain {
blocks[block.Hash()] = block
}
return &stubBlockOracle{
blocks: blocks,
StateOracle: &kvStateOracle{t: t, source: db},
return &StubBlockOracle{
Blocks: blocks,
stateOracle: &KvStateOracle{t: t, Source: db},
}
}
func (o stubBlockOracle) BlockByHash(blockHash common.Hash) *types.Block {
block, ok := o.blocks[blockHash]
func (o StubBlockOracle) BlockByHash(blockHash common.Hash) *types.Block {
block, ok := o.Blocks[blockHash]
if !ok {
o.t.Fatalf("requested unknown block %s", blockHash)
}
return block
}
// kvStateOracle loads data from a source ethdb.KeyValueStore
type kvStateOracle struct {
// KvStateOracle loads data from a source ethdb.KeyValueStore
type KvStateOracle struct {
t *testing.T
source ethdb.KeyValueStore
Source ethdb.KeyValueStore
}
func NewKvStateOracle(t *testing.T, db ethdb.KeyValueStore) *KvStateOracle {
return &KvStateOracle{
t: t,
Source: db,
}
}
func (o *kvStateOracle) NodeByHash(nodeHash common.Hash) []byte {
val, err := o.source.Get(nodeHash.Bytes())
func (o *KvStateOracle) NodeByHash(nodeHash common.Hash) []byte {
val, err := o.Source.Get(nodeHash.Bytes())
if err != nil {
o.t.Fatalf("error retrieving node %v: %v", nodeHash, err)
}
return val
}
func (o *kvStateOracle) CodeByHash(hash common.Hash) []byte {
return rawdb.ReadCode(o.source, hash)
func (o *KvStateOracle) CodeByHash(hash common.Hash) []byte {
return rawdb.ReadCode(o.Source, hash)
}
func newStubStateOracle(t *testing.T) *stubStateOracle {
return &stubStateOracle{
func NewStubStateOracle(t *testing.T) *StubStateOracle {
return &StubStateOracle{
t: t,
data: make(map[common.Hash][]byte),
code: make(map[common.Hash][]byte),
Data: make(map[common.Hash][]byte),
Code: make(map[common.Hash][]byte),
}
}
// Stub StateOracle implementation that reads from simple maps
type stubStateOracle struct {
// StubStateOracle is a StateOracle implementation that reads from simple maps
type StubStateOracle struct {
t *testing.T
data map[common.Hash][]byte
code map[common.Hash][]byte
Data map[common.Hash][]byte
Code map[common.Hash][]byte
}
func (o *stubStateOracle) NodeByHash(nodeHash common.Hash) []byte {
data, ok := o.data[nodeHash]
func (o *StubStateOracle) NodeByHash(nodeHash common.Hash) []byte {
data, ok := o.Data[nodeHash]
if !ok {
o.t.Fatalf("no value for node %v", nodeHash)
}
return data
}
func (o *stubStateOracle) CodeByHash(hash common.Hash) []byte {
data, ok := o.code[hash]
func (o *StubStateOracle) CodeByHash(hash common.Hash) []byte {
data, ok := o.Code[hash]
if !ok {
o.t.Fatalf("no value for code %v", hash)
}
......
package mpt
import "github.com/ethereum/go-ethereum/ethdb"
type Hooks struct {
Get func(key []byte) []byte
Put func(key []byte, value []byte)
Delete func(key []byte)
}
// DB implements the ethdb.Database to back the StateDB of Geth.
type DB struct {
db Hooks
}
func (p *DB) Has(key []byte) (bool, error) {
panic("not supported")
}
func (p *DB) Get(key []byte) ([]byte, error) {
return p.db.Get(key), nil
}
func (p *DB) Put(key []byte, value []byte) error {
p.db.Put(key, value)
return nil
}
func (p DB) Delete(key []byte) error {
p.db.Delete(key)
return nil
}
func (p DB) Stat(property string) (string, error) {
panic("not supported")
}
func (p DB) NewBatch() ethdb.Batch {
panic("not supported")
}
func (p DB) NewBatchWithSize(size int) ethdb.Batch {
panic("not supported")
}
func (p DB) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
panic("not supported")
}
func (p DB) Compact(start []byte, limit []byte) error {
return nil // no-op
}
func (p DB) NewSnapshot() (ethdb.Snapshot, error) {
panic("not supported")
}
func (p DB) Close() error {
return nil
}
// We implement the full ethdb.Database bloat because the StateDB takes this full interface,
// even though it only uses the KeyValue subset.
func (p *DB) HasAncient(kind string, number uint64) (bool, error) {
panic("not supported")
}
func (p *DB) Ancient(kind string, number uint64) ([]byte, error) {
panic("not supported")
}
func (p *DB) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
panic("not supported")
}
func (p *DB) Ancients() (uint64, error) {
panic("not supported")
}
func (p *DB) Tail() (uint64, error) {
panic("not supported")
}
func (p *DB) AncientSize(kind string) (uint64, error) {
panic("not supported")
}
func (p *DB) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
panic("not supported")
}
func (p *DB) ModifyAncients(f func(ethdb.AncientWriteOp) error) (int64, error) {
panic("not supported")
}
func (p *DB) TruncateHead(n uint64) error {
panic("not supported")
}
func (p *DB) TruncateTail(n uint64) error {
panic("not supported")
}
func (p *DB) Sync() error {
panic("not supported")
}
func (p *DB) MigrateTable(s string, f func([]byte) ([]byte, error)) error {
panic("not supported")
}
func (p *DB) AncientDatadir() (string, error) {
panic("not supported")
}
var _ ethdb.KeyValueStore = (*DB)(nil)
package mpt
import (
"bytes"
"fmt"
"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/rlp"
"github.com/ethereum/go-ethereum/trie"
)
// ReadTrie takes a Merkle Patricia Trie (MPT) root of a "DerivableList", and a pre-image oracle getter,
// and traverses the implied MPT to collect all raw leaf nodes in order, which are then returned.
func ReadTrie(root common.Hash, getPreimage func(key common.Hash) []byte) []hexutil.Bytes {
odb := &DB{db: Hooks{
Get: func(key []byte) []byte {
if len(key) != 32 {
panic(fmt.Errorf("expected 32 byte key query, but got %d bytes: %x", len(key), key))
}
return getPreimage(*(*[32]byte)(key))
},
Put: func(key []byte, value []byte) {
panic("put not supported")
},
Delete: func(key []byte) {
panic("delete not supported")
},
}}
// trie.New backed with a trie.NodeReader and trie.Reader seems really promising
// for a simple node-fetching backend, but the interface is half-private,
// while we already have the full database code for doing the same thing.
// Maybe it's still worth a small diff in geth to expose it?
// Diff would be:
//
// type Node = node
//
// func DecodeNode(hash, buf []byte) (node, error) {
// return decodeNode(hash, buf)
// }
//
// And then still some code here to implement the trie.NodeReader and trie.Reader
// interfaces to map to the getPreimageFunction.
//
// For now we just use the state DB trie approach.
tdb := trie.NewDatabase(odb)
tr, err := trie.New(trie.TrieID(root), tdb)
if err != nil {
panic(err)
}
iter := tr.NodeIterator(nil)
// With small lists the iterator seems to use 0x80 (RLP empty string, unlike the others)
// as key for item 0, causing it to come last.
// Let's just remember the keys, and reorder them in the canonical order, to ensure it is correct.
var values [][]byte
var keys []uint64
for iter.Next(true) {
if iter.Leaf() {
k := iter.LeafKey()
var x uint64
err := rlp.DecodeBytes(k, &x)
if err != nil {
panic(fmt.Errorf("invalid key: %w", err))
}
keys = append(keys, x)
values = append(values, iter.LeafBlob())
}
}
out := make([]hexutil.Bytes, len(values))
for i, x := range keys {
if x >= uint64(len(values)) {
panic(fmt.Errorf("bad key: %d", x))
}
if out[x] != nil {
panic(fmt.Errorf("duplicate key %d", x))
}
out[x] = values[i]
}
return out
}
type rawList []hexutil.Bytes
func (r rawList) Len() int {
return len(r)
}
func (r rawList) EncodeIndex(i int, buf *bytes.Buffer) {
buf.Write(r[i])
}
var _ types.DerivableList = rawList(nil)
type noResetHasher struct {
*trie.StackTrie
}
// Reset is intercepted and is no-op, because we want to retain the writing function when calling types.DeriveSha
func (n noResetHasher) Reset() {}
// WriteTrie takes a list of values, and merkleizes them as a "DerivableList":
// a Merkle Patricia Trie (MPT) with values keyed by their RLP encoded index.
// This merkleization matches that of transactions, receipts, and withdrawals lists in the block header
// (at least up to the Shanghai L1 update).
// This then returns the MPT root and a list of pre-images of the trie.
// Note: empty values are illegal, and there may be less pre-images returned than values,
// if any values are less than 32 bytes and fit into branch-node slots that way.
func WriteTrie(values []hexutil.Bytes) (common.Hash, []hexutil.Bytes) {
var out []hexutil.Bytes
st := noResetHasher{trie.NewStackTrie(
func(owner common.Hash, path []byte, hash common.Hash, blob []byte) {
out = append(out, common.CopyBytes(blob)) // the stack hasher may mutate the blob bytes, so copy them.
})}
root := types.DeriveSha(rawList(values), st)
return root, out
}
package mpt
import (
"fmt"
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
type trieCase struct {
name string
elements []hexutil.Bytes
}
func (tc *trieCase) run(t *testing.T) {
root, preimages := WriteTrie(tc.elements)
byHash := make(map[common.Hash][]byte)
for _, v := range preimages {
k := crypto.Keccak256Hash(v)
byHash[k] = v
}
results := ReadTrie(root, func(key common.Hash) []byte {
v, ok := byHash[key]
if !ok {
panic(fmt.Errorf("missing key %s", key))
}
return v
})
require.Equal(t, len(tc.elements), len(results), "expected equal amount of values")
for i, result := range results {
// hex encoded for debugging readability
require.Equal(t, tc.elements[i].String(), result.String(),
"value %d does not match, expected equal value data", i)
}
}
func TestListTrieRoundtrip(t *testing.T) {
testCases := []trieCase{
{name: "empty list", elements: []hexutil.Bytes{}},
{name: "nil list", elements: nil},
{name: "simple", elements: []hexutil.Bytes{[]byte("hello"), []byte("world")}},
}
rng := rand.New(rand.NewSource(1234))
// add some randomized cases
for i := 0; i < 30; i++ {
n := rng.Intn(300)
elems := make([]hexutil.Bytes, n)
for i := range elems {
length := 1 + rng.Intn(300) // empty items not allowed
data := make([]byte, length)
rng.Read(data[:])
elems[i] = data
}
testCases = append(testCases, trieCase{name: fmt.Sprintf("rand_%d", i), elements: elems})
}
for _, tc := range testCases {
t.Run(tc.name, tc.run)
}
}
......@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
cll1 "github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
......@@ -24,7 +25,7 @@ var _ Source = (*sources.L1Client)(nil)
func TestHeaderByHash(t *testing.T) {
t.Run("Success", func(t *testing.T) {
expected := &sources.HeaderInfo{}
expected := &testutils.MockBlockInfo{}
source := &stubSource{nextInfo: expected}
oracle := newFetchingOracle(t, source)
......@@ -54,7 +55,7 @@ func TestHeaderByHash(t *testing.T) {
func TestTransactionsByHash(t *testing.T) {
t.Run("Success", func(t *testing.T) {
expectedInfo := &sources.HeaderInfo{}
expectedInfo := &testutils.MockBlockInfo{}
expectedTxs := types.Transactions{
&types.Transaction{},
}
......@@ -75,7 +76,7 @@ func TestTransactionsByHash(t *testing.T) {
})
t.Run("UnknownBlock_NoTxs", func(t *testing.T) {
oracle := newFetchingOracle(t, &stubSource{nextInfo: &sources.HeaderInfo{}})
oracle := newFetchingOracle(t, &stubSource{nextInfo: &testutils.MockBlockInfo{}})
hash := common.HexToHash("0x4455")
require.PanicsWithError(t, fmt.Errorf("unknown block: %s", hash).Error(), func() {
oracle.TransactionsByBlockHash(hash)
......@@ -96,7 +97,7 @@ func TestTransactionsByHash(t *testing.T) {
func TestReceiptsByHash(t *testing.T) {
t.Run("Success", func(t *testing.T) {
expectedInfo := &sources.HeaderInfo{}
expectedInfo := &testutils.MockBlockInfo{}
expectedRcpts := types.Receipts{
&types.Receipt{},
}
......@@ -117,7 +118,7 @@ func TestReceiptsByHash(t *testing.T) {
})
t.Run("UnknownBlock_NoTxs", func(t *testing.T) {
oracle := newFetchingOracle(t, &stubSource{nextInfo: &sources.HeaderInfo{}})
oracle := newFetchingOracle(t, &stubSource{nextInfo: &testutils.MockBlockInfo{}})
hash := common.HexToHash("0x4455")
require.PanicsWithError(t, fmt.Errorf("unknown block: %s", hash).Error(), func() {
oracle.ReceiptsByBlockHash(hash)
......
package preimage
import (
"encoding/binary"
"fmt"
"io"
)
// HintWriter writes hints to an io.Writer (e.g. a special file descriptor, or a debug log),
// for a pre-image oracle service to prepare specific pre-images.
type HintWriter struct {
w io.Writer
}
var _ Hinter = (*HintWriter)(nil)
func NewHintWriter(w io.Writer) *HintWriter {
return &HintWriter{w: w}
}
func (hw *HintWriter) Hint(v Hint) {
hint := v.Hint()
var hintBytes []byte
hintBytes = binary.BigEndian.AppendUint32(hintBytes, uint32(len(hint)))
hintBytes = append(hintBytes, []byte(hint)...)
hintBytes = append(hintBytes, 0) // to block writing on
_, err := hw.w.Write(hintBytes)
if err != nil {
panic(fmt.Errorf("failed to write pre-image hint: %w", err))
}
}
// HintReader reads the hints of HintWriter and passes them to a router for preparation of the requested pre-images.
// Onchain the written hints are no-op.
type HintReader struct {
r io.Reader
}
func NewHintReader(r io.Reader) *HintReader {
return &HintReader{r: r}
}
func (hr *HintReader) NextHint(router func(hint string) error) error {
var length uint32
if err := binary.Read(hr.r, binary.BigEndian, &length); err != nil {
if err == io.EOF {
return io.EOF
}
return fmt.Errorf("failed to read hint length prefix: %w", err)
}
payload := make([]byte, length)
if length > 0 {
if _, err := io.ReadFull(hr.r, payload); err != nil {
return fmt.Errorf("failed to read hint payload (length %d): %w", length, err)
}
}
if err := router(string(payload)); err != nil {
return fmt.Errorf("failed to handle hint: %w", err)
}
if _, err := hr.r.Read([]byte{0}); err != nil {
return fmt.Errorf("failed to read trailing no-op byte to unblock hint writer: %w", err)
}
return nil
}
package preimage
import (
"bytes"
"crypto/rand"
"io"
"testing"
"github.com/stretchr/testify/require"
)
type rawHint string
func (rh rawHint) Hint() string {
return string(rh)
}
func TestHints(t *testing.T) {
// Note: pretty much every string is valid communication:
// length, payload, 0. Worst case you run out of data, or allocate too much.
testHint := func(hints ...string) {
var buf bytes.Buffer
hw := NewHintWriter(&buf)
for _, h := range hints {
hw.Hint(rawHint(h))
}
hr := NewHintReader(&buf)
var got []string
for i := 0; i < 100; i++ { // sanity limit
err := hr.NextHint(func(hint string) error {
got = append(got, hint)
return nil
})
if err == io.EOF {
break
}
require.NoError(t, err)
}
require.Equal(t, len(hints), len(got), "got all hints")
for i, h := range hints {
require.Equal(t, h, got[i], "hints match")
}
}
t.Run("empty hint", func(t *testing.T) {
testHint("")
})
t.Run("hello world", func(t *testing.T) {
testHint("hello world")
})
t.Run("zero byte", func(t *testing.T) {
testHint(string([]byte{0}))
})
t.Run("many zeroes", func(t *testing.T) {
testHint(string(make([]byte, 1000)))
})
t.Run("random data", func(t *testing.T) {
dat := make([]byte, 1000)
_, _ = rand.Read(dat[:])
testHint(string(dat))
})
t.Run("multiple hints", func(t *testing.T) {
testHint("give me header a", "also header b", "foo bar")
})
t.Run("unexpected EOF", func(t *testing.T) {
var buf bytes.Buffer
hw := NewHintWriter(&buf)
hw.Hint(rawHint("hello"))
_, _ = buf.Read(make([]byte, 1)) // read one byte so it falls short, see if it's detected
hr := NewHintReader(&buf)
err := hr.NextHint(func(hint string) error { return nil })
require.ErrorIs(t, err, io.ErrUnexpectedEOF)
})
}
package preimage
import (
"encoding/binary"
"github.com/ethereum/go-ethereum/common"
)
type Key interface {
// PreimageKey changes the Key commitment into a
// 32-byte type-prefixed preimage key.
PreimageKey() common.Hash
}
type Oracle interface {
// Get the full pre-image of a given pre-image key.
// This returns no error: the client state-transition
// is invalid if there is any missing pre-image data.
Get(key Key) []byte
}
type OracleFn func(key Key) []byte
func (fn OracleFn) Get(key Key) []byte {
return fn(key)
}
// KeyType is the key-type of a pre-image, used to prefix the pre-image key with.
type KeyType byte
const (
// The zero key type is illegal to use, ensuring all keys are non-zero.
_ KeyType = 0
// LocalKeyType is for input-type pre-images, specific to the local program instance.
LocalKeyType KeyType = 1
// Keccak25Key6Type is for keccak256 pre-images, for any global shared pre-images.
Keccak25Key6Type KeyType = 2
)
// LocalIndexKey is a key local to the program, indexing a special program input.
type LocalIndexKey uint64
func (k LocalIndexKey) PreimageKey() (out common.Hash) {
out[0] = byte(LocalKeyType)
binary.BigEndian.PutUint64(out[24:], uint64(k))
return
}
// Keccak256Key wraps a keccak256 hash to use it as a typed pre-image key.
type Keccak256Key common.Hash
func (k Keccak256Key) PreimageKey() (out common.Hash) {
out = common.Hash(k) // copy the keccak hash
out[0] = byte(Keccak25Key6Type) // apply prefix
return
}
// Hint is an interface to enable any program type to function as a hint,
// when passed to the Hinter interface, returning a string representation
// of what data the host should prepare pre-images for.
type Hint interface {
Hint() string
}
// Hinter is an interface to write hints to the host.
// This may be implemented as a no-op or logging hinter
// if the program is executing in a read-only environment
// where the host is expected to have all pre-images ready.
type Hinter interface {
Hint(v Hint)
}
type HinterFn func(v Hint)
func (fn HinterFn) Hint(v Hint) {
fn(v)
}
package preimage
import (
"encoding/binary"
"fmt"
"io"
"github.com/ethereum/go-ethereum/common"
)
// OracleClient implements the Oracle by writing the pre-image key to the given stream,
// and reading back a length-prefixed value.
type OracleClient struct {
rw io.ReadWriter
}
func NewOracleClient(rw io.ReadWriter) *OracleClient {
return &OracleClient{rw: rw}
}
var _ Oracle = (*OracleClient)(nil)
func (o *OracleClient) Get(key Key) []byte {
h := key.PreimageKey()
if _, err := o.rw.Write(h[:]); err != nil {
panic(fmt.Errorf("failed to write key %s (%T) to pre-image oracle: %w", key, key, err))
}
var length uint64
if err := binary.Read(o.rw, binary.BigEndian, &length); err != nil {
panic(fmt.Errorf("failed to read pre-image length of key %s (%T) from pre-image oracle: %w", key, key, err))
}
payload := make([]byte, length)
if _, err := io.ReadFull(o.rw, payload); err != nil {
panic(fmt.Errorf("failed to read pre-image payload (length %d) of key %s (%T) from pre-image oracle: %w", length, key, key, err))
}
return payload
}
// OracleServer serves the pre-image requests of the OracleClient, implementing the same protocol as the onchain VM.
type OracleServer struct {
rw io.ReadWriter
}
func NewOracleServer(rw io.ReadWriter) *OracleServer {
return &OracleServer{rw: rw}
}
func (o *OracleServer) NextPreimageRequest(getPreimage func(key common.Hash) ([]byte, error)) error {
var key common.Hash
if _, err := io.ReadFull(o.rw, key[:]); err != nil {
if err == io.EOF {
return io.EOF
}
return fmt.Errorf("failed to read requested pre-image key: %w", err)
}
value, err := getPreimage(key)
if err != nil {
return fmt.Errorf("failed to serve pre-image %s request: %w", key, err)
}
if err := binary.Write(o.rw, binary.BigEndian, uint64(len(value))); err != nil {
return fmt.Errorf("failed to write length-prefix %d: %w", len(value), err)
}
if len(value) == 0 {
return nil
}
if _, err := o.rw.Write(value); err != nil {
return fmt.Errorf("failed to write pre-image value (%d long): %w", len(value), err)
}
return nil
}
package preimage
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"sync"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
type readWritePair struct {
io.Reader
io.Writer
}
func bidirectionalPipe() (a, b io.ReadWriter) {
ar, bw := io.Pipe()
br, aw := io.Pipe()
return readWritePair{Reader: ar, Writer: aw}, readWritePair{Reader: br, Writer: bw}
}
func TestOracle(t *testing.T) {
testPreimage := func(preimages ...[]byte) {
a, b := bidirectionalPipe()
cl := NewOracleClient(a)
srv := NewOracleServer(b)
preimageByHash := make(map[common.Hash][]byte)
for _, p := range preimages {
k := Keccak256Key(crypto.Keccak256Hash(p))
preimageByHash[k.PreimageKey()] = p
}
for _, p := range preimages {
k := Keccak256Key(crypto.Keccak256Hash(p))
var wg sync.WaitGroup
wg.Add(2)
go func(k Key, p []byte) {
result := cl.Get(k)
wg.Done()
expected := preimageByHash[k.PreimageKey()]
require.True(t, bytes.Equal(expected, result), "need correct preimage %x, got %x", expected, result)
}(k, p)
go func() {
err := srv.NextPreimageRequest(func(key common.Hash) ([]byte, error) {
dat, ok := preimageByHash[key]
if !ok {
return nil, fmt.Errorf("cannot find %s", key)
}
return dat, nil
})
wg.Done()
require.NoError(t, err)
}()
wg.Wait()
}
}
t.Run("empty preimage", func(t *testing.T) {
testPreimage([]byte{})
})
t.Run("nil preimage", func(t *testing.T) {
testPreimage(nil)
})
t.Run("zero", func(t *testing.T) {
testPreimage([]byte{0})
})
t.Run("multiple", func(t *testing.T) {
testPreimage([]byte("tx from alice"), []byte{0x13, 0x37}, []byte("tx from bob"))
})
t.Run("zeroes", func(t *testing.T) {
testPreimage(make([]byte, 1000))
})
t.Run("random", func(t *testing.T) {
dat := make([]byte, 1000)
_, _ = rand.Read(dat[:])
testPreimage(dat)
})
}
......@@ -80,7 +80,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/**
* @custom:semver 1.2.0
* @custom:semver 1.3.0
*
* @param _owner Initial owner of the contract.
* @param _overhead Initial overhead value.
......@@ -98,7 +98,7 @@ contract SystemConfig is OwnableUpgradeable, Semver {
uint64 _gasLimit,
address _unsafeBlockSigner,
ResourceMetering.ResourceConfig memory _config
) Semver(1, 2, 0) {
) Semver(1, 3, 0) {
initialize({
_owner: _owner,
_overhead: _overhead,
......@@ -269,8 +269,11 @@ contract SystemConfig is OwnableUpgradeable, Semver {
_config.minimumBaseFee <= _config.maximumBaseFee,
"SystemConfig: min base fee must be less than max base"
);
// Base fee change denominator must be greater than 0.
require(_config.baseFeeMaxChangeDenominator > 0, "SystemConfig: denominator cannot be 0");
// Base fee change denominator must be greater than 1.
require(
_config.baseFeeMaxChangeDenominator > 1,
"SystemConfig: denominator must be larger than 1"
);
// Max resource limit plus system tx gas must be less than or equal to the L2 gas limit.
// The gas limit must be increased before these values can be increased.
require(
......
......@@ -1085,3 +1085,88 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
assertEq(slot21Expected, slot21After);
}
}
/**
* @title OptimismPortalResourceFuzz_Test
* @dev Test various values of the resource metering config to ensure that deposits cannot be
* broken by changing the config.
*/
contract OptimismPortalResourceFuzz_Test is Portal_Initializer {
/**
* @dev The max gas limit observed throughout this test. Setting this too high can cause
* the test to take too long to run.
*/
uint256 constant MAX_GAS_LIMIT = 30_000_000;
/**
* @dev Test that various values of the resource metering config will not break deposits.
*/
function testFuzz_systemConfigDeposit_succeeds(
uint32 _maxResourceLimit,
uint8 _elasticityMultiplier,
uint8 _baseFeeMaxChangeDenominator,
uint32 _minimumBaseFee,
uint32 _systemTxMaxGas,
uint128 _maximumBaseFee,
uint64 _gasLimit,
uint64 _prevBoughtGas,
uint128 _prevBaseFee,
uint8 _blockDiff
) external {
// Get the set system gas limit
uint64 gasLimit = systemConfig.gasLimit();
// Bound resource config
_maxResourceLimit = uint32(bound(_maxResourceLimit, 21000, MAX_GAS_LIMIT / 8));
_gasLimit = uint64(bound(_gasLimit, 21000, _maxResourceLimit));
_prevBaseFee = uint128(bound(_prevBaseFee, 0, 5 gwei));
// Prevent values that would cause reverts
vm.assume(gasLimit >= _gasLimit);
vm.assume(_minimumBaseFee < _maximumBaseFee);
vm.assume(_baseFeeMaxChangeDenominator > 1);
vm.assume(uint256(_maxResourceLimit) + uint256(_systemTxMaxGas) <= gasLimit);
vm.assume(_elasticityMultiplier > 0);
vm.assume(
((_maxResourceLimit / _elasticityMultiplier) * _elasticityMultiplier) ==
_maxResourceLimit
);
_prevBoughtGas = uint64(bound(_prevBoughtGas, 0, _maxResourceLimit - _gasLimit));
_blockDiff = uint8(bound(_blockDiff, 0, 3));
// Create a resource config to mock the call to the system config with
ResourceMetering.ResourceConfig memory rcfg = ResourceMetering.ResourceConfig({
maxResourceLimit: _maxResourceLimit,
elasticityMultiplier: _elasticityMultiplier,
baseFeeMaxChangeDenominator: _baseFeeMaxChangeDenominator,
minimumBaseFee: _minimumBaseFee,
systemTxMaxGas: _systemTxMaxGas,
maximumBaseFee: _maximumBaseFee
});
vm.mockCall(
address(systemConfig),
abi.encodeWithSelector(systemConfig.resourceConfig.selector),
abi.encode(rcfg)
);
// Set the resource params
uint256 _prevBlockNum = block.number - _blockDiff;
vm.store(
address(op),
bytes32(uint256(1)),
bytes32((_prevBlockNum << 192) | (uint256(_prevBoughtGas) << 128) | _prevBaseFee)
);
// Ensure that the storage setting is correct
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = op.params();
assertEq(prevBaseFee, _prevBaseFee);
assertEq(prevBoughtGas, _prevBoughtGas);
assertEq(prevBlockNum, _prevBlockNum);
// Do a deposit, should not revert
op.depositTransaction{ gas: MAX_GAS_LIMIT }({
_to: address(0x20),
_value: 0x40,
_gasLimit: _gasLimit,
_isCreation: false,
_data: hex""
});
}
}
......@@ -110,7 +110,7 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
maximumBaseFee: 2 gwei
});
vm.prank(sysConf.owner());
vm.expectRevert("SystemConfig: denominator cannot be 0");
vm.expectRevert("SystemConfig: denominator must be larger than 1");
sysConf.setResourceConfig(config);
}
......
......@@ -24,6 +24,14 @@ that maintains 1:1 compatibility with Ethereum.
- [Predeploys](predeploys.md)
- [Glossary](glossary.md)
### Experimental
Specifications of new features in active development.
- [Fault Proof](./fault-proof.md)
- [Dispute Game](./dispute-game.md)
- [Dispute Game Interface](./dispute-game-interface.md)
## Design Goals
Our aim is to design a protocol specification that is:
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than diagrams.net -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="3562px" height="3884px" viewBox="-0.5 -0.5 3562 3884" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2023-04-11T15:13:26.154Z&quot; agent=&quot;Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0&quot; etag=&quot;vDBsOIw1GRsWubY4oKHH&quot; version=&quot;21.1.5&quot; type=&quot;google&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;5oXVfdM0MUB0GZk8333n&quot;&gt;7RzZdto49Gt4JMeWN3hMk7SZTjPNmcx0eZqj2ALUGIuRBYF+/Uhe8CIBDhjLnGkfGutaluW7b2Jg3czXHyhczB5IgMIBMIL1wLodAGCZJuB/BGSTQoBlj1PIlOIghZkF4An/RBnQyKBLHKC4MpEREjK8qAJ9EkXIZxUYpJS8VqdNSFh96wJOkQR48mEoQ7/igM1S6MgxCvg9wtNZ/mbTyO7MYT45A8QzGJDXEsi6G1g3lBCWXs3XNygU2Mvxkj73fsfd7cYoiliTBzYPhvPxr28/Pnw1//YWj6sFs8jQSVdZwXCZfXC2WbbJMcD3vRCXkxCtrwVGB9Y7FAXZ5a0fwjjGPgfO2DzkAJNfUrKMAiRebPDRBIfhDQkJTRa0AohGE/FAzCh5QaU7rj9CzxN+J90ECiTaFB9rblHImQ+ROWJ0w6e8FkTKaTQr0SeHURRChlfV5WHGK9Ptcts3PBLMXwyMjLGHlpstlPG1l4/zNWKypD7KHitTpbaSbR9YiEE6RUxaiF+UvrsAJURXM8Aqurv/GGPvZ3jzOVjNv3n/LO+G+beXCC7Q/pQNCWUzMiURDO8KaI28xZxPhCwyDviBGNtk4gyXjFT5A60x+yYevwJONvyerSaub9flwSYfRPxT06c8Jx9/z1cUg+K5ZJQ/uIN5+EcnRNqDnVzjJDTYN2+k5FiZPd/Gd1zG4KY0YSG4IN7HllVmcsfGXuYbmmDvA/wi3UKrLOfIOqZTlvOOYjnQM5az2+a4imZ5sxpxfqmRPdhpSFPQOlGPUiOmU9UKwD2gRry988+jRWw9HHcs8/hLukpefLQu6oD9zmPFDvPXqJnz1JrPIzm9n8T4M4U+55I6V1V55nWGGXpawAThrzzoqfLHTiKtEGVovRer+V2wAzsl13Y7p+zb1j3H1pS7rdlH7LVutxoKl9Mre22pReAumuKIi4Bx/fibfkGoqQnHUAiC0aUgWONL9HK68lzti5SEPP6+rGikZyS1+kXSffY9V3GalduoFnirdJvbpW4zrQs08h2JgdNQDECvxMC0L9FadeW3NaWpafaKqHLCPlVr76D/goJP4GYGcdQ37WZr126u2iQsKBriuSgBATfke3j3TPnVVFxNEPNniJ6GygDGs23U34ZLbFYROzQ9lU88ElLUoekwJew+JFwoqnITPF1SLhgkGljXApQyqAGjQAgNCcPlYjsz1s65Q1dj9K0s0Zlufwyz2VSLV5S40UiJH672NcmeK9S6EqueVsssa/FHijJFZPz+hf/3xAjV76UOzZo4DIHuZJSn2U/tefVopM2tOa5iWc92Wt6BWoO1d/55ag3eRXrSlmVWtPDVeDw6wHjJ6BFRzDGGaHfcCNx+cCMwatxld8BdOZbKzqlZ5CvY7CbEKKuEaDUGwNaYtFBacc224Ci5rMqk08gUtOIbAdBUGu2OnCO1vzv6vxj4bqma4lVbgwiQlNyCB39kKkbXcvgd4HixZCgPFOu3EwUZEvIigkftenFc6+GztMeMmiu2x8nQMam/dmRIUefoX9QI5LrGY5G/2rYv1EWlL95DPZTcjrWFksDTKyW9jiRzl/xSmta4fXtj15pp7X3gTG1rmrN5XXg3lV63LjiwJ93XUl/bgVxGvW2yi1QGUFRCimBTv5Wox5j6u9+cSyyMd1VFtZtGH/1qV8+3XZICtMC7oxGyZDwaEdsTx7WSalXM6NJPylrSbP4XzoVspP+L+SHEc/F3hvwX7UJWryIq4xW7UxmTU2A5WgO8qmDL/XdJkvosidgwTsRHlBXN0WKdoj67XyJGSp4c8EjJlEJBjdwzTifwjW/nlJiAg5MtVFc7dVfD5GnIUIjiWMlBZ355RITUormovSJKCY07eieKVpiSaJ5g3oC+r0SAmE6irFZc3GyBD+qfV5NFLkKsKnDVU4oRiYR+Lx9pzEAwxNOID0M0ESsIccQ+DK8zMBOKXynctcOS/Hsyq2CO2pH3en5CFXkBlU0164357Qn8WIfA35NYMJ3YOjC+PFSl/FlaoENxTHTBZBk2eFPxUKl7hS+Q1IsNYY+MAMcvO2RqMpGEqh/yMcdBkLhOvRCRocIkAkslIs65RMSVbSJaI3+Z+hwGowJDh8mTo93nyBElvd2Ip4gzK3xOlhJozuIdvq7zbuDcirW4mxpniH8D5RN6ZXs0q/QDVkv088CVU3VqVMWpsYKCdgsEVCdhFSquHkgU5+gzXFU6xnaeqE8xn/8ggSXRYgCs9+8N/m+L3T6fpa+1AJh1ijQ+Sz86sFB7Z+nVBL/ESPFNgaKin7GdBLyiUUCJYldn1AhkjVxOwN/jIpgo7OpXitmpbaQtKEj7sAvYbVpF1o4BongFM/MWCvbXjbRho0h5dCa0qXWM5laki9Axu1VHAxVjGmqe6Kb7QU7PHlYxfyIYnKFTXZKTRk6DWt/or4grnC9trUKN26hBB33UuwvdvW8V8vYKy66C+BOiq3Ys8kkSIhXEuzTJSnTuTsIqciniV9jixhmUeroiOV2Do6l6Js0wlXgCydRBkaXsKiHxTBgj8xMSEidxh5SQ2CYayuxRRL1lBhk5Z2IQOWmX1A41nKI6UfKKA1L7DlKNz3eOSm2j+vQjSg1tVK3F/FA767mcu9xPP9wF6eg0WOAiDxK4hl1x4K8M45ATrzxI0CXxd+svbbTXLN3Hdf7YjlujPTjqEIl2we8qc7R3lzs81VmaxuTEPjlV1IWtzP2LSm3EU3ki4FyeCJARKkvXr+S6nFwftpVclxY6c3Jd0bj2BxmKJKHxOkPRoNQvkBV4KYIBicKNxBh9q2Hag2qNDLQgt6ZRFVpVG52qGnZExZ8Pi1+xTsld/Bi4dfcf&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 22 3760 L 22 3720 L 3142 3720 L 3142 3678 L 3218 3740 L 3142 3802 L 3142 3760 Z" fill="#dae8fc" stroke="#6c8ebf" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1200 3620 L 1340 3620 L 1340 3460 L 980 3460 L 980 3365.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 980 3344.47 L 994 3372.47 L 980 3365.47 L 966 3372.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1560 3620 L 1560 3480 L 1940 3480 L 1940 3365.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1940 3344.47 L 1954 3372.47 L 1940 3365.47 L 1926 3372.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 2060 1820 L 2060 1740 L 1180 1740 L 1180 1605.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1180 1584.47 L 1194 1612.47 L 1180 1605.47 L 1166 1612.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 2300 1820 Q 2300 1700 2140 1700 Q 1980 1700 1980 1605.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1980 1584.47 L 1994 1612.47 L 1980 1605.47 L 1966 1612.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1940" y="1820" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 485px; margin-left: 486px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L2 Oracle</div></div></div></foreignObject><text x="545" y="489" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L2 Oracle</text></switch></g><path d="M 2260 2700 L 2260 2565.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2260 2544.47 L 2274 2572.47 L 2260 2565.47 L 2246 2572.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="2060" y="2700" width="400" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 705px; margin-left: 516px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L2 Engine API</div></div></div></foreignObject><text x="565" y="709" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L2 Engine API</text></switch></g><path d="M 1940 3100 L 1940 2565.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1940 2544.47 L 1954 2572.47 L 1940 2565.47 L 1926 2572.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 2260 3100 L 2260 2965.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2260 2944.47 L 2274 2972.47 L 2260 2965.47 L 2246 2972.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1780" y="3100" width="640" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 805px; margin-left: 446px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L2 OracleEngine</div></div></div></foreignObject><text x="525" y="809" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L2 OracleEngine</text></switch></g><path d="M 2100 2300 L 2100 2180 L 2180 2180 L 2180 2085.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2180 2064.47 L 2194 2092.47 L 2180 2085.47 L 2166 2092.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1940 2300 L 1940 2180 L 1580 2180 L 1580 2085.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1580 2064.47 L 1594 2092.47 L 1580 2085.47 L 1566 2092.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1780" y="2300" width="640" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 605px; margin-left: 446px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">OracleBackedL2Chain</div></div></div></foreignObject><text x="525" y="609" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">OracleBackedL2Chain</text></switch></g><rect x="1900" y="20" width="435" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-dasharray="12 12" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 107px; height: 1px; padding-top: 35px; margin-left: 476px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L2 pre-image<br />fetcher</div></div></div></foreignObject><text x="529" y="39" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L2 pre-image...</text></switch></g><rect x="1220" y="1820" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 485px; margin-left: 306px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Main configuration: chain and rollup configs</div></div></div></foreignObject><text x="365" y="489" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Main configuration:...</text></switch></g><path d="M 1060 860 L 1060 914.53" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1060 935.53 L 1046 907.53 L 1060 914.53 L 1074 907.53 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="820" y="620" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 185px; margin-left: 206px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Preimage KV Store</div></div></div></foreignObject><text x="265" y="189" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Preimage KV Store</text></switch></g><path d="M 980 3100 L 980 2180 L 1340 2180 L 1340 2085.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1340 2064.47 L 1354 2092.47 L 1340 2085.47 L 1326 2092.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 660 3100 L 660 2085.14" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 660 2064.14 L 674 2092.14 L 660 2085.14 L 646 2092.14 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="500" y="3100" width="640" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 805px; margin-left: 126px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L1 OracleEthClient</div></div></div></foreignObject><text x="205" y="809" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L1 OracleEthClient</text></switch></g><path d="M 420 3620 L 420 1460 L 794.53 1460" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 815.53 1460 L 787.53 1474 L 794.53 1460 L 787.53 1446 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 660 3620 L 660 3365.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 660 3344.47 L 674 3372.47 L 660 3365.47 L 646 3372.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="300" y="3620" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 935px; margin-left: 76px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">prologue:<br />dispute and<br />L1 lookup</div></div></div></foreignObject><text x="135" y="939" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">prologue:...</text></switch></g><path d="M 1180 1340 L 1180 1205.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1180 1184.47 L 1194 1212.47 L 1180 1205.47 L 1166 1212.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="820" y="1340" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 365px; margin-left: 206px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Pre-image Oracle<br />Client</div></div></div></foreignObject><text x="265" y="369" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pre-image Oracle...</text></switch></g><path d="M 740 1820 L 740 1740 L 940 1740 L 940 1605.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 940 1584.47 L 954 1612.47 L 940 1605.47 L 926 1612.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 860 1820 Q 860 1780 1300 1780 Q 1740 1780 1740 1605.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1740 1584.47 L 1754 1612.47 L 1740 1605.47 L 1726 1612.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="500" y="1820" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 485px; margin-left: 126px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L1 Oracle</div></div></div></foreignObject><text x="185" y="489" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L1 Oracle</text></switch></g><path d="M 2180 3620 L 2180 3480 L 2260 3480 L 2260 3365.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 2260 3344.47 L 2274 3372.47 L 2260 3365.47 L 2246 3372.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1900" y="3620" width="560" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 935px; margin-left: 476px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">epilogue:<br />output root construction<br />&amp; claim check</div></div></div></foreignObject><text x="545" y="939" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">epilogue:...</text></switch></g><rect x="2620" y="1340" width="880" height="720" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 218px; height: 1px; padding-top: 342px; margin-left: 657px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 18px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div style="font-size: 18px;"><b>Program Client</b>:</div><div style="font-size: 18px;">- stateless<br /></div><div style="font-size: 18px;">- no temp errors</div><div style="font-size: 18px;">- no environment access<br />- onchain<br style="font-size: 18px;" /></div></div></div></div></foreignObject><text x="657" y="360" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="18px">Program Client:...</text></switch></g><rect x="2620" y="580" width="920" height="600" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 228px; height: 1px; padding-top: 220px; margin-left: 657px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 18px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div style="font-size: 18px;"><b>Program Host / VM:</b><br /></div><div style="font-size: 18px;">- stateful</div><div>- pre-image store on disk<br />- offchain<br /></div></div></div></div></foreignObject><text x="657" y="225" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="18px">Program Host / VM:...</text></switch></g><rect x="2550" y="3500" width="760" height="160" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 895px; margin-left: 733px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 23px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">execution trace</div></div></div></foreignObject><text x="733" y="902" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="23px" text-anchor="middle" font-weight="bold">execution trace</text></switch></g><path d="M 180 1260 L 3380 1260" fill="none" stroke="#ff0000" stroke-width="12" stroke-miterlimit="10" stroke-dasharray="36 36" pointer-events="stroke"/><path d="M 1860 1340 L 1860 1085.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" stroke-dasharray="12 12" pointer-events="stroke"/><path d="M 1860 1064.47 L 1874 1092.47 L 1860 1085.47 L 1846 1092.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1620" y="1340" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 365px; margin-left: 406px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Pre-image Hint<br />Writer</div></div></div></foreignObject><text x="465" y="369" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pre-image Hint...</text></switch></g><rect x="1020" y="3620" width="720" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 935px; margin-left: 256px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">derivation loop</div></div></div></foreignObject><text x="345" y="939" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">derivation loop</text></switch></g><path d="M 1860 820 L 1860 485.47" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" stroke-dasharray="12 12" pointer-events="stroke"/><path d="M 1860 464.47 L 1874 492.47 L 1860 485.47 L 1846 492.47 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1620" y="820" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-dasharray="12 12" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 235px; margin-left: 406px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Pre-image Hint<br />Reader</div></div></div></foreignObject><text x="465" y="239" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pre-image Hint...</text></switch></g><path d="M 940 1180 L 940 1314.53" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 940 1335.53 L 926 1307.53 L 940 1314.53 L 954 1307.53 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="820" y="940" width="480" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 265px; margin-left: 206px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Pre-image Oracle<br />Server</div></div></div></foreignObject><text x="265" y="269" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pre-image Oracle...</text></switch></g><rect x="2620" y="100" width="690" height="340" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 171px; height: 1px; padding-top: 107px; margin-left: 657px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 18px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Program tools:</b><br />- pre-image fetching<br />- retry on fetch errors</div></div></div></foreignObject><text x="657" y="107" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="18px">Program tools:...</text></switch></g><rect x="1385" y="20" width="395" height="240" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-dasharray="12 12" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 97px; height: 1px; padding-top: 35px; margin-left: 347px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">L1 pre-image<br />fetcher</div></div></div></foreignObject><text x="396" y="39" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">L1 pre-image...</text></switch></g><path d="M 1622.5 460 L 1622.33 740 L 1325.47 740" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" stroke-dasharray="12 12" pointer-events="stroke"/><path d="M 1304.47 740 L 1332.47 726 L 1325.47 740 L 1332.47 754 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 1622.5 360 L 1623.3 285.71" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" stroke-dasharray="12 12" pointer-events="stroke"/><path d="M 1623.53 264.71 L 1637.23 292.86 L 1623.3 285.71 L 1609.23 292.56 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><path d="M 2097.5 360 L 2098.13 292.19" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" stroke-dasharray="12 12" pointer-events="stroke"/><path d="M 2098.32 271.19 L 2112.06 299.32 L 2098.13 292.19 L 2084.06 299.06 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-miterlimit="10" pointer-events="all"/><rect x="1385" y="360" width="950" height="100" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-dasharray="12 12" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 236px; height: 1px; padding-top: 103px; margin-left: 347px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Pre-image hint router</div></div></div></foreignObject><text x="465" y="106" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Pre-image hint router</text></switch></g><path d="M 180 540 L 3380 540" fill="none" stroke="#ff0000" stroke-width="12" stroke-miterlimit="10" stroke-dasharray="36 36" pointer-events="stroke"/><rect x="1880" y="1020" width="760" height="320" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)scale(4)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 188px; height: 1px; padding-top: 295px; margin-left: 472px;"><div style="box-sizing: border-box; font-size: 0px; text-align: left;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-style: italic; white-space: normal; overflow-wrap: normal;">No-op when onchain / readonly</div></div></div></foreignObject><text x="472" y="299" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="14px" font-style="italic">No-op when onchain / readon...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file
# Fault Proof
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Overview](#overview)
- [Pre-image Oracle](#pre-image-oracle)
- [Pre-image key types](#pre-image-key-types)
- [Type `0`: Zero key](#type-0-zero-key)
- [Type `1`: Local key](#type-1-local-key)
- [Type `2`: Global keccak256 key](#type-2-global-keccak256-key)
- [Type `3`: Global generic key](#type-3-global-generic-key)
- [Type `4-128`: reserved range](#type-4-128-reserved-range)
- [Type `129-255`: application usage](#type-129-255-application-usage)
- [Bootstrapping](#bootstrapping)
- [Hinting](#hinting)
- [Pre-image communication](#pre-image-communication)
- [Fault Proof Program](#fault-proof-program)
- [Prologue](#prologue)
- [Main content](#main-content)
- [Epilogue](#epilogue)
- [Pre-image hinting routes](#pre-image-hinting-routes)
- [`l1-header <blockhash>`](#l1-header-blockhash)
- [`l1-transactions <blockhash>`](#l1-transactions-blockhash)
- [`l1-receipts <blockhash>`](#l1-receipts-blockhash)
- [`l2-header <blockhash>`](#l2-header-blockhash)
- [`l2-transactions <blockhash>`](#l2-transactions-blockhash)
- [`l2-code <codehash>`](#l2-code-codehash)
- [`l2-state-node <nodehash>`](#l2-state-node-nodehash)
- [Fault Proof VM](#fault-proof-vm)
- [Fault Proof Interactive Dispute Game](#fault-proof-interactive-dispute-game)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Overview
A fault proof, also known as fraud proof or interactive game, consists of 3 components:
- [Program]: given a commitment to all rollup inputs (L1 data) and the dispute, verify the dispute statelessly.
- [VM]: given a stateless program and its inputs, trace any instruction step, and prove it on L1.
- [Interactive Dispute Game]: bisect a dispute down to a single instruction, and resolve the base-case using the VM.
Each of these 3 components may have different implementations, which can be combined into different proof stacks,
and contribute to proof diversity when resolving a dispute.
"Stateless execution" of the program, and its individual instructions, refers to reproducing
the exact same computation by authenticating the inputs with a [Pre-image Oracle][oracle].
![Diagram of Program and VM architecture](./assets/fault-proof.svg)
## Pre-image Oracle
[oracle]: #Pre-image-Oracle
The pre-image oracle is the only form of communication between
the [Program] (in the [Client](#client) role) and the [VM] (in the [Server](#server) role).
The program uses the pre-image oracle to query any input data that is understood to be available to the user:
- The initial inputs to bootstrap the program. See [Bootstrapping](#bootstrapping).
- External data not already part of the program code. See [Pre-image hinting routes](#pre-image-hinting-routes).
The communication happens over a simple request-response wire protocol,
see [Pre-image communcation](#pre-image-communication).
### Pre-image key types
Pre-images are identified by a `bytes32` type-prefixed key:
- The first byte identifies the type of request.
- The remaining 31 bytes identify the pre-image key.
#### Type `0`: Zero key
The zero prefix is illegal. This ensures all pre-image keys are non-zero,
enabling storage lookup optimizations and avoiding easy mistakes with invalid zeroed keys in the EVM.
#### Type `1`: Local key
Information specific to the dispute: the remainder of the key may be an index, a string, a hash, etc.
Only the contract(s) managing this dispute instance may serve the value for this key:
it is localized and context-dependent.
This type of key is used for program bootstrapping, to identify the initial input arguments by index or name.
#### Type `2`: Global keccak256 key
This type of key uses a global pre-image store contract, and is fully context-independent and permissionless.
I.e. every key must have a single unique value, regardless of chain history or time.
Using a global store reduces duplicate pre-image registration work,
and avoids unnecessary contract redeployments per dispute.
This global store contract should be non-upgradeable.
Since `keccak256` is a safe 32-byte hash input, the first bit is overwritten with a `2` to derive the key,
while keeping the rest of the key "readable" (matching the original hash).
#### Type `3`: Global generic key
Reserved. This scheme allows for unlimited application-layer pre-image types without fault-proof VM redeployments.
This is a generic version of a global key store: `key = 0x03 ++ keccak256(x, sender)[1:]`, where:
- `x` is a `bytes32`, which can be a hash of an arbitrary-length type of cryptographically secure commitment.
- `sender` is a `bytes32` identifying the pre-image inserter address (left-padded to 32 bytes)
This global store contract should be non-upgradeable.
The global contract is permissionless: users can standardize around external contracts that verify pre-images
(i.e. a specific `sender` will always be trusted for a specific kind of pre-image).
The external contract verifies the pre-image before inserting it into the global store for usage by all
fault proof VMs without requiring the VM or global store contract to be changed.
Users may standardize around upgradeable external pre-image contracts,
in case the implementation of the verification of the pre-image is expected to change.
The store update function is `update(x bytes32, offset uint64, span uint8, value bytes32)`:
- `x` is the `bytes32` `x` that the pre-image `key` is computed with.
- Only part of the pre-image, starting at `offset`, and up to (incl.) 32 bytes `span` can be inserted at a time.
- Pre-images may have an undefined length (e.g. a stream), we only need to know how many bytes of `value` are usable.
- The key and offset will be hashed together to uniquely store the `value` and `span`, for later pre-image serving.
This enables fault proof programs to adopt any new pre-image schemes without VM update or contract redeployment.
It is up to the user to index the special pre-image values by this key scheme,
as there is no way to revert it to the original commitment without knowing said commitment or value.
#### Type `4-128`: reserved range
Range start and and both inclusive.
This range of key types is reserved for future usage by the core protocol.
E.g. version changes, contract migrations, chain-data, additional core features, etc.
`128` specifically (`1000 0000` in binary) is reserved for key-type length-extension
(reducing the content part to `30` or less key bytes), if the need arises.
#### Type `129-255`: application usage
This range of key types may be used by forks or customized versions of the fault proof protocol.
### Bootstrapping
Initial inputs are deterministic, but not necessarily singular or global:
there may be multiple different disputes at the same time, each with its own disputed claims and L1 context.
To bootstrap, the program requests the initial inputs from the VM, using pre-image key type `1`.
The VM is aware of the external context, and maps requested pre-image keys based on their type, i.e.
a local lookup for type `1`, or global one for `2`, and optionally support other key-types.
### Hinting
There is one more form of optional communication between client and server: pre-image hinting.
Hinting is optional, and *is a no-op* in a L1 VM implementation.
The hint itself comes at very low cost onchain: the hint can be a single `write` sys-call,
which is instant as the memory to write as hint does not actually need to be loaded as part of the onchain proof.
Hinting allows the program, when generating a proof offchain,
to instruct the VM what data it is interested in.
The VM can choose to execute the requested hint at any time: either locally (for standard requests),
or in a modular form by redirecting the hint to tooling that may come with the VM program.
Hints do not have to be executed directly: they may first just be logged to show the intents of the program,
and the latest hint may be buffered for lazy execution, or dropped entirely when in read-only mode (like onchain).
When the pre-image oracle serves a request, and the request cannot be served from an existing collection of pre-images
(e.g. a local pre-image cache) then the VM can execute the hint to retrieve the missing pre-image(s).
It is the responsiblity of the program to provide sufficient hinting for every pre-image request.
Some hints may have to be repeated: the VM only has to execute the last hint when handling a missing pre-image.
Note that hints may produce multiple pre-images:
e.g. a hint for an ethereum block with transaction list may prepare pre-images for the header,
each of the transactions, and the intermediate merkle-nodes that form the transactions-list Merkle Patricia Trie.
Hinting is implemented with a minimal wire-protocol over a blocking one-way stream:
```text
<request> := <length prefix> <hint bytes> <end>
<length prefix> := big-endian uint32 # length of <hint bytes>
<hint bytes> := byte sequence
<end> := 0 byte
```
The `<end>` trailing zero byte allows the server to block the program
(since the communication is blocking) until the hint is processed.
### Pre-image communication
Pre-images are communicated with a minimal wire-protocol over a blocking two-way stream.
This protocol can be implemented with blocking read/write syscalls.
```text
<request> := <bytes32> # the type-prefixed pre-image key
<response> := <length prefix> <pre-image bytes>
<length prefix> := big-endian uint64 # length of <pre-image bytes>, note: uint64
<hint bytes> := byte sequence #
```
The `<length prefix>` here may be arbitrarily high:
the client can stop reading at any time if the required part of the pre-image has been read.
After the client writes new `<request>` bytes, the server should be prepared to respond with
the pre-image starting from `offset == 0` upon `read` calls.
The server may limit `read` results artificially to only a small amount of bytes at a time,
even though the full pre-image is ready: this is expected regular IO protocol,
and the client will just have to continue to read the small results at a time,
until 0 bytes are read, indicating EOF.
This enables the server to serve e.g. at most 32 bytes at a time or align reads with VM memory structure,
to limit the amount of VM state that changes per syscall instruction,
and thus keep the proof size per instruction bounded.
## Fault Proof Program
[Program]: #Fault-Proof-Program
The Fault Proof Program defines the verification of claims of the state-transition outputs
of the L2 rollup as a pure function of L1 data.
The `op-program` is the reference implementation of the program, based on `op-node` and `op-geth` implementations.
The program consists of:
- Prologue: load the inputs, given minimal bootstrapping, with possible test-overrides.
- Main content: process the L2 state-transition, i.e. derive the state changes from the L1 inputs.
- Epilogue: inspect the state changes to verify the claim.
### Prologue
The program is bootstrapped with two primary inputs:
- `l1_head`: the L1 block hash that will be perceived as the tip of the L1 chain,
authenticating all prior L1 history.
- `dispute`: identity of the claim to verify.
Bootstrapping happens through special input requests to the host of the program.
Additionally, there are *implied* inputs, which are *derived from the above primary inputs*,
but can be overridden for testing purposes:
- `l2_head`: the L2 block hash that will be perceived as the previously agreed upon tip of the L2 chain,
authenticating all prior L2 history.
- Chain configurations: chain configuration may be baked into the program,
or determined from attributes of the identified `dispute` on L1.
- `l1_chain_config`: The chain-configuration of the L1 chain (also known as `l1_genesis.json`)
- `l2_chain_config`: The chain-configuration of the L2 chain (also known as `l2_genesis.json`)
- `rollup_config`: The rollup configuration used by the rollup-node (also known as `rollup.json`)
The implied inputs rely on L1-introspection to load attributes of the `dispute` through the
[dispute game interface](./dispute-game-interface.md), in the L1 history up and till the specified `l1_head`.
The `dispute` may be the claim itself, or a pointer to specific prior claimed data in L1,
depending on the dispute game interface.
Implied inputs are loaded in a "prologue" before the actual core state-transition function executes.
During testing a simplified prologue that loads the overrides may be used.
> Note: only the test-prologues are currently supported, since the dispute game interface is actively changing.
### Main content
To verify a claim about L2 state, the program first reproduces
the L2 state by applying L1 data to prior agreed L2 history.
This process is also known as the [L2 derivation process](./derivation.md),
and matches the processing in the [rollup node](./rollup-node.md) and [execution-engine](./exec-engine.md).
The difference is that rather than retrieving inputs from an RPC and applying state changes to disk,
the inputs are loaded through the [pre-image oracle][oracle] and the changes accumulate in memory.
The derivation executes with two data-sources:
- Interface to read-only L1 chain, backed by the pre-image oracle:
- The `l1_head` determines the view over the available L1 data: no later L1 data is available.
- The implementation of the chain traverses the header-chain from the `l1_head` down to serve by-number queries.
- The `l1_head` is the L1 unsafe head, safe head, and finalized head.
- Interface to L2 engine API
- Prior L2 chain history is backed by the pre-image oracle, similar to the L1 chain:
- The initial `l2_head` determines the view over the initial available L2 history: no later L2 data is available.
- The implementation of the chain traverses the header-chain from the `l2_head` down to serve by-number queries.
- The `l2_head` is the initial L2 unsafe head, safe head, and finalized head.
- New L2 chain history accumulates in memory.
- Although the pre-image oracle can be used to retrieve data by hash if memory is limited,
the program should prefer to keep the newly created chain data in memory, to minimize pre-image oracle access.
- The L2 unsafe head, safe head, and finalized L2 head will potentially change as derivation progresses.
- L2 state consists of the diff of changes in memory,
and any unchanged state nodes accessible through the read-only L2 history view.
See [Pre-image routes](#pre-image-routes) for specifications of the pre-image oracle backing of these data sources.
Using these data-sources, the derivation pipeline is processed till we hit one of two conditions:
- `EOF`: when we run out of L1 data, the L2 chain will not change further, and the epilogue can start.
- Eager epilogue condition: depending on the type of claim to verify,
if the L2 result irreversible (i.e. no later L1 inputs can override it),
the processing may end early when the result is ready.
E.g. when asserting state at a specific L2 block, rather than the very tip of the L2 chain.
### Epilogue
While the main-content produces the disputed L2 state already,
the epilogue concludes what this means for the disputed claim.
The program produces a binary output to verify the claim, using a standard single-byte Unix exit-code:
- a `0` for success, i.e. the claim is correct.
- a non-zero code for failure, i.e. the claim is incorrect.
- `1` should be preferred for identifying an incorrect claim.
- Other non-zero exit codes may indicate runtime failure,
e.g. a bug in the program code may resolve in a kind of `panic` or unexpected error.
Safety should be preferred over liveness in this case, and the `claim` will fail.
To assert the disputed claim, the epilogue, like the main content,
can introspect L1 and L2 chain data and post-process it further,
to then make a statement about the claim with the final exit code.
A disputed output-root may be disproven by first producing the output-root, and then comparing it:
1. Retrieve the output attributes from the L2 chain view: the state-root, block-hash, withdrawals storage-root.
2. Compute the output-root, as the [proposer should compute it](./proposals.md#l2-output-commitment-construction).
3. If the output-root matches the `claim`, exit with code 0. Otherwise, exit with code 1.
> Note: the dispute game interface is actively changing, and may require additional claim assertions.
> the output-root epilogue may be replaced or extended for general L2 message proving.
### Pre-image hinting routes
The fault proof program implements hint handling for the VM to use,
as well as any program testing outside of VM environment.
This can be exposed via a CLI, or alternative inter-process API.
Every instance of `<blockhash>` in the below routes is `0x`-prefixed, lowercase, hex-encoded.
#### `l1-header <blockhash>`
Requests the host to prepare the L1 block header RLP pre-image of the block `<blockhash>`.
#### `l1-transactions <blockhash>`
Requests the host to prepare the list of transactions of the L1 block with `<blockhash>`:
prepare the RLP pre-images of each of them, including transactions-list MPT nodes.
#### `l1-receipts <blockhash>`
Requests the host to prepare the list of receipts of the L1 block with `<blockhash>`:
prepare the RLP pre-images of each of them, including receipts-list MPT nodes.
#### `l2-header <blockhash>`
Requests the host to prepare the L2 block header RLP pre-image of the block `<blockhash>`.
#### `l2-transactions <blockhash>`
Requests the host to prepare the list of transactions of the L2 block with `<blockhash>`:
prepare the RLP pre-images of each of them, including transactions-list MPT nodes.
#### `l2-code <codehash>`
Requests the host to prepare the L2 smart-contract code with the given `<codehash>`.
#### `l2-state-node <nodehash>`
Requests the host to prepare the L2 MPT node preimage with the given `<nodehash>`.
## Fault Proof VM
[VM]: #Fault-Proof-VM
A fault proof VM implements:
- a smart-contract to verify a single execution-trace step, e.g. a single MIPS instruction.
- a CLI command to generate a proof of a single execution-trace step.
- a CLI command to compute a VM state-root at step N
A fault proof VM relies on a fault proof program to provide an interface
for fetching any missing pre-images based on hints.
The VM emulates the program, as prepared for the VM target architecture,
and generates the state-root or instruction proof data as requested through the VM CLI.
Refer to the documentation of the fault proof VM for further usage information.
Fault Proof VMs:
- [Cannon]: big-endian 32-bit MIPS proof, by OP Labs, in active development.
- [Asterisc]: little-endian 64-bit RISC-V proof, by `@protolambda`, in active development.
[Cannon]: https://github.com/ethereum-optimism/cannon
[Asterisc]: https://github.com/protolambda/asterisc
## Fault Proof Interactive Dispute Game
[Interactive Dispute Game]: #Fault-Proof-Interactive-Dispute-Game
The interactive dispute game allows actors to resolve a dispute with an onchain challenge-response game
that bisects the execution trace of the VM, bounded with a base-case that proves a VM trace step.
The game is multi-player: different non-aligned actors may participate when bonded.
Response time is allocated based on the remaining time in the branch of the tree and alignment with the claim.
The allocated response time is limited by the dispute-game window,
and any additional time necessary based on L1 fee changes when bonds are insufficient.
> Note: the timed, bonded, bisection dispute game is in development.
> Also see [dispute-game specs](./dispute-game.md) for general dispute game system specifications,
> And [dispute-game-interface specs](./dispute-game-interface.md) for dispute game interface specifications.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment