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

Merge branch 'develop' into opstack-docs

parents ad281069 35d4a37c
...@@ -49,7 +49,7 @@ type TypesWithdrawalTransaction struct { ...@@ -49,7 +49,7 @@ type TypesWithdrawalTransaction struct {
// OptimismPortalMetaData contains all meta data concerning the OptimismPortal contract. // OptimismPortalMetaData contains all meta data concerning the OptimismPortal contract.
var OptimismPortalMetaData = &bind.MetaData{ var OptimismPortalMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"contractL2OutputOracle\",\"name\":\"_l2Oracle\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_guardian\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"opaqueData\",\"type\":\"bytes\"}],\"name\":\"TransactionDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"WithdrawalFinalized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"WithdrawalProven\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BASE_FEE_MAX_CHANGE_DENOMINATOR\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ELASTICITY_MULTIPLIER\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARDIAN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INITIAL_BASE_FEE\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L2_ORACLE\",\"outputs\":[{\"internalType\":\"contractL2OutputOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAXIMUM_BASE_FEE\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_RESOURCE_LIMIT\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINIMUM_BASE_FEE\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TARGET_RESOURCE_LIMIT\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"_isCreation\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"depositTransaction\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"donateETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"_tx\",\"type\":\"tuple\"}],\"name\":\"finalizeWithdrawalTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"finalizedWithdrawals\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l2OutputIndex\",\"type\":\"uint256\"}],\"name\":\"isOutputFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Sender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"params\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"prevBaseFee\",\"type\":\"uint128\"},{\"internalType\":\"uint64\",\"name\":\"prevBoughtGas\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"prevBlockNum\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"_tx\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_l2OutputIndex\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"latestBlockhash\",\"type\":\"bytes32\"}],\"internalType\":\"structTypes.OutputRootProof\",\"name\":\"_outputRootProof\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"_withdrawalProof\",\"type\":\"bytes[]\"}],\"name\":\"proveWithdrawalTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"provenWithdrawals\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"outputRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint128\",\"name\":\"timestamp\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"l2OutputIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", ABI: "[{\"inputs\":[{\"internalType\":\"contractL2OutputOracle\",\"name\":\"_l2Oracle\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_guardian\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"opaqueData\",\"type\":\"bytes\"}],\"name\":\"TransactionDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"WithdrawalFinalized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"withdrawalHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"WithdrawalProven\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BASE_FEE_MAX_CHANGE_DENOMINATOR\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ELASTICITY_MULTIPLIER\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARDIAN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INITIAL_BASE_FEE\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L2_ORACLE\",\"outputs\":[{\"internalType\":\"contractL2OutputOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAXIMUM_BASE_FEE\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_RESOURCE_LIMIT\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINIMUM_BASE_FEE\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TARGET_RESOURCE_LIMIT\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"_gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"_isCreation\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"depositTransaction\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"donateETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"_tx\",\"type\":\"tuple\"}],\"name\":\"finalizeWithdrawalTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"finalizedWithdrawals\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_paused\",\"type\":\"bool\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l2OutputIndex\",\"type\":\"uint256\"}],\"name\":\"isOutputFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2Sender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"params\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"prevBaseFee\",\"type\":\"uint128\"},{\"internalType\":\"uint64\",\"name\":\"prevBoughtGas\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"prevBlockNum\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"_tx\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_l2OutputIndex\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"latestBlockhash\",\"type\":\"bytes32\"}],\"internalType\":\"structTypes.OutputRootProof\",\"name\":\"_outputRootProof\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"_withdrawalProof\",\"type\":\"bytes[]\"}],\"name\":\"proveWithdrawalTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"provenWithdrawals\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"outputRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint128\",\"name\":\"timestamp\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"l2OutputIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
Bin: "0x6101206040523480156200001257600080fd5b50604051620059073803806200590783398101604081905262000035916200028e565b6001608052600260a052600060c0526001600160a01b0380841660e05282166101005262000063816200006c565b505050620002e6565b600054610100900460ff16158080156200008d5750600054600160ff909116105b80620000bd5750620000aa30620001c360201b62001fb61760201c565b158015620000bd575060005460ff166001145b620001265760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156200014a576000805461ff0019166101001790555b603280546001600160a01b03191661dead1790556035805483151560ff1990911617905562000178620001d2565b8015620001bf576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b03163b151590565b600054610100900460ff166200023f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016200011d565b60408051606081018252633b9aca0080825260006020830152436001600160401b031691909201819052600160c01b0217600155565b6001600160a01b03811681146200028b57600080fd5b50565b600080600060608486031215620002a457600080fd5b8351620002b18162000275565b6020850151909350620002c48162000275565b60408501519092508015158114620002db57600080fd5b809150509250925092565b60805160a05160c05160e051610100516155a4620003636000396000818161035701528181610ad201526113d50152600081816101c101528181610d3b01528181610f1c01528181611331015281816116eb0152818161195d015261227c0152600061129c015260006112730152600061124a01526155a46000f3fe6080604052600436106101835760003560e01c80638456cb59116100d6578063ca3e99ba1161007f578063d53a822f11610059578063d53a822f146104ec578063e965084c1461050c578063e9e05c421461059857600080fd5b8063ca3e99ba14610421578063cd7c978914610436578063cff0ab961461044b57600080fd5b80638c3152e9116100b05780638c3152e9146103a45780639bf62d82146103c4578063a14238e7146103f157600080fd5b80638456cb5914610379578063867ead131461038e5780638b4c40b0146101a857600080fd5b80635c1f2827116101385780636bb0291e116101125780636bb0291e146103105780636dbffb7814610325578063724c184c1461034557600080fd5b80635c1f28271461029d5780635c975abb146102cf57806364b79208146102f957600080fd5b80633f4ba83a116101695780633f4ba83a146102465780634870496f1461025b57806354fd4d501461027b57600080fd5b80621c2ff6146101af57806313620abd1461020d57600080fd5b366101aa576101a83334620186a06000604051806020016040528060008152506105a6565b005b600080fd5b3480156101bb57600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561021957600080fd5b50610225633b9aca0081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610204565b34801561025257600080fd5b506101a8610aba565b34801561026757600080fd5b506101a8610276366004614c39565b610bdd565b34801561028757600080fd5b50610290611243565b6040516102049190614d8f565b3480156102a957600080fd5b506102c16fffffffffffffffffffffffffffffffff81565b604051908152602001610204565b3480156102db57600080fd5b506035546102e99060ff1681565b6040519015158152602001610204565b34801561030557600080fd5b506102c1627a120081565b34801561031c57600080fd5b506102c1600481565b34801561033157600080fd5b506102e9610340366004614da2565b6112e6565b34801561035157600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561038557600080fd5b506101a86113bd565b34801561039a57600080fd5b506102c161271081565b3480156103b057600080fd5b506101a86103bf366004614dbb565b6114dd565b3480156103d057600080fd5b506032546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103fd57600080fd5b506102e961040c366004614da2565b60336020526000908152604090205460ff1681565b34801561042d57600080fd5b506102c1611db8565b34801561044257600080fd5b506102c1600881565b34801561045757600080fd5b506001546104b3906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff9283166020850152911690820152606001610204565b3480156104f857600080fd5b506101a8610507366004614e00565b611dc9565b34801561051857600080fd5b5061056a610527366004614da2565b603460205260009081526040902080546001909101546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041683565b604080519384526fffffffffffffffffffffffffffffffff9283166020850152911690820152606001610204565b6101a86105a6366004614e1b565b8260005a9050831561065d5773ffffffffffffffffffffffffffffffffffffffff87161561065d57604080517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260248101919091527f4f7074696d69736d506f7274616c3a206d7573742073656e6420746f2061646460448201527f72657373283029207768656e206372656174696e67206120636f6e747261637460648201526084015b60405180910390fd5b6152088567ffffffffffffffff1610156106f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4f7074696d69736d506f7274616c3a20676173206c696d6974206d757374206360448201527f6f76657220696e737472696e7369632067617320636f737400000000000000006064820152608401610654565b3332811461071a575033731111000000000000000000000000000000001111015b60003488888888604051602001610735959493929190614ea0565b604051602081830303815290604052905060008973ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32846040516107a59190614d8f565b60405180910390a450506001546000906107e5907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1643614f34565b905080156109195760006107fd6004627a1200614f7a565b6001546108289190700100000000000000000000000000000000900467ffffffffffffffff16614fe2565b90506000600861083c6004627a1200614f7a565b6108469190615056565b6001546108669084906fffffffffffffffffffffffffffffffff16615056565b6108709190614f7a565b6001549091506000906108b39061089a9084906fffffffffffffffffffffffffffffffff16615112565b6127106fffffffffffffffffffffffffffffffff611fd2565b905060018411156108da576108d761089a8260086108d2600189614f34565b611ff1565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b6001805484919060109061094c908490700100000000000000000000000000000000900467ffffffffffffffff16615186565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550627a1200600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff161315610a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5265736f757263654d65746572696e673a2063616e6e6f7420627579206d6f7260448201527f6520676173207468616e20617661696c61626c6520676173206c696d697400006064820152608401610654565b600154600090610a54906fffffffffffffffffffffffffffffffff1667ffffffffffffffff86166151b2565b6fffffffffffffffffffffffffffffffff1690506000610a7848633b9aca00612046565b610a8290836151ea565b905060005a610a919086614f34565b905080821115610aad57610aad610aa88284614f34565b61205d565b5050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610b7f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e20756e706175736500000000000000000000000000000000000000000000006064820152608401610654565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60355460ff1615610c4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610654565b3073ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff1603610d09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a20796f752063616e6e6f742073656e642060448201527f6d6573736167657320746f2074686520706f7274616c20636f6e7472616374006064820152608401610654565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018590526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610d97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbb919061521e565b519050610dd5610dd036869003860186615283565b61208b565b8114610e63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a20696e76616c6964206f7574707574207260448201527f6f6f742070726f6f6600000000000000000000000000000000000000000000006064820152608401610654565b6000610e6e876120e7565b6000818152603460209081526040918290208251606081018452815481526001909101546fffffffffffffffffffffffffffffffff8082169383018490527001000000000000000000000000000000009091041692810192909252919250901580610fa05750805160408083015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9c919061521e565b5114155b61102c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173682060448201527f68617320616c7265616479206265656e2070726f76656e0000000000000000006064820152608401610654565b60408051602081018490526000918101829052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012090830181905292506110f59101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f01000000000000000000000000000000000000000000000000000000000000006020830152906110eb888a6152e9565b8a60400135612117565b611181576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a20696e76616c696420776974686472617760448201527f616c20696e636c7573696f6e2070726f6f6600000000000000000000000000006064820152608401610654565b604080516060810182528581526fffffffffffffffffffffffffffffffff42811660208084019182528c831684860190815260008981526034835286812095518655925190518416700100000000000000000000000000000000029316929092176001909301929092558b830151908c0151925173ffffffffffffffffffffffffffffffffffffffff918216939091169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f629190a4505050505050505050565b606061126e7f000000000000000000000000000000000000000000000000000000000000000061213b565b6112977f000000000000000000000000000000000000000000000000000000000000000061213b565b6112c07f000000000000000000000000000000000000000000000000000000000000000061213b565b6040516020016112d29392919061536d565b604051602081830303815290604052905090565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018290526000906113b79073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a25ae55790602401606060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139c919061521e565b602001516fffffffffffffffffffffffffffffffff16612278565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e207061757365000000000000000000000000000000000000000000000000006064820152608401610654565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610bd3565b60355460ff161561154a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610654565b60325473ffffffffffffffffffffffffffffffffffffffff1661dead146115f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a2063616e206f6e6c79207472696767657260448201527f206f6e65207769746864726177616c20706572207472616e73616374696f6e006064820152608401610654565b60006115fe826120e7565b60008181526034602090815260408083208151606081018352815481526001909101546fffffffffffffffffffffffffffffffff808216948301859052700100000000000000000000000000000000909104169181019190915292935090036116e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206e60448201527f6f74206265656e2070726f76656e2079657400000000000000000000000000006064820152608401610654565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663887862726040518163ffffffff1660e01b8152600401602060405180830381865afa158015611754573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177891906153e3565b81602001516fffffffffffffffffffffffffffffffff161015611843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604b60248201527f4f7074696d69736d506f7274616c3a207769746864726177616c2074696d657360448201527f74616d70206c657373207468616e204c32204f7261636c65207374617274696e60648201527f672074696d657374616d70000000000000000000000000000000000000000000608482015260a401610654565b61186281602001516fffffffffffffffffffffffffffffffff16612278565b611914576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604560248201527f4f7074696d69736d506f7274616c3a2070726f76656e2077697468647261776160448201527f6c2066696e616c697a6174696f6e20706572696f6420686173206e6f7420656c60648201527f6170736564000000000000000000000000000000000000000000000000000000608482015260a401610654565b60408181015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa1580156119b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dd919061521e565b8251815191925014611a97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f4f7074696d69736d506f7274616c3a206f757470757420726f6f742070726f7660448201527f656e206973206e6f74207468652073616d652061732063757272656e74206f7560648201527f7470757420726f6f740000000000000000000000000000000000000000000000608482015260a401610654565b611ab681602001516fffffffffffffffffffffffffffffffff16612278565b611b68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f4f7074696d69736d506f7274616c3a206f75747075742070726f706f73616c2060448201527f66696e616c697a6174696f6e20706572696f6420686173206e6f7420656c617060648201527f7365640000000000000000000000000000000000000000000000000000000000608482015260a401610654565b60008381526033602052604090205460ff1615611c07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206160448201527f6c7265616479206265656e2066696e616c697a656400000000000000000000006064820152608401610654565b600083815260336020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055908601516032805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff00000000000000000000000000000000000000009092169190911790558501516080860151606087015160a0880151611ca99392919061231b565b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405190915084907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b90611d0e90841515815260200190565b60405180910390a280158015611d245750326001145b15611db1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4f7074696d69736d506f7274616c3a207769746864726177616c206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610654565b5050505050565b611dc66004627a1200614f7a565b81565b600054610100900460ff1615808015611de95750600054600160ff909116105b80611e035750303b158015611e03575060005460ff166001145b611e8f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610654565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611eed57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead179055603580548315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055611f4f612375565b8015611fb257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b6000611fe7611fe18585612458565b83612468565b90505b9392505050565b6000670de0b6b3a76400006120326120098583614f7a565b61201b90670de0b6b3a7640000614fe2565b61202d85670de0b6b3a7640000615056565b612477565b61203c9086615056565b611fe79190614f7a565b6000818310156120565781611fea565b5090919050565b6000805a90505b825a6120709083614f34565b10156120865761207f826153fc565b9150612064565b505050565b600081600001518260200151836040015184606001516040516020016120ca949392919093845260208401929092526040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b80516020808301516040808501516060860151608087015160a088015193516000976120ca979096959101615434565b600080612123866124a8565b9050612131818686866124da565b9695505050505050565b60608160000361217e57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156121a85780612192816153fc565b91506121a19050600a836151ea565b9150612182565b60008167ffffffffffffffff8111156121c3576121c3614a5f565b6040519080825280601f01601f1916602001820160405280156121ed576020820181803683370190505b5090505b841561227057612202600183614f34565b915061220f600a8661548b565b61221a90603061549f565b60f81b81838151811061222f5761222f6154b7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612269600a866151ea565b94506121f1565b949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f4daa2916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230991906153e3565b612313908361549f565b421192915050565b600080603f60c88601604002045a101561235e576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080845160208601878a5af19695505050505050565b600054610100900460ff1661240c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610654565b60408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b6000818312156120565781611fea565b60008183126120565781611fea565b6000611fea670de0b6b3a76400008361248f8661250a565b6124999190615056565b6124a39190614f7a565b61274e565b606081805190602001206040516020016124c491815260200190565b6040516020818303038152906040529050919050565b6000612501846124eb87868661298d565b8051602091820120825192909101919091201490565b95945050505050565b6000808213612575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610654565b6000606061258284613415565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361277f57506000919050565b680755bf798b4a1bf1e582126127f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610654565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b606060008451116129fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152606401610654565b6000612a05846134eb565b90506000612a12866135da565b9050600084604051602001612a2991815260200190565b60405160208183030381529060405290506000805b845181101561338c576000858281518110612a5b57612a5b6154b7565b602002602001015190508451831115612af6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152608401610654565b82600003612baf5780518051602091820120604051612b4492612b1e92910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b612baa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610654565b612d06565b805151602011612c655780518051602091820120604051612bd992612b1e92910190815260200190565b612baa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152608401610654565b805184516020808701919091208251919092012014612d06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152608401610654565b612d126010600161549f565b81602001515103612ef35784518303612e8b576000612d4e8260200151601081518110612d4157612d416154b7565b6020026020010151613775565b90506000815111612de1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610654565b60018751612def9190614f34565b8314612e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610654565b9650611fea95505050505050565b6000858481518110612e9f57612e9f6154b7565b602001015160f81c60f81b60f81c9050600082602001518260ff1681518110612eca57612eca6154b7565b60200260200101519050612edd816138d5565b9550612eea60018661549f565b94505050613379565b6002816020015151036132f1576000612f0b826138fa565b9050600081600081518110612f2257612f226154b7565b016020015160f81c90506000612f396002836154e6565b612f44906002615508565b90506000612f55848360ff1661391e565b90506000612f638a8961391e565b90506000612f718383613954565b905080835114613003576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610654565b60ff851660021480613018575060ff85166003145b1561320c57808251146130ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610654565b60006130c98860200151600181518110612d4157612d416154b7565b9050600081511161315c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610654565b60018d5161316a9190614f34565b89146131f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610654565b9c50611fea9b505050505050505050505050565b60ff8516158061321f575060ff85166001145b1561325e5761324b876020015160018151811061323e5761323e6154b7565b60200260200101516138d5565b9950613257818a61549f565b98506132e6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608401610654565b505050505050613379565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608401610654565b5080613384816153fc565b915050612a3e565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608401610654565b6000808211613480576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610654565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b805160609060008167ffffffffffffffff81111561350b5761350b614a5f565b60405190808252806020026020018201604052801561355057816020015b60408051808201909152606080825260208201528152602001906001900390816135295790505b50905060005b828110156135d257604051806040016040528086838151811061357b5761357b6154b7565b602002602001015181526020016135aa87848151811061359d5761359d6154b7565b6020026020010151613a03565b8152508282815181106135bf576135bf6154b7565b6020908102919091010152600101613556565b509392505050565b805160609060006135ec82600261552b565b67ffffffffffffffff81111561360457613604614a5f565b6040519080825280601f01601f19166020018201604052801561362e576020820181803683370190505b5090506000805b8381101561376b5785818151811061364f5761364f6154b7565b6020910101517fff000000000000000000000000000000000000000000000000000000000000008116925060041c7f0ff000000000000000000000000000000000000000000000000000000000000016836136ab83600261552b565b815181106136bb576136bb6154b7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f0f0000000000000000000000000000000000000000000000000000000000000082168361371983600261552b565b61372490600161549f565b81518110613734576137346154b7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101613635565b5090949350505050565b6060600080600061378585613a16565b9194509250905060008160018111156137a0576137a0615568565b1461382d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610654565b613837828461549f565b8551146138c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152608401610654565b61250185602001518484614483565b606060208260000151106138f1576138ec82613775565b6113b7565b6113b782614524565b60606113b76139198360200151600081518110612d4157612d416154b7565b6135da565b60608251821061393d57506040805160208101909152600081526113b7565b611fea838384865161394f9190614f34565b61453a565b6000806000835185511061396957835161396c565b84515b90505b80821080156139f3575083828151811061398b5761398b6154b7565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168583815181106139ca576139ca6154b7565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156135d25781600101915061396f565b60606113b7613a1183614712565b6147fb565b600080600080846000015111613ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610654565b6020840151805160001a607f8111613af957600060016000945094509450505061447c565b60b78111613d07576000613b0e608083614f34565b905080876000015111613bc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e6729000000000000000000000000000000000000608482015260a401610654565b6001838101517fff00000000000000000000000000000000000000000000000000000000000000169082141580613c4257507f80000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610155b613cf4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e672900000000000000000000000000000000000000608482015260a401610654565b506001955093506000925061447c915050565b60bf8111614055576000613d1c60b783614f34565b905080876000015111613dd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e6729000000000000000000000000000000608482015260a401610654565b60018301517fff00000000000000000000000000000000000000000000000000000000000000166000819003613eb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e672900000000000000000000000000000000000000000000608482015260a401610654565b600184015160088302610100031c60378111613f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e6729000000000000000000000000000000000000000000000000608482015260a401610654565b613f83818461549f565b895111614038576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e67290000000000000000000000000000000000000000608482015260a401610654565b61404383600161549f565b975095506000945061447c9350505050565b60f7811161413657600061406a60c083614f34565b905080876000015111614125576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c6973742900000000000000000000000000000000000000000000608482015260a401610654565b60019550935084925061447c915050565b600061414360f783614f34565b9050808760000151116141fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c6973742900000000000000000000000000000000000000608482015260a401610654565b60018301517fff000000000000000000000000000000000000000000000000000000000000001660008190036142dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c69737429000000000000000000000000000000000000000000000000608482015260a401610654565b600184015160088302610100031c603781116143a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c697374290000000000000000000000000000000000000000000000000000608482015260a401610654565b6143aa818461549f565b89511161445f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c6973742900000000000000000000000000000000000000000000608482015260a401610654565b61446a83600161549f565b975095506001945061447c9350505050565b9193909250565b606060008267ffffffffffffffff8111156144a0576144a0614a5f565b6040519080825280601f01601f1916602001820160405280156144ca576020820181803683370190505b509050826000036144dc579050611fea565b60006144e8858761549f565b90506020820160005b858110156145095782810151828201526020016144f1565b85811115614518576000868301525b50919695505050505050565b60606113b7826020015160008460000151614483565b60608182601f0110156145a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610654565b828284011015614615576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610654565b81830184511015614682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610654565b6060821580156146a15760405191506000825260208201604052614709565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156146da5780518352602092830192016146c2565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b604080518082019091526000808252602082015260008251116147dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610654565b50604080518082019091528151815260209182019181019190915290565b6060600080600061480b85613a16565b91945092509050600181600181111561482657614826615568565b146148b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610654565b84516148bf838561549f565b1461494c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152608401610654565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816149655790505090506000845b8751811015614a53576000806149d86040518060400160405280858d600001516149bc9190614f34565b8152602001858d602001516149d1919061549f565b9052613a16565b5091509150604051806040016040528083836149f4919061549f565b8152602001848c60200151614a09919061549f565b815250858581518110614a1e57614a1e6154b7565b6020908102919091010152614a3460018561549f565b9350614a40818361549f565b614a4a908461549f565b92505050614992565b50815295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614ad557614ad5614a5f565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b0157600080fd5b919050565b600082601f830112614b1757600080fd5b813567ffffffffffffffff811115614b3157614b31614a5f565b614b6260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a8e565b818152846020838601011115614b7757600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614ba657600080fd5b60405160c0810167ffffffffffffffff8282108183111715614bca57614bca614a5f565b8160405282935084358352614be160208601614add565b6020840152614bf260408601614add565b6040840152606085013560608401526080850135608084015260a0850135915080821115614c1f57600080fd5b50614c2c85828601614b06565b60a0830152505092915050565b600080600080600085870360e0811215614c5257600080fd5b863567ffffffffffffffff80821115614c6a57600080fd5b614c768a838b01614b94565b97506020890135965060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc084011215614caf57600080fd5b60408901955060c0890135925080831115614cc957600080fd5b828901925089601f840112614cdd57600080fd5b8235915080821115614cee57600080fd5b508860208260051b8401011115614d0457600080fd5b959894975092955050506020019190565b60005b83811015614d30578181015183820152602001614d18565b83811115614d3f576000848401525b50505050565b60008151808452614d5d816020860160208601614d15565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611fea6020830184614d45565b600060208284031215614db457600080fd5b5035919050565b600060208284031215614dcd57600080fd5b813567ffffffffffffffff811115614de457600080fd5b61227084828501614b94565b80358015158114614b0157600080fd5b600060208284031215614e1257600080fd5b611fea82614df0565b600080600080600060a08688031215614e3357600080fd5b614e3c86614add565b945060208601359350604086013567ffffffffffffffff8082168214614e6157600080fd5b819450614e7060608901614df0565b93506080880135915080821115614e8657600080fd5b50614e9388828901614b06565b9150509295509295909350565b8581528460208201527fffffffffffffffff0000000000000000000000000000000000000000000000008460c01b16604082015282151560f81b604882015260008251614ef4816049850160208701614d15565b919091016049019695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015614f4657614f46614f05565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614f8957614f89614f4b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615614fdd57614fdd614f05565b500590565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561501c5761501c614f05565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561505057615050614f05565b50500390565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561509757615097614f05565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156150d2576150d2614f05565b600087129250878205871284841616156150ee576150ee614f05565b8785058712818416161561510457615104614f05565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561514c5761514c614f05565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561518057615180614f05565b50500190565b600067ffffffffffffffff8083168185168083038211156151a9576151a9614f05565b01949350505050565b60006fffffffffffffffffffffffffffffffff808316818516818304811182151516156151e1576151e1614f05565b02949350505050565b6000826151f9576151f9614f4b565b500490565b80516fffffffffffffffffffffffffffffffff81168114614b0157600080fd5b60006060828403121561523057600080fd5b6040516060810181811067ffffffffffffffff8211171561525357615253614a5f565b60405282518152615266602084016151fe565b6020820152615277604084016151fe565b60408201529392505050565b60006080828403121561529557600080fd5b6040516080810181811067ffffffffffffffff821117156152b8576152b8614a5f565b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b600067ffffffffffffffff8084111561530457615304614a5f565b8360051b6020615315818301614a8e565b86815291850191818101903684111561532d57600080fd5b865b84811015615361578035868111156153475760008081fd5b61535336828b01614b06565b84525091830191830161532f565b50979650505050505050565b6000845161537f818460208901614d15565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516153bb816001850160208a01614d15565b600192019182015283516153d6816002840160208801614d15565b0160020195945050505050565b6000602082840312156153f557600080fd5b5051919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361542d5761542d614f05565b5060010190565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261547f60c0830184614d45565b98975050505050505050565b60008261549a5761549a614f4b565b500690565b600082198211156154b2576154b2614f05565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff8316806154f9576154f9614f4b565b8060ff84160691505092915050565b600060ff821660ff84168082101561552257615522614f05565b90039392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561556357615563614f05565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c634300080f000a", Bin: "0x6101206040523480156200001257600080fd5b50604051620058d4380380620058d483398101604081905262000035916200028e565b6001608052600260a052600060c0526001600160a01b0380841660e05282166101005262000063816200006c565b505050620002e6565b600054610100900460ff16158080156200008d5750600054600160ff909116105b80620000bd5750620000aa30620001c360201b62001cc21760201c565b158015620000bd575060005460ff166001145b620001265760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156200014a576000805461ff0019166101001790555b603280546001600160a01b03191661dead1790556035805483151560ff1990911617905562000178620001d2565b8015620001bf576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b03163b151590565b600054610100900460ff166200023f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016200011d565b60408051606081018252633b9aca0080825260006020830152436001600160401b031691909201819052600160c01b0217600155565b6001600160a01b03811681146200028b57600080fd5b50565b600080600060608486031215620002a457600080fd5b8351620002b18162000275565b6020850151909350620002c48162000275565b60408501519092508015158114620002db57600080fd5b809150509250925092565b60805160a05160c05160e051610100516155716200036360003960008181610358015281816107dd01526110e00152600081816101c101528181610a4601528181610c270152818161103c015281816113f60152818161166801526121c801526000610fa701526000610f7e01526000610f5501526155716000f3fe6080604052600436106101835760003560e01c80638456cb59116100d6578063ca3e99ba1161007f578063d53a822f11610059578063d53a822f146104ef578063e965084c1461050f578063e9e05c421461059b57600080fd5b8063ca3e99ba14610424578063cd7c978914610439578063cff0ab961461044e57600080fd5b80638c3152e9116100b05780638c3152e9146103a75780639bf62d82146103c7578063a14238e7146103f457600080fd5b80638456cb591461037a578063867ead131461038f5780638b4c40b0146101a857600080fd5b80635c1f2827116101385780636bb0291e116101125780636bb0291e146103115780636dbffb7814610326578063724c184c1461034657600080fd5b80635c1f28271461029d5780635c975abb146102cf57806364b79208146102f957600080fd5b80633f4ba83a116101695780633f4ba83a146102465780634870496f1461025b57806354fd4d501461027b57600080fd5b80621c2ff6146101af57806313620abd1461020d57600080fd5b366101aa576101a83334620186a06000604051806020016040528060008152506105a9565b005b600080fd5b3480156101bb57600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561021957600080fd5b50610225633b9aca0081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610204565b34801561025257600080fd5b506101a86107c5565b34801561026757600080fd5b506101a8610276366004614c3e565b6108e8565b34801561028757600080fd5b50610290610f4e565b6040516102049190614d94565b3480156102a957600080fd5b506102c16fffffffffffffffffffffffffffffffff81565b604051908152602001610204565b3480156102db57600080fd5b506035546102e99060ff1681565b6040519015158152602001610204565b34801561030557600080fd5b506102c16301312d0081565b34801561031d57600080fd5b506102c1600a81565b34801561033257600080fd5b506102e9610341366004614da7565b610ff1565b34801561035257600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561038657600080fd5b506101a86110c8565b34801561039b57600080fd5b506102c1633b9aca0081565b3480156103b357600080fd5b506101a86103c2366004614dc0565b6111e8565b3480156103d357600080fd5b506032546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561040057600080fd5b506102e961040f366004614da7565b60336020526000908152604090205460ff1681565b34801561043057600080fd5b506102c1611ac3565b34801561044557600080fd5b506102c1600881565b34801561045a57600080fd5b506001546104b6906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff9283166020850152911690820152606001610204565b3480156104fb57600080fd5b506101a861050a366004614e05565b611ad5565b34801561051b57600080fd5b5061056d61052a366004614da7565b603460205260009081526040902080546001909101546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041683565b604080519384526fffffffffffffffffffffffffffffffff9283166020850152911690820152606001610204565b6101a86105a9366004614e20565b8260005a905083156106605773ffffffffffffffffffffffffffffffffffffffff87161561066057604080517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260248101919091527f4f7074696d69736d506f7274616c3a206d7573742073656e6420746f2061646460448201527f72657373283029207768656e206372656174696e67206120636f6e747261637460648201526084015b60405180910390fd5b6152088567ffffffffffffffff1610156106fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4f7074696d69736d506f7274616c3a20676173206c696d6974206d757374206360448201527f6f76657220696e737472696e7369632067617320636f737400000000000000006064820152608401610657565b3332811461071d575033731111000000000000000000000000000000001111015b60003488888888604051602001610738959493929190614ea5565b604051602081830303815290604052905060008973ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32846040516107a89190614d94565b60405180910390a450506107bc8282611cde565b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461088a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e20756e706175736500000000000000000000000000000000000000000000006064820152608401610657565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60355460ff1615610955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610657565b3073ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff1603610a14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a20796f752063616e6e6f742073656e642060448201527f6d6573736167657320746f2074686520706f7274616c20636f6e7472616374006064820152608401610657565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018590526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610aa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac69190614f2a565b519050610ae0610adb36869003860186614f8f565b611fd7565b8114610b6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a20696e76616c6964206f7574707574207260448201527f6f6f742070726f6f6600000000000000000000000000000000000000000000006064820152608401610657565b6000610b7987612033565b6000818152603460209081526040918290208251606081018452815481526001909101546fffffffffffffffffffffffffffffffff8082169383018490527001000000000000000000000000000000009091041692810192909252919250901580610cab5750805160408083015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca79190614f2a565b5114155b610d37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173682060448201527f68617320616c7265616479206265656e2070726f76656e0000000000000000006064820152608401610657565b60408051602081018490526000918101829052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083018190529250610e009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f0100000000000000000000000000000000000000000000000000000000000000602083015290610df6888a614ff5565b8a60400135612063565b610e8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a20696e76616c696420776974686472617760448201527f616c20696e636c7573696f6e2070726f6f6600000000000000000000000000006064820152608401610657565b604080516060810182528581526fffffffffffffffffffffffffffffffff42811660208084019182528c831684860190815260008981526034835286812095518655925190518416700100000000000000000000000000000000029316929092176001909301929092558b830151908c0151925173ffffffffffffffffffffffffffffffffffffffff918216939091169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f629190a4505050505050505050565b6060610f797f0000000000000000000000000000000000000000000000000000000000000000612087565b610fa27f0000000000000000000000000000000000000000000000000000000000000000612087565b610fcb7f0000000000000000000000000000000000000000000000000000000000000000612087565b604051602001610fdd93929190615079565b604051602081830303815290604052905090565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018290526000906110c29073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a25ae55790602401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a79190614f2a565b602001516fffffffffffffffffffffffffffffffff166121c4565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461118d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e207061757365000000000000000000000000000000000000000000000000006064820152608401610657565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016108de565b60355460ff1615611255576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610657565b60325473ffffffffffffffffffffffffffffffffffffffff1661dead146112fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a2063616e206f6e6c79207472696767657260448201527f206f6e65207769746864726177616c20706572207472616e73616374696f6e006064820152608401610657565b600061130982612033565b60008181526034602090815260408083208151606081018352815481526001909101546fffffffffffffffffffffffffffffffff808216948301859052700100000000000000000000000000000000909104169181019190915292935090036113f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206e60448201527f6f74206265656e2070726f76656e2079657400000000000000000000000000006064820152608401610657565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663887862726040518163ffffffff1660e01b8152600401602060405180830381865afa15801561145f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148391906150ef565b81602001516fffffffffffffffffffffffffffffffff16101561154e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604b60248201527f4f7074696d69736d506f7274616c3a207769746864726177616c2074696d657360448201527f74616d70206c657373207468616e204c32204f7261636c65207374617274696e60648201527f672074696d657374616d70000000000000000000000000000000000000000000608482015260a401610657565b61156d81602001516fffffffffffffffffffffffffffffffff166121c4565b61161f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604560248201527f4f7074696d69736d506f7274616c3a2070726f76656e2077697468647261776160448201527f6c2066696e616c697a6174696f6e20706572696f6420686173206e6f7420656c60648201527f6170736564000000000000000000000000000000000000000000000000000000608482015260a401610657565b60408181015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa1580156116c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e89190614f2a565b82518151919250146117a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f4f7074696d69736d506f7274616c3a206f757470757420726f6f742070726f7660448201527f656e206973206e6f74207468652073616d652061732063757272656e74206f7560648201527f7470757420726f6f740000000000000000000000000000000000000000000000608482015260a401610657565b6117c181602001516fffffffffffffffffffffffffffffffff166121c4565b611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f4f7074696d69736d506f7274616c3a206f75747075742070726f706f73616c2060448201527f66696e616c697a6174696f6e20706572696f6420686173206e6f7420656c617060648201527f7365640000000000000000000000000000000000000000000000000000000000608482015260a401610657565b60008381526033602052604090205460ff1615611912576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206160448201527f6c7265616479206265656e2066696e616c697a656400000000000000000000006064820152608401610657565b600083815260336020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055908601516032805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff00000000000000000000000000000000000000009092169190911790558501516080860151606087015160a08801516119b493929190612267565b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405190915084907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b90611a1990841515815260200190565b60405180910390a280158015611a2f5750326001145b15611abc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4f7074696d69736d506f7274616c3a207769746864726177616c206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610657565b5050505050565b611ad2600a6301312d00615166565b81565b600054610100900460ff1615808015611af55750600054600160ff909116105b80611b0f5750303b158015611b0f575060005460ff166001145b611b9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610657565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611bf957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead179055603580548315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055611c5b6122c1565b8015611cbe57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b600154600090611d14907801000000000000000000000000000000000000000000000000900467ffffffffffffffff16436151ce565b90508015611e4c576000611d2d600a6301312d00615166565b600154611d589190700100000000000000000000000000000000900467ffffffffffffffff166151e5565b905060006008611d6d600a6301312d00615166565b611d779190615259565b600154611d979084906fffffffffffffffffffffffffffffffff16615259565b611da19190615166565b600154909150600090611de690611dcb9084906fffffffffffffffffffffffffffffffff16615315565b633b9aca006fffffffffffffffffffffffffffffffff6123a4565b90506001841115611e0d57611e0a611dcb826008611e056001896151ce565b6123c3565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b60018054849190601090611e7f908490700100000000000000000000000000000000900467ffffffffffffffff16615389565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506301312d00600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff161315611f5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5265736f757263654d65746572696e673a2063616e6e6f7420627579206d6f7260448201527f6520676173207468616e20617661696c61626c6520676173206c696d697400006064820152608401610657565b600154600090611f88906fffffffffffffffffffffffffffffffff1667ffffffffffffffff86166153b5565b90506000611f9a48633b9aca00612418565b611fa490836153f2565b905060005a611fb390866151ce565b905080821115611fcf57611fcf611fca82846151ce565b61242f565b505050505050565b60008160000151826020015183604001518460600151604051602001612016949392919093845260208401929092526040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b80516020808301516040808501516060860151608087015160a08801519351600097612016979096959101615406565b60008061206f8661245d565b905061207d8186868661248f565b9695505050505050565b6060816000036120ca57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156120f457806120de8161545d565b91506120ed9050600a836153f2565b91506120ce565b60008167ffffffffffffffff81111561210f5761210f614a64565b6040519080825280601f01601f191660200182016040528015612139576020820181803683370190505b5090505b84156121bc5761214e6001836151ce565b915061215b600a86615495565b6121669060306154a9565b60f81b81838151811061217b5761217b6154c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506121b5600a866153f2565b945061213d565b949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f4daa2916040518163ffffffff1660e01b8152600401602060405180830381865afa158015612231573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225591906150ef565b61225f90836154a9565b421192915050565b600080603f60c88601604002045a10156122aa576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080845160208601878a5af19695505050505050565b600054610100900460ff16612358576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610657565b60408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b60006123b96123b385856124bf565b836124cf565b90505b9392505050565b6000670de0b6b3a76400006124046123db8583615166565b6123ed90670de0b6b3a76400006151e5565b6123ff85670de0b6b3a7640000615259565b6124de565b61240e9086615259565b6123b99190615166565b60008183101561242857816123bc565b5090919050565b6000805a90505b825a61244290836151ce565b1015612458576124518261545d565b9150612436565b505050565b6060818051906020012060405160200161247991815260200190565b6040516020818303038152906040529050919050565b60006124b6846124a087868661250f565b8051602091820120825192909101919091201490565b95945050505050565b60008183121561242857816123bc565b600081831261242857816123bc565b60006123bc670de0b6b3a7640000836124f686612f97565b6125009190615259565b61250a9190615166565b6131db565b6060600084511161257c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152606401610657565b60006125878461341a565b9050600061259486613509565b90506000846040516020016125ab91815260200190565b60405160208183030381529060405290506000805b8451811015612f0e5760008582815181106125dd576125dd6154c1565b602002602001015190508451831115612678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152608401610657565b8260000361273157805180516020918201206040516126c6926126a092910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b61272c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610657565b612888565b8051516020116127e7578051805160209182012060405161275b926126a092910190815260200190565b61272c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152608401610657565b805184516020808701919091208251919092012014612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152608401610657565b612894601060016154a9565b81602001515103612a755784518303612a0d5760006128d082602001516010815181106128c3576128c36154c1565b60200260200101516136a4565b90506000815111612963576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610657565b6001875161297191906151ce565b83146129ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610657565b96506123bc95505050505050565b6000858481518110612a2157612a216154c1565b602001015160f81c60f81b60f81c9050600082602001518260ff1681518110612a4c57612a4c6154c1565b60200260200101519050612a5f81613804565b9550612a6c6001866154a9565b94505050612efb565b600281602001515103612e73576000612a8d82613829565b9050600081600081518110612aa457612aa46154c1565b016020015160f81c90506000612abb6002836154f0565b612ac6906002615512565b90506000612ad7848360ff1661384d565b90506000612ae58a8961384d565b90506000612af38383613883565b905080835114612b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610657565b60ff851660021480612b9a575060ff85166003145b15612d8e5780825114612c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610657565b6000612c4b88602001516001815181106128c3576128c36154c1565b90506000815111612cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610657565b60018d51612cec91906151ce565b8914612d7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610657565b9c506123bc9b505050505050505050505050565b60ff85161580612da1575060ff85166001145b15612de057612dcd8760200151600181518110612dc057612dc06154c1565b6020026020010151613804565b9950612dd9818a6154a9565b9850612e68565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608401610657565b505050505050612efb565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608401610657565b5080612f068161545d565b9150506125c0565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608401610657565b6000808213613002576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610657565b6000606061300f84613932565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361320c57506000919050565b680755bf798b4a1bf1e5821261327e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610657565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b805160609060008167ffffffffffffffff81111561343a5761343a614a64565b60405190808252806020026020018201604052801561347f57816020015b60408051808201909152606080825260208201528152602001906001900390816134585790505b50905060005b828110156135015760405180604001604052808683815181106134aa576134aa6154c1565b602002602001015181526020016134d98784815181106134cc576134cc6154c1565b6020026020010151613a08565b8152508282815181106134ee576134ee6154c1565b6020908102919091010152600101613485565b509392505050565b8051606090600061351b8260026153b5565b67ffffffffffffffff81111561353357613533614a64565b6040519080825280601f01601f19166020018201604052801561355d576020820181803683370190505b5090506000805b8381101561369a5785818151811061357e5761357e6154c1565b6020910101517fff000000000000000000000000000000000000000000000000000000000000008116925060041c7f0ff000000000000000000000000000000000000000000000000000000000000016836135da8360026153b5565b815181106135ea576135ea6154c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f0f000000000000000000000000000000000000000000000000000000000000008216836136488360026153b5565b6136539060016154a9565b81518110613663576136636154c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101613564565b5090949350505050565b606060008060006136b485613a1b565b9194509250905060008160018111156136cf576136cf615535565b1461375c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610657565b61376682846154a9565b8551146137f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152608401610657565b6124b685602001518484614488565b606060208260000151106138205761381b826136a4565b6110c2565b6110c282614529565b60606110c261384883602001516000815181106128c3576128c36154c1565b613509565b60608251821061386c57506040805160208101909152600081526110c2565b6123bc838384865161387e91906151ce565b61453f565b6000806000835185511061389857835161389b565b84515b90505b808210801561392257508382815181106138ba576138ba6154c1565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168583815181106138f9576138f96154c1565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156135015781600101915061389e565b600080821161399d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610657565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b60606110c2613a1683614717565b614800565b600080600080846000015111613ad9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610657565b6020840151805160001a607f8111613afe576000600160009450945094505050614481565b60b78111613d0c576000613b136080836151ce565b905080876000015111613bce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e6729000000000000000000000000000000000000608482015260a401610657565b6001838101517fff00000000000000000000000000000000000000000000000000000000000000169082141580613c4757507f80000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610155b613cf9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e672900000000000000000000000000000000000000608482015260a401610657565b5060019550935060009250614481915050565b60bf811161405a576000613d2160b7836151ce565b905080876000015111613ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e6729000000000000000000000000000000608482015260a401610657565b60018301517fff00000000000000000000000000000000000000000000000000000000000000166000819003613eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e672900000000000000000000000000000000000000000000608482015260a401610657565b600184015160088302610100031c60378111613f7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e6729000000000000000000000000000000000000000000000000608482015260a401610657565b613f8881846154a9565b89511161403d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e67290000000000000000000000000000000000000000608482015260a401610657565b6140488360016154a9565b97509550600094506144819350505050565b60f7811161413b57600061406f60c0836151ce565b90508087600001511161412a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c6973742900000000000000000000000000000000000000000000608482015260a401610657565b600195509350849250614481915050565b600061414860f7836151ce565b905080876000015111614203576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c6973742900000000000000000000000000000000000000608482015260a401610657565b60018301517fff000000000000000000000000000000000000000000000000000000000000001660008190036142e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c69737429000000000000000000000000000000000000000000000000608482015260a401610657565b600184015160088302610100031c603781116143a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c697374290000000000000000000000000000000000000000000000000000608482015260a401610657565b6143af81846154a9565b895111614464576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c6973742900000000000000000000000000000000000000000000608482015260a401610657565b61446f8360016154a9565b97509550600194506144819350505050565b9193909250565b606060008267ffffffffffffffff8111156144a5576144a5614a64565b6040519080825280601f01601f1916602001820160405280156144cf576020820181803683370190505b509050826000036144e15790506123bc565b60006144ed85876154a9565b90506020820160005b8581101561450e5782810151828201526020016144f6565b8581111561451d576000868301525b50919695505050505050565b60606110c2826020015160008460000151614488565b60608182601f0110156145ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610657565b82828401101561461a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610657565b81830184511015614687576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610657565b6060821580156146a6576040519150600082526020820160405261470e565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156146df5780518352602092830192016146c7565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b604080518082019091526000808252602082015260008251116147e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610657565b50604080518082019091528151815260209182019181019190915290565b6060600080600061481085613a1b565b91945092509050600181600181111561482b5761482b615535565b146148b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610657565b84516148c483856154a9565b14614951576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152608401610657565b6040805160208082526104208201909252600091816020015b604080518082019091526000808252602082015281526020019060019003908161496a5790505090506000845b8751811015614a58576000806149dd6040518060400160405280858d600001516149c191906151ce565b8152602001858d602001516149d691906154a9565b9052613a1b565b5091509150604051806040016040528083836149f991906154a9565b8152602001848c60200151614a0e91906154a9565b815250858581518110614a2357614a236154c1565b6020908102919091010152614a396001856154a9565b9350614a4581836154a9565b614a4f90846154a9565b92505050614997565b50815295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614ada57614ada614a64565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b0657600080fd5b919050565b600082601f830112614b1c57600080fd5b813567ffffffffffffffff811115614b3657614b36614a64565b614b6760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a93565b818152846020838601011115614b7c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614bab57600080fd5b60405160c0810167ffffffffffffffff8282108183111715614bcf57614bcf614a64565b8160405282935084358352614be660208601614ae2565b6020840152614bf760408601614ae2565b6040840152606085013560608401526080850135608084015260a0850135915080821115614c2457600080fd5b50614c3185828601614b0b565b60a0830152505092915050565b600080600080600085870360e0811215614c5757600080fd5b863567ffffffffffffffff80821115614c6f57600080fd5b614c7b8a838b01614b99565b97506020890135965060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc084011215614cb457600080fd5b60408901955060c0890135925080831115614cce57600080fd5b828901925089601f840112614ce257600080fd5b8235915080821115614cf357600080fd5b508860208260051b8401011115614d0957600080fd5b959894975092955050506020019190565b60005b83811015614d35578181015183820152602001614d1d565b83811115614d44576000848401525b50505050565b60008151808452614d62816020860160208601614d1a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006123bc6020830184614d4a565b600060208284031215614db957600080fd5b5035919050565b600060208284031215614dd257600080fd5b813567ffffffffffffffff811115614de957600080fd5b6121bc84828501614b99565b80358015158114614b0657600080fd5b600060208284031215614e1757600080fd5b6123bc82614df5565b600080600080600060a08688031215614e3857600080fd5b614e4186614ae2565b945060208601359350604086013567ffffffffffffffff8082168214614e6657600080fd5b819450614e7560608901614df5565b93506080880135915080821115614e8b57600080fd5b50614e9888828901614b0b565b9150509295509295909350565b8581528460208201527fffffffffffffffff0000000000000000000000000000000000000000000000008460c01b16604082015282151560f81b604882015260008251614ef9816049850160208701614d1a565b919091016049019695505050505050565b80516fffffffffffffffffffffffffffffffff81168114614b0657600080fd5b600060608284031215614f3c57600080fd5b6040516060810181811067ffffffffffffffff82111715614f5f57614f5f614a64565b60405282518152614f7260208401614f0a565b6020820152614f8360408401614f0a565b60408201529392505050565b600060808284031215614fa157600080fd5b6040516080810181811067ffffffffffffffff82111715614fc457614fc4614a64565b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b600067ffffffffffffffff8084111561501057615010614a64565b8360051b6020615021818301614a93565b86815291850191818101903684111561503957600080fd5b865b8481101561506d578035868111156150535760008081fd5b61505f36828b01614b0b565b84525091830191830161503b565b50979650505050505050565b6000845161508b818460208901614d1a565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516150c7816001850160208a01614d1a565b600192019182015283516150e2816002840160208801614d1a565b0160020195945050505050565b60006020828403121561510157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261517557615175615108565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156151c9576151c9615137565b500590565b6000828210156151e0576151e0615137565b500390565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561521f5761521f615137565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561525357615253615137565b50500390565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561529a5761529a615137565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156152d5576152d5615137565b600087129250878205871284841616156152f1576152f1615137565b8785058712818416161561530757615307615137565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561534f5761534f615137565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561538357615383615137565b50500190565b600067ffffffffffffffff8083168185168083038211156153ac576153ac615137565b01949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156153ed576153ed615137565b500290565b60008261540157615401615108565b500490565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261545160c0830184614d4a565b98975050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361548e5761548e615137565b5060010190565b6000826154a4576154a4615108565b500690565b600082198211156154bc576154bc615137565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff83168061550357615503615108565b8060ff84160691505092915050565b600060ff821660ff84168082101561552c5761552c615137565b90039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c634300080f000a",
} }
// OptimismPortalABI is the input ABI used to generate the binding from. // OptimismPortalABI is the input ABI used to generate the binding from.
......
...@@ -13,7 +13,7 @@ const OptimismPortalStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contrac ...@@ -13,7 +13,7 @@ const OptimismPortalStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contrac
var OptimismPortalStorageLayout = new(solc.StorageLayout) var OptimismPortalStorageLayout = new(solc.StorageLayout)
var OptimismPortalDeployedBin = "0x6080604052600436106101835760003560e01c80638456cb59116100d6578063ca3e99ba1161007f578063d53a822f11610059578063d53a822f146104ec578063e965084c1461050c578063e9e05c421461059857600080fd5b8063ca3e99ba14610421578063cd7c978914610436578063cff0ab961461044b57600080fd5b80638c3152e9116100b05780638c3152e9146103a45780639bf62d82146103c4578063a14238e7146103f157600080fd5b80638456cb5914610379578063867ead131461038e5780638b4c40b0146101a857600080fd5b80635c1f2827116101385780636bb0291e116101125780636bb0291e146103105780636dbffb7814610325578063724c184c1461034557600080fd5b80635c1f28271461029d5780635c975abb146102cf57806364b79208146102f957600080fd5b80633f4ba83a116101695780633f4ba83a146102465780634870496f1461025b57806354fd4d501461027b57600080fd5b80621c2ff6146101af57806313620abd1461020d57600080fd5b366101aa576101a83334620186a06000604051806020016040528060008152506105a6565b005b600080fd5b3480156101bb57600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561021957600080fd5b50610225633b9aca0081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610204565b34801561025257600080fd5b506101a8610aba565b34801561026757600080fd5b506101a8610276366004614c39565b610bdd565b34801561028757600080fd5b50610290611243565b6040516102049190614d8f565b3480156102a957600080fd5b506102c16fffffffffffffffffffffffffffffffff81565b604051908152602001610204565b3480156102db57600080fd5b506035546102e99060ff1681565b6040519015158152602001610204565b34801561030557600080fd5b506102c1627a120081565b34801561031c57600080fd5b506102c1600481565b34801561033157600080fd5b506102e9610340366004614da2565b6112e6565b34801561035157600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561038557600080fd5b506101a86113bd565b34801561039a57600080fd5b506102c161271081565b3480156103b057600080fd5b506101a86103bf366004614dbb565b6114dd565b3480156103d057600080fd5b506032546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103fd57600080fd5b506102e961040c366004614da2565b60336020526000908152604090205460ff1681565b34801561042d57600080fd5b506102c1611db8565b34801561044257600080fd5b506102c1600881565b34801561045757600080fd5b506001546104b3906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff9283166020850152911690820152606001610204565b3480156104f857600080fd5b506101a8610507366004614e00565b611dc9565b34801561051857600080fd5b5061056a610527366004614da2565b603460205260009081526040902080546001909101546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041683565b604080519384526fffffffffffffffffffffffffffffffff9283166020850152911690820152606001610204565b6101a86105a6366004614e1b565b8260005a9050831561065d5773ffffffffffffffffffffffffffffffffffffffff87161561065d57604080517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260248101919091527f4f7074696d69736d506f7274616c3a206d7573742073656e6420746f2061646460448201527f72657373283029207768656e206372656174696e67206120636f6e747261637460648201526084015b60405180910390fd5b6152088567ffffffffffffffff1610156106f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4f7074696d69736d506f7274616c3a20676173206c696d6974206d757374206360448201527f6f76657220696e737472696e7369632067617320636f737400000000000000006064820152608401610654565b3332811461071a575033731111000000000000000000000000000000001111015b60003488888888604051602001610735959493929190614ea0565b604051602081830303815290604052905060008973ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32846040516107a59190614d8f565b60405180910390a450506001546000906107e5907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1643614f34565b905080156109195760006107fd6004627a1200614f7a565b6001546108289190700100000000000000000000000000000000900467ffffffffffffffff16614fe2565b90506000600861083c6004627a1200614f7a565b6108469190615056565b6001546108669084906fffffffffffffffffffffffffffffffff16615056565b6108709190614f7a565b6001549091506000906108b39061089a9084906fffffffffffffffffffffffffffffffff16615112565b6127106fffffffffffffffffffffffffffffffff611fd2565b905060018411156108da576108d761089a8260086108d2600189614f34565b611ff1565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b6001805484919060109061094c908490700100000000000000000000000000000000900467ffffffffffffffff16615186565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550627a1200600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff161315610a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5265736f757263654d65746572696e673a2063616e6e6f7420627579206d6f7260448201527f6520676173207468616e20617661696c61626c6520676173206c696d697400006064820152608401610654565b600154600090610a54906fffffffffffffffffffffffffffffffff1667ffffffffffffffff86166151b2565b6fffffffffffffffffffffffffffffffff1690506000610a7848633b9aca00612046565b610a8290836151ea565b905060005a610a919086614f34565b905080821115610aad57610aad610aa88284614f34565b61205d565b5050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610b7f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e20756e706175736500000000000000000000000000000000000000000000006064820152608401610654565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60355460ff1615610c4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610654565b3073ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff1603610d09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a20796f752063616e6e6f742073656e642060448201527f6d6573736167657320746f2074686520706f7274616c20636f6e7472616374006064820152608401610654565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018590526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610d97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbb919061521e565b519050610dd5610dd036869003860186615283565b61208b565b8114610e63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a20696e76616c6964206f7574707574207260448201527f6f6f742070726f6f6600000000000000000000000000000000000000000000006064820152608401610654565b6000610e6e876120e7565b6000818152603460209081526040918290208251606081018452815481526001909101546fffffffffffffffffffffffffffffffff8082169383018490527001000000000000000000000000000000009091041692810192909252919250901580610fa05750805160408083015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9c919061521e565b5114155b61102c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173682060448201527f68617320616c7265616479206265656e2070726f76656e0000000000000000006064820152608401610654565b60408051602081018490526000918101829052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012090830181905292506110f59101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f01000000000000000000000000000000000000000000000000000000000000006020830152906110eb888a6152e9565b8a60400135612117565b611181576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a20696e76616c696420776974686472617760448201527f616c20696e636c7573696f6e2070726f6f6600000000000000000000000000006064820152608401610654565b604080516060810182528581526fffffffffffffffffffffffffffffffff42811660208084019182528c831684860190815260008981526034835286812095518655925190518416700100000000000000000000000000000000029316929092176001909301929092558b830151908c0151925173ffffffffffffffffffffffffffffffffffffffff918216939091169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f629190a4505050505050505050565b606061126e7f000000000000000000000000000000000000000000000000000000000000000061213b565b6112977f000000000000000000000000000000000000000000000000000000000000000061213b565b6112c07f000000000000000000000000000000000000000000000000000000000000000061213b565b6040516020016112d29392919061536d565b604051602081830303815290604052905090565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018290526000906113b79073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a25ae55790602401606060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139c919061521e565b602001516fffffffffffffffffffffffffffffffff16612278565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e207061757365000000000000000000000000000000000000000000000000006064820152608401610654565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610bd3565b60355460ff161561154a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610654565b60325473ffffffffffffffffffffffffffffffffffffffff1661dead146115f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a2063616e206f6e6c79207472696767657260448201527f206f6e65207769746864726177616c20706572207472616e73616374696f6e006064820152608401610654565b60006115fe826120e7565b60008181526034602090815260408083208151606081018352815481526001909101546fffffffffffffffffffffffffffffffff808216948301859052700100000000000000000000000000000000909104169181019190915292935090036116e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206e60448201527f6f74206265656e2070726f76656e2079657400000000000000000000000000006064820152608401610654565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663887862726040518163ffffffff1660e01b8152600401602060405180830381865afa158015611754573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177891906153e3565b81602001516fffffffffffffffffffffffffffffffff161015611843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604b60248201527f4f7074696d69736d506f7274616c3a207769746864726177616c2074696d657360448201527f74616d70206c657373207468616e204c32204f7261636c65207374617274696e60648201527f672074696d657374616d70000000000000000000000000000000000000000000608482015260a401610654565b61186281602001516fffffffffffffffffffffffffffffffff16612278565b611914576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604560248201527f4f7074696d69736d506f7274616c3a2070726f76656e2077697468647261776160448201527f6c2066696e616c697a6174696f6e20706572696f6420686173206e6f7420656c60648201527f6170736564000000000000000000000000000000000000000000000000000000608482015260a401610654565b60408181015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa1580156119b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dd919061521e565b8251815191925014611a97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f4f7074696d69736d506f7274616c3a206f757470757420726f6f742070726f7660448201527f656e206973206e6f74207468652073616d652061732063757272656e74206f7560648201527f7470757420726f6f740000000000000000000000000000000000000000000000608482015260a401610654565b611ab681602001516fffffffffffffffffffffffffffffffff16612278565b611b68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f4f7074696d69736d506f7274616c3a206f75747075742070726f706f73616c2060448201527f66696e616c697a6174696f6e20706572696f6420686173206e6f7420656c617060648201527f7365640000000000000000000000000000000000000000000000000000000000608482015260a401610654565b60008381526033602052604090205460ff1615611c07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206160448201527f6c7265616479206265656e2066696e616c697a656400000000000000000000006064820152608401610654565b600083815260336020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055908601516032805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff00000000000000000000000000000000000000009092169190911790558501516080860151606087015160a0880151611ca99392919061231b565b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405190915084907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b90611d0e90841515815260200190565b60405180910390a280158015611d245750326001145b15611db1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4f7074696d69736d506f7274616c3a207769746864726177616c206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610654565b5050505050565b611dc66004627a1200614f7a565b81565b600054610100900460ff1615808015611de95750600054600160ff909116105b80611e035750303b158015611e03575060005460ff166001145b611e8f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610654565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611eed57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead179055603580548315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055611f4f612375565b8015611fb257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b6000611fe7611fe18585612458565b83612468565b90505b9392505050565b6000670de0b6b3a76400006120326120098583614f7a565b61201b90670de0b6b3a7640000614fe2565b61202d85670de0b6b3a7640000615056565b612477565b61203c9086615056565b611fe79190614f7a565b6000818310156120565781611fea565b5090919050565b6000805a90505b825a6120709083614f34565b10156120865761207f826153fc565b9150612064565b505050565b600081600001518260200151836040015184606001516040516020016120ca949392919093845260208401929092526040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b80516020808301516040808501516060860151608087015160a088015193516000976120ca979096959101615434565b600080612123866124a8565b9050612131818686866124da565b9695505050505050565b60608160000361217e57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156121a85780612192816153fc565b91506121a19050600a836151ea565b9150612182565b60008167ffffffffffffffff8111156121c3576121c3614a5f565b6040519080825280601f01601f1916602001820160405280156121ed576020820181803683370190505b5090505b841561227057612202600183614f34565b915061220f600a8661548b565b61221a90603061549f565b60f81b81838151811061222f5761222f6154b7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612269600a866151ea565b94506121f1565b949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f4daa2916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230991906153e3565b612313908361549f565b421192915050565b600080603f60c88601604002045a101561235e576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080845160208601878a5af19695505050505050565b600054610100900460ff1661240c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610654565b60408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b6000818312156120565781611fea565b60008183126120565781611fea565b6000611fea670de0b6b3a76400008361248f8661250a565b6124999190615056565b6124a39190614f7a565b61274e565b606081805190602001206040516020016124c491815260200190565b6040516020818303038152906040529050919050565b6000612501846124eb87868661298d565b8051602091820120825192909101919091201490565b95945050505050565b6000808213612575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610654565b6000606061258284613415565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361277f57506000919050565b680755bf798b4a1bf1e582126127f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610654565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b606060008451116129fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152606401610654565b6000612a05846134eb565b90506000612a12866135da565b9050600084604051602001612a2991815260200190565b60405160208183030381529060405290506000805b845181101561338c576000858281518110612a5b57612a5b6154b7565b602002602001015190508451831115612af6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152608401610654565b82600003612baf5780518051602091820120604051612b4492612b1e92910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b612baa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610654565b612d06565b805151602011612c655780518051602091820120604051612bd992612b1e92910190815260200190565b612baa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152608401610654565b805184516020808701919091208251919092012014612d06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152608401610654565b612d126010600161549f565b81602001515103612ef35784518303612e8b576000612d4e8260200151601081518110612d4157612d416154b7565b6020026020010151613775565b90506000815111612de1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610654565b60018751612def9190614f34565b8314612e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610654565b9650611fea95505050505050565b6000858481518110612e9f57612e9f6154b7565b602001015160f81c60f81b60f81c9050600082602001518260ff1681518110612eca57612eca6154b7565b60200260200101519050612edd816138d5565b9550612eea60018661549f565b94505050613379565b6002816020015151036132f1576000612f0b826138fa565b9050600081600081518110612f2257612f226154b7565b016020015160f81c90506000612f396002836154e6565b612f44906002615508565b90506000612f55848360ff1661391e565b90506000612f638a8961391e565b90506000612f718383613954565b905080835114613003576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610654565b60ff851660021480613018575060ff85166003145b1561320c57808251146130ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610654565b60006130c98860200151600181518110612d4157612d416154b7565b9050600081511161315c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610654565b60018d5161316a9190614f34565b89146131f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610654565b9c50611fea9b505050505050505050505050565b60ff8516158061321f575060ff85166001145b1561325e5761324b876020015160018151811061323e5761323e6154b7565b60200260200101516138d5565b9950613257818a61549f565b98506132e6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608401610654565b505050505050613379565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608401610654565b5080613384816153fc565b915050612a3e565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608401610654565b6000808211613480576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610654565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b805160609060008167ffffffffffffffff81111561350b5761350b614a5f565b60405190808252806020026020018201604052801561355057816020015b60408051808201909152606080825260208201528152602001906001900390816135295790505b50905060005b828110156135d257604051806040016040528086838151811061357b5761357b6154b7565b602002602001015181526020016135aa87848151811061359d5761359d6154b7565b6020026020010151613a03565b8152508282815181106135bf576135bf6154b7565b6020908102919091010152600101613556565b509392505050565b805160609060006135ec82600261552b565b67ffffffffffffffff81111561360457613604614a5f565b6040519080825280601f01601f19166020018201604052801561362e576020820181803683370190505b5090506000805b8381101561376b5785818151811061364f5761364f6154b7565b6020910101517fff000000000000000000000000000000000000000000000000000000000000008116925060041c7f0ff000000000000000000000000000000000000000000000000000000000000016836136ab83600261552b565b815181106136bb576136bb6154b7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f0f0000000000000000000000000000000000000000000000000000000000000082168361371983600261552b565b61372490600161549f565b81518110613734576137346154b7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101613635565b5090949350505050565b6060600080600061378585613a16565b9194509250905060008160018111156137a0576137a0615568565b1461382d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610654565b613837828461549f565b8551146138c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152608401610654565b61250185602001518484614483565b606060208260000151106138f1576138ec82613775565b6113b7565b6113b782614524565b60606113b76139198360200151600081518110612d4157612d416154b7565b6135da565b60608251821061393d57506040805160208101909152600081526113b7565b611fea838384865161394f9190614f34565b61453a565b6000806000835185511061396957835161396c565b84515b90505b80821080156139f3575083828151811061398b5761398b6154b7565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168583815181106139ca576139ca6154b7565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156135d25781600101915061396f565b60606113b7613a1183614712565b6147fb565b600080600080846000015111613ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610654565b6020840151805160001a607f8111613af957600060016000945094509450505061447c565b60b78111613d07576000613b0e608083614f34565b905080876000015111613bc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e6729000000000000000000000000000000000000608482015260a401610654565b6001838101517fff00000000000000000000000000000000000000000000000000000000000000169082141580613c4257507f80000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610155b613cf4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e672900000000000000000000000000000000000000608482015260a401610654565b506001955093506000925061447c915050565b60bf8111614055576000613d1c60b783614f34565b905080876000015111613dd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e6729000000000000000000000000000000608482015260a401610654565b60018301517fff00000000000000000000000000000000000000000000000000000000000000166000819003613eb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e672900000000000000000000000000000000000000000000608482015260a401610654565b600184015160088302610100031c60378111613f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e6729000000000000000000000000000000000000000000000000608482015260a401610654565b613f83818461549f565b895111614038576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e67290000000000000000000000000000000000000000608482015260a401610654565b61404383600161549f565b975095506000945061447c9350505050565b60f7811161413657600061406a60c083614f34565b905080876000015111614125576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c6973742900000000000000000000000000000000000000000000608482015260a401610654565b60019550935084925061447c915050565b600061414360f783614f34565b9050808760000151116141fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c6973742900000000000000000000000000000000000000608482015260a401610654565b60018301517fff000000000000000000000000000000000000000000000000000000000000001660008190036142dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c69737429000000000000000000000000000000000000000000000000608482015260a401610654565b600184015160088302610100031c603781116143a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c697374290000000000000000000000000000000000000000000000000000608482015260a401610654565b6143aa818461549f565b89511161445f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c6973742900000000000000000000000000000000000000000000608482015260a401610654565b61446a83600161549f565b975095506001945061447c9350505050565b9193909250565b606060008267ffffffffffffffff8111156144a0576144a0614a5f565b6040519080825280601f01601f1916602001820160405280156144ca576020820181803683370190505b509050826000036144dc579050611fea565b60006144e8858761549f565b90506020820160005b858110156145095782810151828201526020016144f1565b85811115614518576000868301525b50919695505050505050565b60606113b7826020015160008460000151614483565b60608182601f0110156145a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610654565b828284011015614615576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610654565b81830184511015614682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610654565b6060821580156146a15760405191506000825260208201604052614709565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156146da5780518352602092830192016146c2565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b604080518082019091526000808252602082015260008251116147dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610654565b50604080518082019091528151815260209182019181019190915290565b6060600080600061480b85613a16565b91945092509050600181600181111561482657614826615568565b146148b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610654565b84516148bf838561549f565b1461494c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152608401610654565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816149655790505090506000845b8751811015614a53576000806149d86040518060400160405280858d600001516149bc9190614f34565b8152602001858d602001516149d1919061549f565b9052613a16565b5091509150604051806040016040528083836149f4919061549f565b8152602001848c60200151614a09919061549f565b815250858581518110614a1e57614a1e6154b7565b6020908102919091010152614a3460018561549f565b9350614a40818361549f565b614a4a908461549f565b92505050614992565b50815295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614ad557614ad5614a5f565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b0157600080fd5b919050565b600082601f830112614b1757600080fd5b813567ffffffffffffffff811115614b3157614b31614a5f565b614b6260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a8e565b818152846020838601011115614b7757600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614ba657600080fd5b60405160c0810167ffffffffffffffff8282108183111715614bca57614bca614a5f565b8160405282935084358352614be160208601614add565b6020840152614bf260408601614add565b6040840152606085013560608401526080850135608084015260a0850135915080821115614c1f57600080fd5b50614c2c85828601614b06565b60a0830152505092915050565b600080600080600085870360e0811215614c5257600080fd5b863567ffffffffffffffff80821115614c6a57600080fd5b614c768a838b01614b94565b97506020890135965060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc084011215614caf57600080fd5b60408901955060c0890135925080831115614cc957600080fd5b828901925089601f840112614cdd57600080fd5b8235915080821115614cee57600080fd5b508860208260051b8401011115614d0457600080fd5b959894975092955050506020019190565b60005b83811015614d30578181015183820152602001614d18565b83811115614d3f576000848401525b50505050565b60008151808452614d5d816020860160208601614d15565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611fea6020830184614d45565b600060208284031215614db457600080fd5b5035919050565b600060208284031215614dcd57600080fd5b813567ffffffffffffffff811115614de457600080fd5b61227084828501614b94565b80358015158114614b0157600080fd5b600060208284031215614e1257600080fd5b611fea82614df0565b600080600080600060a08688031215614e3357600080fd5b614e3c86614add565b945060208601359350604086013567ffffffffffffffff8082168214614e6157600080fd5b819450614e7060608901614df0565b93506080880135915080821115614e8657600080fd5b50614e9388828901614b06565b9150509295509295909350565b8581528460208201527fffffffffffffffff0000000000000000000000000000000000000000000000008460c01b16604082015282151560f81b604882015260008251614ef4816049850160208701614d15565b919091016049019695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015614f4657614f46614f05565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614f8957614f89614f4b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615614fdd57614fdd614f05565b500590565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561501c5761501c614f05565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561505057615050614f05565b50500390565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561509757615097614f05565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156150d2576150d2614f05565b600087129250878205871284841616156150ee576150ee614f05565b8785058712818416161561510457615104614f05565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561514c5761514c614f05565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561518057615180614f05565b50500190565b600067ffffffffffffffff8083168185168083038211156151a9576151a9614f05565b01949350505050565b60006fffffffffffffffffffffffffffffffff808316818516818304811182151516156151e1576151e1614f05565b02949350505050565b6000826151f9576151f9614f4b565b500490565b80516fffffffffffffffffffffffffffffffff81168114614b0157600080fd5b60006060828403121561523057600080fd5b6040516060810181811067ffffffffffffffff8211171561525357615253614a5f565b60405282518152615266602084016151fe565b6020820152615277604084016151fe565b60408201529392505050565b60006080828403121561529557600080fd5b6040516080810181811067ffffffffffffffff821117156152b8576152b8614a5f565b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b600067ffffffffffffffff8084111561530457615304614a5f565b8360051b6020615315818301614a8e565b86815291850191818101903684111561532d57600080fd5b865b84811015615361578035868111156153475760008081fd5b61535336828b01614b06565b84525091830191830161532f565b50979650505050505050565b6000845161537f818460208901614d15565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516153bb816001850160208a01614d15565b600192019182015283516153d6816002840160208801614d15565b0160020195945050505050565b6000602082840312156153f557600080fd5b5051919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361542d5761542d614f05565b5060010190565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261547f60c0830184614d45565b98975050505050505050565b60008261549a5761549a614f4b565b500690565b600082198211156154b2576154b2614f05565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff8316806154f9576154f9614f4b565b8060ff84160691505092915050565b600060ff821660ff84168082101561552257615522614f05565b90039392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561556357615563614f05565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c634300080f000a" var OptimismPortalDeployedBin = "0x6080604052600436106101835760003560e01c80638456cb59116100d6578063ca3e99ba1161007f578063d53a822f11610059578063d53a822f146104ef578063e965084c1461050f578063e9e05c421461059b57600080fd5b8063ca3e99ba14610424578063cd7c978914610439578063cff0ab961461044e57600080fd5b80638c3152e9116100b05780638c3152e9146103a75780639bf62d82146103c7578063a14238e7146103f457600080fd5b80638456cb591461037a578063867ead131461038f5780638b4c40b0146101a857600080fd5b80635c1f2827116101385780636bb0291e116101125780636bb0291e146103115780636dbffb7814610326578063724c184c1461034657600080fd5b80635c1f28271461029d5780635c975abb146102cf57806364b79208146102f957600080fd5b80633f4ba83a116101695780633f4ba83a146102465780634870496f1461025b57806354fd4d501461027b57600080fd5b80621c2ff6146101af57806313620abd1461020d57600080fd5b366101aa576101a83334620186a06000604051806020016040528060008152506105a9565b005b600080fd5b3480156101bb57600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561021957600080fd5b50610225633b9aca0081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610204565b34801561025257600080fd5b506101a86107c5565b34801561026757600080fd5b506101a8610276366004614c3e565b6108e8565b34801561028757600080fd5b50610290610f4e565b6040516102049190614d94565b3480156102a957600080fd5b506102c16fffffffffffffffffffffffffffffffff81565b604051908152602001610204565b3480156102db57600080fd5b506035546102e99060ff1681565b6040519015158152602001610204565b34801561030557600080fd5b506102c16301312d0081565b34801561031d57600080fd5b506102c1600a81565b34801561033257600080fd5b506102e9610341366004614da7565b610ff1565b34801561035257600080fd5b506101e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561038657600080fd5b506101a86110c8565b34801561039b57600080fd5b506102c1633b9aca0081565b3480156103b357600080fd5b506101a86103c2366004614dc0565b6111e8565b3480156103d357600080fd5b506032546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561040057600080fd5b506102e961040f366004614da7565b60336020526000908152604090205460ff1681565b34801561043057600080fd5b506102c1611ac3565b34801561044557600080fd5b506102c1600881565b34801561045a57600080fd5b506001546104b6906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff9283166020850152911690820152606001610204565b3480156104fb57600080fd5b506101a861050a366004614e05565b611ad5565b34801561051b57600080fd5b5061056d61052a366004614da7565b603460205260009081526040902080546001909101546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041683565b604080519384526fffffffffffffffffffffffffffffffff9283166020850152911690820152606001610204565b6101a86105a9366004614e20565b8260005a905083156106605773ffffffffffffffffffffffffffffffffffffffff87161561066057604080517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260248101919091527f4f7074696d69736d506f7274616c3a206d7573742073656e6420746f2061646460448201527f72657373283029207768656e206372656174696e67206120636f6e747261637460648201526084015b60405180910390fd5b6152088567ffffffffffffffff1610156106fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4f7074696d69736d506f7274616c3a20676173206c696d6974206d757374206360448201527f6f76657220696e737472696e7369632067617320636f737400000000000000006064820152608401610657565b3332811461071d575033731111000000000000000000000000000000001111015b60003488888888604051602001610738959493929190614ea5565b604051602081830303815290604052905060008973ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32846040516107a89190614d94565b60405180910390a450506107bc8282611cde565b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461088a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e20756e706175736500000000000000000000000000000000000000000000006064820152608401610657565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60355460ff1615610955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610657565b3073ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff1603610a14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a20796f752063616e6e6f742073656e642060448201527f6d6573736167657320746f2074686520706f7274616c20636f6e7472616374006064820152608401610657565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018590526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610aa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac69190614f2a565b519050610ae0610adb36869003860186614f8f565b611fd7565b8114610b6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a20696e76616c6964206f7574707574207260448201527f6f6f742070726f6f6600000000000000000000000000000000000000000000006064820152608401610657565b6000610b7987612033565b6000818152603460209081526040918290208251606081018452815481526001909101546fffffffffffffffffffffffffffffffff8082169383018490527001000000000000000000000000000000009091041692810192909252919250901580610cab5750805160408083015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca79190614f2a565b5114155b610d37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173682060448201527f68617320616c7265616479206265656e2070726f76656e0000000000000000006064820152608401610657565b60408051602081018490526000918101829052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083018190529250610e009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f0100000000000000000000000000000000000000000000000000000000000000602083015290610df6888a614ff5565b8a60400135612063565b610e8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a20696e76616c696420776974686472617760448201527f616c20696e636c7573696f6e2070726f6f6600000000000000000000000000006064820152608401610657565b604080516060810182528581526fffffffffffffffffffffffffffffffff42811660208084019182528c831684860190815260008981526034835286812095518655925190518416700100000000000000000000000000000000029316929092176001909301929092558b830151908c0151925173ffffffffffffffffffffffffffffffffffffffff918216939091169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f629190a4505050505050505050565b6060610f797f0000000000000000000000000000000000000000000000000000000000000000612087565b610fa27f0000000000000000000000000000000000000000000000000000000000000000612087565b610fcb7f0000000000000000000000000000000000000000000000000000000000000000612087565b604051602001610fdd93929190615079565b604051602081830303815290604052905090565b6040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018290526000906110c29073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a25ae55790602401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a79190614f2a565b602001516fffffffffffffffffffffffffffffffff166121c4565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461118d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4f7074696d69736d506f7274616c3a206f6e6c7920677561726469616e20636160448201527f6e207061757365000000000000000000000000000000000000000000000000006064820152608401610657565b603580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016108de565b60355460ff1615611255576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f7074696d69736d506f7274616c3a20706175736564000000000000000000006044820152606401610657565b60325473ffffffffffffffffffffffffffffffffffffffff1661dead146112fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d506f7274616c3a2063616e206f6e6c79207472696767657260448201527f206f6e65207769746864726177616c20706572207472616e73616374696f6e006064820152608401610657565b600061130982612033565b60008181526034602090815260408083208151606081018352815481526001909101546fffffffffffffffffffffffffffffffff808216948301859052700100000000000000000000000000000000909104169181019190915292935090036113f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206e60448201527f6f74206265656e2070726f76656e2079657400000000000000000000000000006064820152608401610657565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663887862726040518163ffffffff1660e01b8152600401602060405180830381865afa15801561145f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148391906150ef565b81602001516fffffffffffffffffffffffffffffffff16101561154e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604b60248201527f4f7074696d69736d506f7274616c3a207769746864726177616c2074696d657360448201527f74616d70206c657373207468616e204c32204f7261636c65207374617274696e60648201527f672074696d657374616d70000000000000000000000000000000000000000000608482015260a401610657565b61156d81602001516fffffffffffffffffffffffffffffffff166121c4565b61161f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604560248201527f4f7074696d69736d506f7274616c3a2070726f76656e2077697468647261776160448201527f6c2066696e616c697a6174696f6e20706572696f6420686173206e6f7420656c60648201527f6170736564000000000000000000000000000000000000000000000000000000608482015260a401610657565b60408181015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa1580156116c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e89190614f2a565b82518151919250146117a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f4f7074696d69736d506f7274616c3a206f757470757420726f6f742070726f7660448201527f656e206973206e6f74207468652073616d652061732063757272656e74206f7560648201527f7470757420726f6f740000000000000000000000000000000000000000000000608482015260a401610657565b6117c181602001516fffffffffffffffffffffffffffffffff166121c4565b611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f4f7074696d69736d506f7274616c3a206f75747075742070726f706f73616c2060448201527f66696e616c697a6174696f6e20706572696f6420686173206e6f7420656c617060648201527f7365640000000000000000000000000000000000000000000000000000000000608482015260a401610657565b60008381526033602052604090205460ff1615611912576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206160448201527f6c7265616479206265656e2066696e616c697a656400000000000000000000006064820152608401610657565b600083815260336020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055908601516032805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff00000000000000000000000000000000000000009092169190911790558501516080860151606087015160a08801516119b493929190612267565b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405190915084907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b90611a1990841515815260200190565b60405180910390a280158015611a2f5750326001145b15611abc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4f7074696d69736d506f7274616c3a207769746864726177616c206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610657565b5050505050565b611ad2600a6301312d00615166565b81565b600054610100900460ff1615808015611af55750600054600160ff909116105b80611b0f5750303b158015611b0f575060005460ff166001145b611b9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610657565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611bf957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead179055603580548315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055611c5b6122c1565b8015611cbe57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b600154600090611d14907801000000000000000000000000000000000000000000000000900467ffffffffffffffff16436151ce565b90508015611e4c576000611d2d600a6301312d00615166565b600154611d589190700100000000000000000000000000000000900467ffffffffffffffff166151e5565b905060006008611d6d600a6301312d00615166565b611d779190615259565b600154611d979084906fffffffffffffffffffffffffffffffff16615259565b611da19190615166565b600154909150600090611de690611dcb9084906fffffffffffffffffffffffffffffffff16615315565b633b9aca006fffffffffffffffffffffffffffffffff6123a4565b90506001841115611e0d57611e0a611dcb826008611e056001896151ce565b6123c3565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b60018054849190601090611e7f908490700100000000000000000000000000000000900467ffffffffffffffff16615389565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506301312d00600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff161315611f5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5265736f757263654d65746572696e673a2063616e6e6f7420627579206d6f7260448201527f6520676173207468616e20617661696c61626c6520676173206c696d697400006064820152608401610657565b600154600090611f88906fffffffffffffffffffffffffffffffff1667ffffffffffffffff86166153b5565b90506000611f9a48633b9aca00612418565b611fa490836153f2565b905060005a611fb390866151ce565b905080821115611fcf57611fcf611fca82846151ce565b61242f565b505050505050565b60008160000151826020015183604001518460600151604051602001612016949392919093845260208401929092526040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b80516020808301516040808501516060860151608087015160a08801519351600097612016979096959101615406565b60008061206f8661245d565b905061207d8186868661248f565b9695505050505050565b6060816000036120ca57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156120f457806120de8161545d565b91506120ed9050600a836153f2565b91506120ce565b60008167ffffffffffffffff81111561210f5761210f614a64565b6040519080825280601f01601f191660200182016040528015612139576020820181803683370190505b5090505b84156121bc5761214e6001836151ce565b915061215b600a86615495565b6121669060306154a9565b60f81b81838151811061217b5761217b6154c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506121b5600a866153f2565b945061213d565b949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f4daa2916040518163ffffffff1660e01b8152600401602060405180830381865afa158015612231573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225591906150ef565b61225f90836154a9565b421192915050565b600080603f60c88601604002045a10156122aa576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080845160208601878a5af19695505050505050565b600054610100900460ff16612358576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610657565b60408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b60006123b96123b385856124bf565b836124cf565b90505b9392505050565b6000670de0b6b3a76400006124046123db8583615166565b6123ed90670de0b6b3a76400006151e5565b6123ff85670de0b6b3a7640000615259565b6124de565b61240e9086615259565b6123b99190615166565b60008183101561242857816123bc565b5090919050565b6000805a90505b825a61244290836151ce565b1015612458576124518261545d565b9150612436565b505050565b6060818051906020012060405160200161247991815260200190565b6040516020818303038152906040529050919050565b60006124b6846124a087868661250f565b8051602091820120825192909101919091201490565b95945050505050565b60008183121561242857816123bc565b600081831261242857816123bc565b60006123bc670de0b6b3a7640000836124f686612f97565b6125009190615259565b61250a9190615166565b6131db565b6060600084511161257c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152606401610657565b60006125878461341a565b9050600061259486613509565b90506000846040516020016125ab91815260200190565b60405160208183030381529060405290506000805b8451811015612f0e5760008582815181106125dd576125dd6154c1565b602002602001015190508451831115612678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152608401610657565b8260000361273157805180516020918201206040516126c6926126a092910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b61272c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610657565b612888565b8051516020116127e7578051805160209182012060405161275b926126a092910190815260200190565b61272c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152608401610657565b805184516020808701919091208251919092012014612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152608401610657565b612894601060016154a9565b81602001515103612a755784518303612a0d5760006128d082602001516010815181106128c3576128c36154c1565b60200260200101516136a4565b90506000815111612963576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610657565b6001875161297191906151ce565b83146129ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610657565b96506123bc95505050505050565b6000858481518110612a2157612a216154c1565b602001015160f81c60f81b60f81c9050600082602001518260ff1681518110612a4c57612a4c6154c1565b60200260200101519050612a5f81613804565b9550612a6c6001866154a9565b94505050612efb565b600281602001515103612e73576000612a8d82613829565b9050600081600081518110612aa457612aa46154c1565b016020015160f81c90506000612abb6002836154f0565b612ac6906002615512565b90506000612ad7848360ff1661384d565b90506000612ae58a8961384d565b90506000612af38383613883565b905080835114612b85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610657565b60ff851660021480612b9a575060ff85166003145b15612d8e5780825114612c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610657565b6000612c4b88602001516001815181106128c3576128c36154c1565b90506000815111612cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610657565b60018d51612cec91906151ce565b8914612d7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610657565b9c506123bc9b505050505050505050505050565b60ff85161580612da1575060ff85166001145b15612de057612dcd8760200151600181518110612dc057612dc06154c1565b6020026020010151613804565b9950612dd9818a6154a9565b9850612e68565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608401610657565b505050505050612efb565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608401610657565b5080612f068161545d565b9150506125c0565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608401610657565b6000808213613002576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610657565b6000606061300f84613932565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361320c57506000919050565b680755bf798b4a1bf1e5821261327e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610657565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b805160609060008167ffffffffffffffff81111561343a5761343a614a64565b60405190808252806020026020018201604052801561347f57816020015b60408051808201909152606080825260208201528152602001906001900390816134585790505b50905060005b828110156135015760405180604001604052808683815181106134aa576134aa6154c1565b602002602001015181526020016134d98784815181106134cc576134cc6154c1565b6020026020010151613a08565b8152508282815181106134ee576134ee6154c1565b6020908102919091010152600101613485565b509392505050565b8051606090600061351b8260026153b5565b67ffffffffffffffff81111561353357613533614a64565b6040519080825280601f01601f19166020018201604052801561355d576020820181803683370190505b5090506000805b8381101561369a5785818151811061357e5761357e6154c1565b6020910101517fff000000000000000000000000000000000000000000000000000000000000008116925060041c7f0ff000000000000000000000000000000000000000000000000000000000000016836135da8360026153b5565b815181106135ea576135ea6154c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f0f000000000000000000000000000000000000000000000000000000000000008216836136488360026153b5565b6136539060016154a9565b81518110613663576136636154c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101613564565b5090949350505050565b606060008060006136b485613a1b565b9194509250905060008160018111156136cf576136cf615535565b1461375c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610657565b61376682846154a9565b8551146137f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152608401610657565b6124b685602001518484614488565b606060208260000151106138205761381b826136a4565b6110c2565b6110c282614529565b60606110c261384883602001516000815181106128c3576128c36154c1565b613509565b60608251821061386c57506040805160208101909152600081526110c2565b6123bc838384865161387e91906151ce565b61453f565b6000806000835185511061389857835161389b565b84515b90505b808210801561392257508382815181106138ba576138ba6154c1565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168583815181106138f9576138f96154c1565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156135015781600101915061389e565b600080821161399d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610657565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b60606110c2613a1683614717565b614800565b600080600080846000015111613ad9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610657565b6020840151805160001a607f8111613afe576000600160009450945094505050614481565b60b78111613d0c576000613b136080836151ce565b905080876000015111613bce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e6729000000000000000000000000000000000000608482015260a401610657565b6001838101517fff00000000000000000000000000000000000000000000000000000000000000169082141580613c4757507f80000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610155b613cf9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e672900000000000000000000000000000000000000608482015260a401610657565b5060019550935060009250614481915050565b60bf811161405a576000613d2160b7836151ce565b905080876000015111613ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e6729000000000000000000000000000000608482015260a401610657565b60018301517fff00000000000000000000000000000000000000000000000000000000000000166000819003613eba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e672900000000000000000000000000000000000000000000608482015260a401610657565b600184015160088302610100031c60378111613f7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e6729000000000000000000000000000000000000000000000000608482015260a401610657565b613f8881846154a9565b89511161403d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e67290000000000000000000000000000000000000000608482015260a401610657565b6140488360016154a9565b97509550600094506144819350505050565b60f7811161413b57600061406f60c0836151ce565b90508087600001511161412a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c6973742900000000000000000000000000000000000000000000608482015260a401610657565b600195509350849250614481915050565b600061414860f7836151ce565b905080876000015111614203576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c6973742900000000000000000000000000000000000000608482015260a401610657565b60018301517fff000000000000000000000000000000000000000000000000000000000000001660008190036142e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c69737429000000000000000000000000000000000000000000000000608482015260a401610657565b600184015160088302610100031c603781116143a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c697374290000000000000000000000000000000000000000000000000000608482015260a401610657565b6143af81846154a9565b895111614464576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c6973742900000000000000000000000000000000000000000000608482015260a401610657565b61446f8360016154a9565b97509550600194506144819350505050565b9193909250565b606060008267ffffffffffffffff8111156144a5576144a5614a64565b6040519080825280601f01601f1916602001820160405280156144cf576020820181803683370190505b509050826000036144e15790506123bc565b60006144ed85876154a9565b90506020820160005b8581101561450e5782810151828201526020016144f6565b8581111561451d576000868301525b50919695505050505050565b60606110c2826020015160008460000151614488565b60608182601f0110156145ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610657565b82828401101561461a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610657565b81830184511015614687576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610657565b6060821580156146a6576040519150600082526020820160405261470e565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156146df5780518352602092830192016146c7565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b604080518082019091526000808252602082015260008251116147e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610657565b50604080518082019091528151815260209182019181019190915290565b6060600080600061481085613a1b565b91945092509050600181600181111561482b5761482b615535565b146148b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610657565b84516148c483856154a9565b14614951576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152608401610657565b6040805160208082526104208201909252600091816020015b604080518082019091526000808252602082015281526020019060019003908161496a5790505090506000845b8751811015614a58576000806149dd6040518060400160405280858d600001516149c191906151ce565b8152602001858d602001516149d691906154a9565b9052613a1b565b5091509150604051806040016040528083836149f991906154a9565b8152602001848c60200151614a0e91906154a9565b815250858581518110614a2357614a236154c1565b6020908102919091010152614a396001856154a9565b9350614a4581836154a9565b614a4f90846154a9565b92505050614997565b50815295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614ada57614ada614a64565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b0657600080fd5b919050565b600082601f830112614b1c57600080fd5b813567ffffffffffffffff811115614b3657614b36614a64565b614b6760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a93565b818152846020838601011115614b7c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614bab57600080fd5b60405160c0810167ffffffffffffffff8282108183111715614bcf57614bcf614a64565b8160405282935084358352614be660208601614ae2565b6020840152614bf760408601614ae2565b6040840152606085013560608401526080850135608084015260a0850135915080821115614c2457600080fd5b50614c3185828601614b0b565b60a0830152505092915050565b600080600080600085870360e0811215614c5757600080fd5b863567ffffffffffffffff80821115614c6f57600080fd5b614c7b8a838b01614b99565b97506020890135965060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc084011215614cb457600080fd5b60408901955060c0890135925080831115614cce57600080fd5b828901925089601f840112614ce257600080fd5b8235915080821115614cf357600080fd5b508860208260051b8401011115614d0957600080fd5b959894975092955050506020019190565b60005b83811015614d35578181015183820152602001614d1d565b83811115614d44576000848401525b50505050565b60008151808452614d62816020860160208601614d1a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006123bc6020830184614d4a565b600060208284031215614db957600080fd5b5035919050565b600060208284031215614dd257600080fd5b813567ffffffffffffffff811115614de957600080fd5b6121bc84828501614b99565b80358015158114614b0657600080fd5b600060208284031215614e1757600080fd5b6123bc82614df5565b600080600080600060a08688031215614e3857600080fd5b614e4186614ae2565b945060208601359350604086013567ffffffffffffffff8082168214614e6657600080fd5b819450614e7560608901614df5565b93506080880135915080821115614e8b57600080fd5b50614e9888828901614b0b565b9150509295509295909350565b8581528460208201527fffffffffffffffff0000000000000000000000000000000000000000000000008460c01b16604082015282151560f81b604882015260008251614ef9816049850160208701614d1a565b919091016049019695505050505050565b80516fffffffffffffffffffffffffffffffff81168114614b0657600080fd5b600060608284031215614f3c57600080fd5b6040516060810181811067ffffffffffffffff82111715614f5f57614f5f614a64565b60405282518152614f7260208401614f0a565b6020820152614f8360408401614f0a565b60408201529392505050565b600060808284031215614fa157600080fd5b6040516080810181811067ffffffffffffffff82111715614fc457614fc4614a64565b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b600067ffffffffffffffff8084111561501057615010614a64565b8360051b6020615021818301614a93565b86815291850191818101903684111561503957600080fd5b865b8481101561506d578035868111156150535760008081fd5b61505f36828b01614b0b565b84525091830191830161503b565b50979650505050505050565b6000845161508b818460208901614d1a565b80830190507f2e0000000000000000000000000000000000000000000000000000000000000080825285516150c7816001850160208a01614d1a565b600192019182015283516150e2816002840160208801614d1a565b0160020195945050505050565b60006020828403121561510157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261517557615175615108565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156151c9576151c9615137565b500590565b6000828210156151e0576151e0615137565b500390565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561521f5761521f615137565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561525357615253615137565b50500390565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561529a5761529a615137565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156152d5576152d5615137565b600087129250878205871284841616156152f1576152f1615137565b8785058712818416161561530757615307615137565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561534f5761534f615137565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561538357615383615137565b50500190565b600067ffffffffffffffff8083168185168083038211156153ac576153ac615137565b01949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156153ed576153ed615137565b500290565b60008261540157615401615108565b500490565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261545160c0830184614d4a565b98975050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361548e5761548e615137565b5060010190565b6000826154a4576154a4615108565b500690565b600082198211156154bc576154bc615137565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff83168061550357615503615108565b8060ff84160691505092915050565b600060ff821660ff84168082101561552c5761552c615137565b90039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c634300080f000a"
func init() { func init() {
if err := json.Unmarshal([]byte(OptimismPortalStorageLayoutJSON), OptimismPortalStorageLayout); err != nil { if err := json.Unmarshal([]byte(OptimismPortalStorageLayoutJSON), OptimismPortalStorageLayout); err != nil {
......
...@@ -53,7 +53,7 @@ func waitForL1OriginOnL2(l1BlockNum uint64, client *ethclient.Client, timeout ti ...@@ -53,7 +53,7 @@ func waitForL1OriginOnL2(l1BlockNum uint64, client *ethclient.Client, timeout ti
} }
case err := <-headSub.Err(): case err := <-headSub.Err():
return nil, fmt.Errorf("Error in head subscription: %w", err) return nil, fmt.Errorf("error in head subscription: %w", err)
case <-timeoutCh: case <-timeoutCh:
return nil, errors.New("timeout") return nil, errors.New("timeout")
} }
...@@ -101,7 +101,7 @@ func waitForBlock(number *big.Int, client *ethclient.Client, timeout time.Durati ...@@ -101,7 +101,7 @@ func waitForBlock(number *big.Int, client *ethclient.Client, timeout time.Durati
return client.BlockByNumber(ctx, number) return client.BlockByNumber(ctx, number)
} }
case err := <-headSub.Err(): case err := <-headSub.Err():
return nil, fmt.Errorf("Error in head subscription: %w", err) return nil, fmt.Errorf("error in head subscription: %w", err)
case <-timeoutCh: case <-timeoutCh:
return nil, errors.New("timeout") return nil, errors.New("timeout")
} }
......
...@@ -464,7 +464,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -464,7 +464,7 @@ func (cfg SystemConfig) Start() (*System, error) {
if p, ok := p2pNodes[name]; ok { if p, ok := p2pNodes[name]; ok {
c.P2P = p c.P2P = p
if c.Driver.SequencerEnabled { if c.Driver.SequencerEnabled && c.P2PSigner == nil {
c.P2PSigner = &p2p.PreparedSigner{Signer: p2p.NewLocalSigner(cfg.Secrets.SequencerP2P)} c.P2PSigner = &p2p.PreparedSigner{Signer: p2p.NewLocalSigner(cfg.Secrets.SequencerP2P)}
} }
} }
......
...@@ -28,7 +28,10 @@ import ( ...@@ -28,7 +28,10 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/client" "github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
rollupNode "github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-node/p2p"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver"
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/withdrawals" "github.com/ethereum-optimism/optimism/op-node/withdrawals"
...@@ -590,7 +593,7 @@ func TestSystemMockP2P(t *testing.T) { ...@@ -590,7 +593,7 @@ func TestSystemMockP2P(t *testing.T) {
// connect the nodes // connect the nodes
cfg.P2PTopology = map[string][]string{ cfg.P2PTopology = map[string][]string{
"verifier": []string{"sequencer"}, "verifier": {"sequencer"},
} }
var published, received []common.Hash var published, received []common.Hash
...@@ -646,6 +649,189 @@ func TestSystemMockP2P(t *testing.T) { ...@@ -646,6 +649,189 @@ func TestSystemMockP2P(t *testing.T) {
require.Contains(t, received, receiptVerif.BlockHash) require.Contains(t, received, receiptVerif.BlockHash)
} }
// TestSystemMockPeerScoring sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that
// the nodes can sync L2 blocks before they are confirmed on L1.
func TestSystemMockPeerScoring(t *testing.T) {
parallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t)
// slow down L1 blocks so we can see the L2 blocks arrive well before the L1 blocks do.
// Keep the seq window small so the L2 chain is started quick
cfg.DeployConfig.L1BlockTime = 10
// Append additional nodes to the system to construct a dense p2p network
cfg.Nodes["verifier2"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
}
cfg.Nodes["verifier3"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
}
cfg.Loggers["verifier2"] = testlog.Logger(t, log.LvlInfo).New("role", "verifier")
cfg.Loggers["verifier3"] = testlog.Logger(t, log.LvlInfo).New("role", "verifier")
// Construct a new sequencer with an invalid privkey to produce invalid gossip
// We can then test that the peer scoring system will ban the node
sequencer2PrivateKey := cfg.Secrets.Mallory
cfg.Nodes["sequencer2"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: true,
},
// Submitter PrivKey is set in system start for rollup nodes where sequencer = true
RPC: rollupNode.RPCConfig{
ListenAddr: "127.0.0.1",
ListenPort: 0,
EnableAdmin: true,
},
L1EpochPollInterval: time.Second * 4,
P2PSigner: &p2p.PreparedSigner{Signer: p2p.NewLocalSigner(sequencer2PrivateKey)},
}
cfg.Loggers["sequencer2"] = testlog.Logger(t, log.LvlInfo).New("role", "sequencer")
// connect the nodes
cfg.P2PTopology = map[string][]string{
"verifier": {"sequencer", "sequencer2", "verifier2", "verifier3"},
"verifier2": {"sequencer", "sequencer2", "verifier", "verifier3"},
"verifier3": {"sequencer", "sequencer2", "verifier", "verifier2"},
}
// Set peer scoring for each node, but without banning
for _, node := range cfg.Nodes {
params, err := p2p.GetPeerScoreParams("light", 2)
require.NoError(t, err)
node.P2P = &p2p.Config{
PeerScoring: params,
BanningEnabled: false,
}
}
var published, published2, received1, received2, received3 []common.Hash
seqTracer, verifTracer, verifTracer2, verifTracer3 := new(FnTracer), new(FnTracer), new(FnTracer), new(FnTracer)
seq2Tracer := new(FnTracer)
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayload) {
published = append(published, payload.BlockHash)
}
seq2Tracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayload) {
published2 = append(published2, payload.BlockHash)
}
verifTracer.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
received1 = append(received1, payload.BlockHash)
}
verifTracer2.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
received2 = append(received2, payload.BlockHash)
}
verifTracer3.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayload) {
received3 = append(received3, payload.BlockHash)
}
cfg.Nodes["sequencer"].Tracer = seqTracer
cfg.Nodes["sequencer2"].Tracer = seq2Tracer
cfg.Nodes["verifier"].Tracer = verifTracer
cfg.Nodes["verifier2"].Tracer = verifTracer2
cfg.Nodes["verifier3"].Tracer = verifTracer3
sys, err := cfg.Start()
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l2Seq := sys.Clients["sequencer"]
// l2Seq2 := sys.Clients["sequencer2"]
l2Verif := sys.Clients["verifier"]
l2Verif2 := sys.Clients["verifier2"]
l2Verif3 := sys.Clients["verifier3"]
// Transactor Account
ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff}
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{
ChainID: cfg.L2ChainIDBig(),
Nonce: 0,
To: &toAddr,
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
})
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
// Wait until the block it was first included in shows up in the safe chain on the verifier
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, receiptSeq, receiptVerif)
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif2, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier2")
require.Equal(t, receiptSeq, receiptVerif)
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif3, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier3")
require.Equal(t, receiptSeq, receiptVerif)
// Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(received1))
require.GreaterOrEqual(t, len(published), len(received2))
require.GreaterOrEqual(t, len(published), len(received3))
require.ElementsMatch(t, published, received1[:len(published)])
require.ElementsMatch(t, published, received2[:len(published)])
require.ElementsMatch(t, published, received3[:len(published)])
// Verify that the tx was received via p2p
require.Contains(t, received1, receiptVerif.BlockHash)
require.Contains(t, received2, receiptVerif.BlockHash)
require.Contains(t, received3, receiptVerif.BlockHash)
// Submit TX to the second (malicious) sequencer node
// toAddr = common.Address{0xff, 0xff}
// maliciousTx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{
// ChainID: cfg.L2ChainIDBig(),
// Nonce: 1,
// To: &toAddr,
// Value: big.NewInt(1_000_000_000),
// GasTipCap: big.NewInt(10),
// GasFeeCap: big.NewInt(200),
// Gas: 21000,
// })
// err = l2Seq2.SendTransaction(context.Background(), maliciousTx)
// require.Nil(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
// receiptSeq, err = waitForTransaction(maliciousTx.Hash(), l2Seq2, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on sequencer")
// Wait until the block it was first included in shows up in the safe chain on the verifier
// receiptVerif, err = waitForTransaction(maliciousTx.Hash(), l2Verif, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on verifier")
// require.Equal(t, receiptSeq, receiptVerif)
// receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif2, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on verifier2")
// require.Equal(t, receiptSeq, receiptVerif)
// receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif3, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
// require.Nil(t, err, "Waiting for L2 tx on verifier3")
// require.Equal(t, receiptSeq, receiptVerif)
}
func TestL1InfoContract(t *testing.T) { func TestL1InfoContract(t *testing.T) {
parallel(t) parallel(t)
if !verboseGethNodes { if !verboseGethNodes {
......
# Batch Decoding Tool
The batch decoding tool is a utility to aid in debugging the batch submitter & the op-node
by looking at what batches were submitted on L1.
## Design Philosophy
The `batch_decoder` tool is designed to be simple & flexible. It offloads as much data analysis
as possible to other tools. It is built around manipulating JSON on disk. The first stage is to
fetch all transaction which are sent to a batch inbox address. Those transactions are decoded into
frames in that step & information about them is recorded. After transactions are fetched the frames
are re-assembled into channels in a second step that does not touch the network.
## Commands
### Fetch
`batch_decoder fetch` pulls all L1 transactions sent to the batch inbox address in a given L1 block
range and then stores them on disk to a specified path as JSON files where the name of the file is
the transaction hash.
### Reassemble
`batch_decoder reassemble` goes through all of the found frames in the cache & then turns them
into channels. It then stores the channels with metadata on disk where the file name is the Channel ID.
## JQ Cheat Sheet
`jq` is a really useful utility for manipulating JSON files.
```
# Pretty print a JSON file
jq . $JSON_FILE
# Print the number of valid & invalid transactions
jq .valid_data $TX_DIR/* | sort | uniq -c
# Select all transactions that have invalid data & then print the transaction hash
jq "select(.valid_data == false)|.tx.hash" $TX_DIR
# Select all channels that are not ready and then get the id and inclusion block & tx hash of the first frame.
jq "select(.is_ready == false)|[.id, .frames[0].inclusion_block, .frames[0].transaction_hash]" $CHANNEL_DIR
```
## Roadmap
- Parallel transaction fetching (CLI-3563)
- Create force-close channel tx data from channel ID (CLI-3564)
- Pull the batches out of channels & store that information inside the ChannelWithMetadata (CLI-3565)
- Transaction Bytes used
- Total uncompressed (different from tx bytes) + compressed bytes
- Invert ChannelWithMetadata so block numbers/hashes are mapped to channels they are submitted in (CLI-3560)
...@@ -16,11 +16,12 @@ import ( ...@@ -16,11 +16,12 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
) )
type TransactionWithMeta struct { type TransactionWithMetadata struct {
TxIndex uint64 `json:"tx_index"` TxIndex uint64 `json:"tx_index"`
InboxAddr common.Address `json:"inbox_address"` InboxAddr common.Address `json:"inbox_address"`
BlockNumber uint64 `json:"block_number"` BlockNumber uint64 `json:"block_number"`
BlockHash common.Hash `json:"block_hash"` BlockHash common.Hash `json:"block_hash"`
BlockTime uint64 `json:"block_time"`
ChainId uint64 `json:"chain_id"` ChainId uint64 `json:"chain_id"`
Sender common.Address `json:"sender"` Sender common.Address `json:"sender"`
ValidSender bool `json:"valid_sender"` ValidSender bool `json:"valid_sender"`
...@@ -38,6 +39,9 @@ type Config struct { ...@@ -38,6 +39,9 @@ type Config struct {
OutDirectory string OutDirectory string
} }
// Batches fetches & stores all transactions sent to the batch inbox address in
// the given block range (inclusive to exclusive).
// The transactions & metadata are written to the out directory.
func Batches(client *ethclient.Client, config Config) (totalValid, totalInvalid int) { func Batches(client *ethclient.Client, config Config) (totalValid, totalInvalid int) {
if err := os.MkdirAll(config.OutDirectory, 0750); err != nil { if err := os.MkdirAll(config.OutDirectory, 0750); err != nil {
log.Fatal(err) log.Fatal(err)
...@@ -53,13 +57,15 @@ func Batches(client *ethclient.Client, config Config) (totalValid, totalInvalid ...@@ -53,13 +57,15 @@ func Batches(client *ethclient.Client, config Config) (totalValid, totalInvalid
return return
} }
// fetchBatchesPerBlock gets a block & the parses all of the transactions in the block.
func fetchBatchesPerBlock(client *ethclient.Client, number *big.Int, signer types.Signer, config Config) (validBatchCount, invalidBatchCount int) { func fetchBatchesPerBlock(client *ethclient.Client, number *big.Int, signer types.Signer, config Config) (validBatchCount, invalidBatchCount int) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
block, err := client.BlockByNumber(ctx, number) block, err := client.BlockByNumber(ctx, number)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
fmt.Println("Fetched block: ", number)
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
if tx.To() != nil && *tx.To() == config.BatchInbox { if tx.To() != nil && *tx.To() == config.BatchInbox {
sender, err := signer.Sender(tx) sender, err := signer.Sender(tx)
...@@ -88,13 +94,14 @@ func fetchBatchesPerBlock(client *ethclient.Client, number *big.Int, signer type ...@@ -88,13 +94,14 @@ func fetchBatchesPerBlock(client *ethclient.Client, number *big.Int, signer type
invalidBatchCount += 1 invalidBatchCount += 1
} }
txm := &TransactionWithMeta{ txm := &TransactionWithMetadata{
Tx: tx, Tx: tx,
Sender: sender, Sender: sender,
ValidSender: validSender, ValidSender: validSender,
TxIndex: uint64(i), TxIndex: uint64(i),
BlockNumber: block.NumberU64(), BlockNumber: block.NumberU64(),
BlockHash: block.Hash(), BlockHash: block.Hash(),
BlockTime: block.Time(),
ChainId: config.ChainID.Uint64(), ChainId: config.ChainID.Uint64(),
InboxAddr: config.BatchInbox, InboxAddr: config.BatchInbox,
Frames: frames, Frames: frames,
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/fetch" "github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/fetch"
"github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/reassemble"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/urfave/cli" "github.com/urfave/cli"
...@@ -59,7 +60,7 @@ func main() { ...@@ -59,7 +60,7 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
chainID, err := client.ChainID(ctx) chainID, err := client.ChainID(ctx)
if err != nil { if err != nil {
...@@ -82,6 +83,36 @@ func main() { ...@@ -82,6 +83,36 @@ func main() {
return nil return nil
}, },
}, },
{
Name: "reassemble",
Usage: "Reassembles channels from fetched batches",
Flags: []cli.Flag{
cli.StringFlag{
Name: "inbox",
Value: "0xff00000000000000000000000000000000000420",
Usage: "Batch Inbox Address",
},
cli.StringFlag{
Name: "in",
Value: "/tmp/batch_decoder/transactions_cache",
Usage: "Cache directory for the found transactions",
},
cli.StringFlag{
Name: "out",
Value: "/tmp/batch_decoder/channel_cache",
Usage: "Cache directory for the found channels",
},
},
Action: func(cliCtx *cli.Context) error {
config := reassemble.Config{
BatchInbox: common.HexToAddress(cliCtx.String("inbox")),
InDirectory: cliCtx.String("in"),
OutDirectory: cliCtx.String("out"),
}
reassemble.Channels(config)
return nil
},
},
} }
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
......
package reassemble
import (
"encoding/json"
"fmt"
"io"
"log"
"os"
"path"
"sort"
"github.com/ethereum-optimism/optimism/op-node/cmd/batch_decoder/fetch"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/common"
)
type ChannelWithMetadata struct {
ID derive.ChannelID `json:"id"`
IsReady bool `json:"is_ready"`
InvalidFrames bool `json:"invalid_frames"`
InvalidBatches bool `json:"invalid_batches"`
Frames []FrameWithMetadata `json:"frames"`
Batches []derive.BatchV1 `json:"batches"`
}
type FrameWithMetadata struct {
TxHash common.Hash `json:"transaction_hash"`
InclusionBlock uint64 `json:"inclusion_block"`
Timestamp uint64 `json:"timestamp"`
BlockHash common.Hash `json:"block_hash"`
Frame derive.Frame `json:"frame"`
}
type Config struct {
BatchInbox common.Address
InDirectory string
OutDirectory string
}
// Channels loads all transactions from the given input directory that are submitted to the
// specified batch inbox and then re-assembles all channels & writes the re-assembled channels
// to the out directory.
func Channels(config Config) {
if err := os.MkdirAll(config.OutDirectory, 0750); err != nil {
log.Fatal(err)
}
txns := loadTransactions(config.InDirectory, config.BatchInbox)
// Sort first by block number then by transaction index inside the block number range.
// This is to match the order they are processed in derivation.
sort.Slice(txns, func(i, j int) bool {
if txns[i].BlockNumber == txns[j].BlockNumber {
return txns[i].TxIndex < txns[j].TxIndex
} else {
return txns[i].BlockNumber < txns[j].BlockNumber
}
})
frames := transactionsToFrames(txns)
framesByChannel := make(map[derive.ChannelID][]FrameWithMetadata)
for _, frame := range frames {
framesByChannel[frame.Frame.ID] = append(framesByChannel[frame.Frame.ID], frame)
}
for id, frames := range framesByChannel {
ch := processFrames(id, frames)
filename := path.Join(config.OutDirectory, fmt.Sprintf("%s.json", id.String()))
if err := writeChannel(ch, filename); err != nil {
log.Fatal(err)
}
}
}
func writeChannel(ch ChannelWithMetadata, filename string) error {
file, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
enc := json.NewEncoder(file)
return enc.Encode(ch)
}
func processFrames(id derive.ChannelID, frames []FrameWithMetadata) ChannelWithMetadata {
ch := derive.NewChannel(id, eth.L1BlockRef{Number: frames[0].InclusionBlock})
invalidFrame := false
for _, frame := range frames {
if ch.IsReady() {
fmt.Printf("Channel %v is ready despite having more frames\n", id.String())
invalidFrame = true
break
}
if err := ch.AddFrame(frame.Frame, eth.L1BlockRef{Number: frame.InclusionBlock}); err != nil {
fmt.Printf("Error adding to channel %v. Err: %v\n", id.String(), err)
invalidFrame = true
}
}
var batches []derive.BatchV1
invalidBatches := false
if ch.IsReady() {
br, err := derive.BatchReader(ch.Reader(), eth.L1BlockRef{})
if err == nil {
for batch, err := br(); err != io.EOF; batch, err = br() {
if err != nil {
fmt.Printf("Error reading batch for channel %v. Err: %v\n", id.String(), err)
invalidBatches = true
} else {
batches = append(batches, batch.Batch.BatchV1)
}
}
} else {
fmt.Printf("Error creating batch reader for channel %v. Err: %v\n", id.String(), err)
}
} else {
fmt.Printf("Channel %v is not ready\n", id.String())
}
return ChannelWithMetadata{
ID: id,
Frames: frames,
IsReady: ch.IsReady(),
InvalidFrames: invalidFrame,
InvalidBatches: invalidBatches,
Batches: batches,
}
}
func transactionsToFrames(txns []fetch.TransactionWithMetadata) []FrameWithMetadata {
var out []FrameWithMetadata
for _, tx := range txns {
for _, frame := range tx.Frames {
fm := FrameWithMetadata{
TxHash: tx.Tx.Hash(),
InclusionBlock: tx.BlockNumber,
BlockHash: tx.BlockHash,
Timestamp: tx.BlockTime,
Frame: frame,
}
out = append(out, fm)
}
}
return out
}
func loadTransactions(dir string, inbox common.Address) []fetch.TransactionWithMetadata {
files, err := os.ReadDir(dir)
if err != nil {
log.Fatal(err)
}
var out []fetch.TransactionWithMetadata
for _, file := range files {
f := path.Join(dir, file.Name())
txm := loadTransactionsFile(f)
if txm.InboxAddr == inbox && txm.ValidSender {
out = append(out, txm)
}
}
return out
}
func loadTransactionsFile(file string) fetch.TransactionWithMetadata {
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer f.Close()
dec := json.NewDecoder(f)
var txm fetch.TransactionWithMetadata
if err := dec.Decode(&txm); err != nil {
log.Fatalf("Failed to decode %v. Err: %v\n", file, err)
}
return txm
}
...@@ -25,6 +25,33 @@ var ( ...@@ -25,6 +25,33 @@ var (
Required: false, Required: false,
EnvVar: p2pEnv("NO_DISCOVERY"), EnvVar: p2pEnv("NO_DISCOVERY"),
} }
PeerScoring = cli.StringFlag{
Name: "p2p.scoring.peers",
Usage: "Sets the peer scoring strategy for the P2P stack. " +
"Can be one of: none or light." +
"Custom scoring strategies can be defined in the config file.",
Required: false,
Value: "none",
EnvVar: p2pEnv("PEER_SCORING"),
}
// Banning Flag - whether or not we want to act on the scoring
Banning = cli.BoolFlag{
Name: "p2p.ban.peers",
Usage: "Enables peer banning. This should ONLY be enabled once certain peer scoring is working correctly.",
Required: false,
EnvVar: p2pEnv("PEER_BANNING"),
}
TopicScoring = cli.StringFlag{
Name: "p2p.scoring.topics",
Usage: "Sets the topic scoring strategy. " +
"Can be one of: none or light." +
"Custom scoring strategies can be defined in the config file.",
Required: false,
Value: "none",
EnvVar: p2pEnv("TOPIC_SCORING"),
}
P2PPrivPath = cli.StringFlag{ P2PPrivPath = cli.StringFlag{
Name: "p2p.priv.path", Name: "p2p.priv.path",
Usage: "Read the hex-encoded 32-byte private key for the peer ID from this txt file. Created if not already exists." + Usage: "Read the hex-encoded 32-byte private key for the peer ID from this txt file. Created if not already exists." +
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
pb "github.com/libp2p/go-libp2p-pubsub/pb" pb "github.com/libp2p/go-libp2p-pubsub/pb"
libp2pmetrics "github.com/libp2p/go-libp2p/core/metrics" libp2pmetrics "github.com/libp2p/go-libp2p/core/metrics"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
...@@ -64,6 +65,8 @@ type Metricer interface { ...@@ -64,6 +65,8 @@ type Metricer interface {
RecordSequencerBuildingDiffTime(duration time.Duration) RecordSequencerBuildingDiffTime(duration time.Duration)
RecordSequencerSealingTime(duration time.Duration) RecordSequencerSealingTime(duration time.Duration)
Document() []metrics.DocumentedMetric Document() []metrics.DocumentedMetric
// P2P Metrics
RecordPeerScoring(peerID peer.ID, score float64)
} }
// Metrics tracks all the metrics for the op-node. // Metrics tracks all the metrics for the op-node.
...@@ -116,6 +119,7 @@ type Metrics struct { ...@@ -116,6 +119,7 @@ type Metrics struct {
// P2P Metrics // P2P Metrics
PeerCount prometheus.Gauge PeerCount prometheus.Gauge
StreamCount prometheus.Gauge StreamCount prometheus.Gauge
PeerScores *prometheus.GaugeVec
GossipEventsTotal *prometheus.CounterVec GossipEventsTotal *prometheus.CounterVec
BandwidthTotal *prometheus.GaugeVec BandwidthTotal *prometheus.GaugeVec
...@@ -289,6 +293,16 @@ func NewMetrics(procName string) *Metrics { ...@@ -289,6 +293,16 @@ func NewMetrics(procName string) *Metrics {
Name: "stream_count", Name: "stream_count",
Help: "Count of currently connected p2p streams", Help: "Count of currently connected p2p streams",
}), }),
PeerScores: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: ns,
Subsystem: "p2p",
Name: "peer_scores",
Help: "Peer scoring",
}, []string{
// No label names here since peer ids would open a service attack vector.
// Each peer id would be a separate metric, flooding prometheus.
// See: https://prometheus.io/docs/practices/naming/#labels
}),
GossipEventsTotal: factory.NewCounterVec(prometheus.CounterOpts{ GossipEventsTotal: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: ns, Namespace: ns,
Subsystem: "p2p", Subsystem: "p2p",
...@@ -477,6 +491,10 @@ func (m *Metrics) RecordGossipEvent(evType int32) { ...@@ -477,6 +491,10 @@ func (m *Metrics) RecordGossipEvent(evType int32) {
m.GossipEventsTotal.WithLabelValues(pb.TraceEvent_Type_name[evType]).Inc() m.GossipEventsTotal.WithLabelValues(pb.TraceEvent_Type_name[evType]).Inc()
} }
func (m *Metrics) RecordPeerScoring(peerID peer.ID, score float64) {
m.PeerScores.WithLabelValues(peerID.String()).Set(score)
}
func (m *Metrics) IncPeerCount() { func (m *Metrics) IncPeerCount() {
m.PeerCount.Inc() m.PeerCount.Inc()
} }
...@@ -609,6 +627,9 @@ func (n *noopMetricer) RecordSequencerReset() { ...@@ -609,6 +627,9 @@ func (n *noopMetricer) RecordSequencerReset() {
func (n *noopMetricer) RecordGossipEvent(evType int32) { func (n *noopMetricer) RecordGossipEvent(evType int32) {
} }
func (n *noopMetricer) RecordPeerScoring(peerID peer.ID, score float64) {
}
func (n *noopMetricer) IncPeerCount() { func (n *noopMetricer) IncPeerCount() {
} }
......
...@@ -24,7 +24,7 @@ import ( ...@@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
) )
func NewConfig(ctx *cli.Context) (*p2p.Config, error) { func NewConfig(ctx *cli.Context, blockTime uint64) (*p2p.Config, error) {
conf := &p2p.Config{} conf := &p2p.Config{}
if ctx.GlobalBool(flags.DisableP2P.Name) { if ctx.GlobalBool(flags.DisableP2P.Name) {
...@@ -54,6 +54,18 @@ func NewConfig(ctx *cli.Context) (*p2p.Config, error) { ...@@ -54,6 +54,18 @@ func NewConfig(ctx *cli.Context) (*p2p.Config, error) {
return nil, fmt.Errorf("failed to load p2p gossip options: %w", err) return nil, fmt.Errorf("failed to load p2p gossip options: %w", err)
} }
if err := loadPeerScoringParams(conf, ctx, blockTime); err != nil {
return nil, fmt.Errorf("failed to load p2p peer scoring options: %w", err)
}
if err := loadBanningOption(conf, ctx); err != nil {
return nil, fmt.Errorf("failed to load banning option: %w", err)
}
if err := loadTopicScoringParams(conf, ctx, blockTime); err != nil {
return nil, fmt.Errorf("failed to load p2p topic scoring options: %w", err)
}
conf.ConnGater = p2p.DefaultConnGater conf.ConnGater = p2p.DefaultConnGater
conf.ConnMngr = p2p.DefaultConnManager conf.ConnMngr = p2p.DefaultConnManager
...@@ -73,6 +85,49 @@ func validatePort(p uint) (uint16, error) { ...@@ -73,6 +85,49 @@ func validatePort(p uint) (uint16, error) {
return uint16(p), nil return uint16(p), nil
} }
// loadTopicScoringParams loads the topic scoring options from the CLI context.
//
// If the topic scoring options are not set, then the default topic scoring.
func loadTopicScoringParams(conf *p2p.Config, ctx *cli.Context, blockTime uint64) error {
scoringLevel := ctx.GlobalString(flags.TopicScoring.Name)
if scoringLevel != "" {
// Set default block topic scoring parameters
// See prysm: https://github.com/prysmaticlabs/prysm/blob/develop/beacon-chain/p2p/gossip_scoring_params.go
// And research from lighthouse: https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c
// And docs: https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#topic-parameter-calculation-and-decay
topicScoreParams, err := p2p.GetTopicScoreParams(scoringLevel, blockTime)
if err != nil {
return err
}
conf.TopicScoring = topicScoreParams
}
return nil
}
// loadPeerScoringParams loads the scoring options from the CLI context.
//
// If the scoring level is not set, no scoring is enabled.
func loadPeerScoringParams(conf *p2p.Config, ctx *cli.Context, blockTime uint64) error {
scoringLevel := ctx.GlobalString(flags.PeerScoring.Name)
if scoringLevel != "" {
peerScoreParams, err := p2p.GetPeerScoreParams(scoringLevel, blockTime)
if err != nil {
return err
}
conf.PeerScoring = peerScoreParams
}
return nil
}
// loadBanningOption loads whether or not to ban peers from the CLI context.
func loadBanningOption(conf *p2p.Config, ctx *cli.Context) error {
ban := ctx.GlobalBool(flags.Banning.Name)
conf.BanningEnabled = ban
return nil
}
func loadListenOpts(conf *p2p.Config, ctx *cli.Context) error { func loadListenOpts(conf *p2p.Config, ctx *cli.Context) error {
listenIP := ctx.GlobalString(flags.ListenIP.Name) listenIP := ctx.GlobalString(flags.ListenIP.Name)
if listenIP != "" { // optional if listenIP != "" { // optional
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
ds "github.com/ipfs/go-datastore" ds "github.com/ipfs/go-datastore"
"github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core"
"github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/crypto"
...@@ -49,6 +50,13 @@ type Config struct { ...@@ -49,6 +50,13 @@ type Config struct {
DisableP2P bool DisableP2P bool
NoDiscovery bool NoDiscovery bool
// Pubsub Scoring Parameters
PeerScoring pubsub.PeerScoreParams
TopicScoring pubsub.TopicScoreParams
// Whether to ban peers based on their [PeerScoring] score.
BanningEnabled bool
ListenIP net.IP ListenIP net.IP
ListenTCPPort uint16 ListenTCPPort uint16
...@@ -95,6 +103,7 @@ type Config struct { ...@@ -95,6 +103,7 @@ type Config struct {
ConnMngr func(conf *Config) (connmgr.ConnManager, error) ConnMngr func(conf *Config) (connmgr.ConnManager, error)
} }
//go:generate mockery --name ConnectionGater
type ConnectionGater interface { type ConnectionGater interface {
connmgr.ConnectionGater connmgr.ConnectionGater
...@@ -138,6 +147,18 @@ func (conf *Config) Disabled() bool { ...@@ -138,6 +147,18 @@ func (conf *Config) Disabled() bool {
return conf.DisableP2P return conf.DisableP2P
} }
func (conf *Config) PeerScoringParams() *pubsub.PeerScoreParams {
return &conf.PeerScoring
}
func (conf *Config) BanPeers() bool {
return conf.BanningEnabled
}
func (conf *Config) TopicScoringParams() *pubsub.TopicScoreParams {
return &conf.TopicScoring
}
const maxMeshParam = 1000 const maxMeshParam = 1000
func (conf *Config) Check() error { func (conf *Config) Check() error {
......
...@@ -40,6 +40,8 @@ const ( ...@@ -40,6 +40,8 @@ const (
DefaultMeshDlo = 6 // topic stable mesh low watermark DefaultMeshDlo = 6 // topic stable mesh low watermark
DefaultMeshDhi = 12 // topic stable mesh high watermark DefaultMeshDhi = 12 // topic stable mesh high watermark
DefaultMeshDlazy = 6 // gossip target DefaultMeshDlazy = 6 // gossip target
// peerScoreInspectFrequency is the frequency at which peer scores are inspected
peerScoreInspectFrequency = 15 * time.Second
) )
// Message domains, the msg id function uncompresses to keep data monomorphic, // Message domains, the msg id function uncompresses to keep data monomorphic,
...@@ -49,6 +51,9 @@ var MessageDomainInvalidSnappy = [4]byte{0, 0, 0, 0} ...@@ -49,6 +51,9 @@ var MessageDomainInvalidSnappy = [4]byte{0, 0, 0, 0}
var MessageDomainValidSnappy = [4]byte{1, 0, 0, 0} var MessageDomainValidSnappy = [4]byte{1, 0, 0, 0}
type GossipSetupConfigurables interface { type GossipSetupConfigurables interface {
PeerScoringParams() *pubsub.PeerScoreParams
TopicScoringParams() *pubsub.TopicScoreParams
BanPeers() bool
ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Option
} }
...@@ -56,8 +61,10 @@ type GossipRuntimeConfig interface { ...@@ -56,8 +61,10 @@ type GossipRuntimeConfig interface {
P2PSequencerAddress() common.Address P2PSequencerAddress() common.Address
} }
//go:generate mockery --name GossipMetricer
type GossipMetricer interface { type GossipMetricer interface {
RecordGossipEvent(evType int32) RecordGossipEvent(evType int32)
RecordPeerScoring(peerID peer.ID, score float64)
} }
func blocksTopicV1(cfg *rollup.Config) string { func blocksTopicV1(cfg *rollup.Config) string {
...@@ -143,7 +150,7 @@ func BuildGlobalGossipParams(cfg *rollup.Config) pubsub.GossipSubParams { ...@@ -143,7 +150,7 @@ func BuildGlobalGossipParams(cfg *rollup.Config) pubsub.GossipSubParams {
// NewGossipSub configures a new pubsub instance with the specified parameters. // NewGossipSub configures a new pubsub instance with the specified parameters.
// PubSub uses a GossipSubRouter as it's router under the hood. // PubSub uses a GossipSubRouter as it's router under the hood.
func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config, gossipConf GossipSetupConfigurables, m GossipMetricer) (*pubsub.PubSub, error) { func NewGossipSub(p2pCtx context.Context, h host.Host, g ConnectionGater, cfg *rollup.Config, gossipConf GossipSetupConfigurables, m GossipMetricer, log log.Logger) (*pubsub.PubSub, error) {
denyList, err := pubsub.NewTimeCachedBlacklist(30 * time.Second) denyList, err := pubsub.NewTimeCachedBlacklist(30 * time.Second)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -164,9 +171,9 @@ func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config, gossi ...@@ -164,9 +171,9 @@ func NewGossipSub(p2pCtx context.Context, h host.Host, cfg *rollup.Config, gossi
pubsub.WithGossipSubParams(params), pubsub.WithGossipSubParams(params),
pubsub.WithEventTracer(&gossipTracer{m: m}), 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(&params)...)
return pubsub.NewGossipSub(p2pCtx, h, gossipOpts...) return pubsub.NewGossipSub(p2pCtx, h, gossipOpts...)
// TODO: pubsub.WithPeerScoreInspect(inspect, InspectInterval) to update peerstore scores with gossip scores
} }
func validationResultString(v pubsub.ValidationResult) string { func validationResultString(v pubsub.ValidationResult) string {
...@@ -431,7 +438,7 @@ func (p *publisher) Close() error { ...@@ -431,7 +438,7 @@ func (p *publisher) Close() error {
return p.blocksTopic.Close() return p.blocksTopic.Close()
} }
func JoinGossip(p2pCtx context.Context, self peer.ID, ps *pubsub.PubSub, log log.Logger, cfg *rollup.Config, runCfg GossipRuntimeConfig, gossipIn GossipIn) (GossipOut, error) { func JoinGossip(p2pCtx context.Context, self peer.ID, topicScoreParams *pubsub.TopicScoreParams, ps *pubsub.PubSub, log log.Logger, cfg *rollup.Config, runCfg GossipRuntimeConfig, gossipIn GossipIn) (GossipOut, error) {
val := guardGossipValidator(log, logValidationResult(self, "validated block", log, BuildBlocksValidator(log, cfg, runCfg))) val := guardGossipValidator(log, logValidationResult(self, "validated block", log, BuildBlocksValidator(log, cfg, runCfg)))
blocksTopicName := blocksTopicV1(cfg) blocksTopicName := blocksTopicV1(cfg)
err := ps.RegisterTopicValidator(blocksTopicName, err := ps.RegisterTopicValidator(blocksTopicName,
...@@ -451,11 +458,14 @@ func JoinGossip(p2pCtx context.Context, self peer.ID, ps *pubsub.PubSub, log log ...@@ -451,11 +458,14 @@ func JoinGossip(p2pCtx context.Context, self peer.ID, ps *pubsub.PubSub, log log
} }
go LogTopicEvents(p2pCtx, log.New("topic", "blocks"), blocksTopicEvents) go LogTopicEvents(p2pCtx, log.New("topic", "blocks"), blocksTopicEvents)
// TODO: block topic scoring parameters // A [TimeInMeshQuantum] value of 0 means the topic score is disabled.
// See prysm: https://github.com/prysmaticlabs/prysm/blob/develop/beacon-chain/p2p/gossip_scoring_params.go // If we passed a topicScoreParams with [TimeInMeshQuantum] set to 0,
// And research from lighthouse: https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c // libp2p errors since the params will be rejected.
// And docs: https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#topic-parameter-calculation-and-decay if topicScoreParams != nil && topicScoreParams.TimeInMeshQuantum != 0 {
//err := blocksTopic.SetScoreParams(&pubsub.TopicScoreParams{......}) if err = blocksTopic.SetScoreParams(topicScoreParams); err != nil {
return nil, fmt.Errorf("failed to set topic score params: %w", err)
}
}
subscription, err := blocksTopic.Subscribe() subscription, err := blocksTopic.Subscribe()
if err != nil { if err != nil {
......
...@@ -168,7 +168,7 @@ func TestP2PFull(t *testing.T) { ...@@ -168,7 +168,7 @@ func TestP2PFull(t *testing.T) {
_, err = p2pClientA.DiscoveryTable(ctx) _, err = p2pClientA.DiscoveryTable(ctx)
// rpc does not preserve error type // rpc does not preserve error type
require.Equal(t, err.Error(), DisabledDiscovery.Error(), "expecting discv5 to be disabled") require.Equal(t, err.Error(), ErrDisabledDiscovery.Error(), "expecting discv5 to be disabled")
require.NoError(t, p2pClientA.BlockPeer(ctx, hostB.ID())) require.NoError(t, p2pClientA.BlockPeer(ctx, hostB.ID()))
blockedPeers, err := p2pClientA.ListBlockedPeers(ctx) blockedPeers, err := p2pClientA.ListBlockedPeers(ctx)
......
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
control "github.com/libp2p/go-libp2p/core/control"
mock "github.com/stretchr/testify/mock"
multiaddr "github.com/multiformats/go-multiaddr"
net "net"
network "github.com/libp2p/go-libp2p/core/network"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// ConnectionGater is an autogenerated mock type for the ConnectionGater type
type ConnectionGater struct {
mock.Mock
}
// BlockAddr provides a mock function with given fields: ip
func (_m *ConnectionGater) BlockAddr(ip net.IP) error {
ret := _m.Called(ip)
var r0 error
if rf, ok := ret.Get(0).(func(net.IP) error); ok {
r0 = rf(ip)
} else {
r0 = ret.Error(0)
}
return r0
}
// BlockPeer provides a mock function with given fields: p
func (_m *ConnectionGater) BlockPeer(p peer.ID) error {
ret := _m.Called(p)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID) error); ok {
r0 = rf(p)
} else {
r0 = ret.Error(0)
}
return r0
}
// BlockSubnet provides a mock function with given fields: ipnet
func (_m *ConnectionGater) BlockSubnet(ipnet *net.IPNet) error {
ret := _m.Called(ipnet)
var r0 error
if rf, ok := ret.Get(0).(func(*net.IPNet) error); ok {
r0 = rf(ipnet)
} else {
r0 = ret.Error(0)
}
return r0
}
// InterceptAccept provides a mock function with given fields: _a0
func (_m *ConnectionGater) InterceptAccept(_a0 network.ConnMultiaddrs) bool {
ret := _m.Called(_a0)
var r0 bool
if rf, ok := ret.Get(0).(func(network.ConnMultiaddrs) bool); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// InterceptAddrDial provides a mock function with given fields: _a0, _a1
func (_m *ConnectionGater) InterceptAddrDial(_a0 peer.ID, _a1 multiaddr.Multiaddr) bool {
ret := _m.Called(_a0, _a1)
var r0 bool
if rf, ok := ret.Get(0).(func(peer.ID, multiaddr.Multiaddr) bool); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// InterceptPeerDial provides a mock function with given fields: p
func (_m *ConnectionGater) InterceptPeerDial(p peer.ID) bool {
ret := _m.Called(p)
var r0 bool
if rf, ok := ret.Get(0).(func(peer.ID) bool); ok {
r0 = rf(p)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// InterceptSecured provides a mock function with given fields: _a0, _a1, _a2
func (_m *ConnectionGater) InterceptSecured(_a0 network.Direction, _a1 peer.ID, _a2 network.ConnMultiaddrs) bool {
ret := _m.Called(_a0, _a1, _a2)
var r0 bool
if rf, ok := ret.Get(0).(func(network.Direction, peer.ID, network.ConnMultiaddrs) bool); ok {
r0 = rf(_a0, _a1, _a2)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// InterceptUpgraded provides a mock function with given fields: _a0
func (_m *ConnectionGater) InterceptUpgraded(_a0 network.Conn) (bool, control.DisconnectReason) {
ret := _m.Called(_a0)
var r0 bool
if rf, ok := ret.Get(0).(func(network.Conn) bool); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(bool)
}
var r1 control.DisconnectReason
if rf, ok := ret.Get(1).(func(network.Conn) control.DisconnectReason); ok {
r1 = rf(_a0)
} else {
r1 = ret.Get(1).(control.DisconnectReason)
}
return r0, r1
}
// ListBlockedAddrs provides a mock function with given fields:
func (_m *ConnectionGater) ListBlockedAddrs() []net.IP {
ret := _m.Called()
var r0 []net.IP
if rf, ok := ret.Get(0).(func() []net.IP); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]net.IP)
}
}
return r0
}
// ListBlockedPeers provides a mock function with given fields:
func (_m *ConnectionGater) ListBlockedPeers() []peer.ID {
ret := _m.Called()
var r0 []peer.ID
if rf, ok := ret.Get(0).(func() []peer.ID); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]peer.ID)
}
}
return r0
}
// ListBlockedSubnets provides a mock function with given fields:
func (_m *ConnectionGater) ListBlockedSubnets() []*net.IPNet {
ret := _m.Called()
var r0 []*net.IPNet
if rf, ok := ret.Get(0).(func() []*net.IPNet); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*net.IPNet)
}
}
return r0
}
// UnblockAddr provides a mock function with given fields: ip
func (_m *ConnectionGater) UnblockAddr(ip net.IP) error {
ret := _m.Called(ip)
var r0 error
if rf, ok := ret.Get(0).(func(net.IP) error); ok {
r0 = rf(ip)
} else {
r0 = ret.Error(0)
}
return r0
}
// UnblockPeer provides a mock function with given fields: p
func (_m *ConnectionGater) UnblockPeer(p peer.ID) error {
ret := _m.Called(p)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID) error); ok {
r0 = rf(p)
} else {
r0 = ret.Error(0)
}
return r0
}
// UnblockSubnet provides a mock function with given fields: ipnet
func (_m *ConnectionGater) UnblockSubnet(ipnet *net.IPNet) error {
ret := _m.Called(ipnet)
var r0 error
if rf, ok := ret.Get(0).(func(*net.IPNet) error); ok {
r0 = rf(ipnet)
} else {
r0 = ret.Error(0)
}
return r0
}
type mockConstructorTestingTNewConnectionGater interface {
mock.TestingT
Cleanup(func())
}
// NewConnectionGater creates a new instance of ConnectionGater. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewConnectionGater(t mockConstructorTestingTNewConnectionGater) *ConnectionGater {
mock := &ConnectionGater{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// GossipMetricer is an autogenerated mock type for the GossipMetricer type
type GossipMetricer struct {
mock.Mock
}
// RecordGossipEvent provides a mock function with given fields: evType
func (_m *GossipMetricer) RecordGossipEvent(evType int32) {
_m.Called(evType)
}
// RecordPeerScoring provides a mock function with given fields: peerID, score
func (_m *GossipMetricer) RecordPeerScoring(peerID peer.ID, score float64) {
_m.Called(peerID, score)
}
type mockConstructorTestingTNewGossipMetricer interface {
mock.TestingT
Cleanup(func())
}
// NewGossipMetricer creates a new instance of GossipMetricer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewGossipMetricer(t mockConstructorTestingTNewGossipMetricer) *GossipMetricer {
mock := &GossipMetricer{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// PeerGater is an autogenerated mock type for the PeerGater type
type PeerGater struct {
mock.Mock
}
// Update provides a mock function with given fields: _a0, _a1
func (_m *PeerGater) Update(_a0 peer.ID, _a1 float64) {
_m.Called(_a0, _a1)
}
type mockConstructorTestingTNewPeerGater interface {
mock.TestingT
Cleanup(func())
}
// NewPeerGater creates a new instance of PeerGater. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPeerGater(t mockConstructorTestingTNewPeerGater) *PeerGater {
mock := &PeerGater{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// Peerstore is an autogenerated mock type for the Peerstore type
type Peerstore struct {
mock.Mock
}
// PeerInfo provides a mock function with given fields: _a0
func (_m *Peerstore) PeerInfo(_a0 peer.ID) peer.AddrInfo {
ret := _m.Called(_a0)
var r0 peer.AddrInfo
if rf, ok := ret.Get(0).(func(peer.ID) peer.AddrInfo); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(peer.AddrInfo)
}
return r0
}
// Peers provides a mock function with given fields:
func (_m *Peerstore) Peers() peer.IDSlice {
ret := _m.Called()
var r0 peer.IDSlice
if rf, ok := ret.Get(0).(func() peer.IDSlice); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(peer.IDSlice)
}
}
return r0
}
type mockConstructorTestingTNewPeerstore interface {
mock.TestingT
Cleanup(func())
}
// NewPeerstore creates a new instance of Peerstore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPeerstore(t mockConstructorTestingTNewPeerstore) *Peerstore {
mock := &Peerstore{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
...@@ -76,12 +76,11 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l ...@@ -76,12 +76,11 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
// notify of any new connections/streams/etc. // notify of any new connections/streams/etc.
n.host.Network().Notify(NewNetworkNotifier(log, metrics)) n.host.Network().Notify(NewNetworkNotifier(log, metrics))
// note: the IDDelta functionality was removed from libP2P, and no longer needs to be explicitly disabled. // note: the IDDelta functionality was removed from libP2P, and no longer needs to be explicitly disabled.
n.gs, err = NewGossipSub(resourcesCtx, n.host, rollupCfg, setup, metrics) n.gs, err = NewGossipSub(resourcesCtx, n.host, n.gater, rollupCfg, setup, metrics, log)
if err != nil { if err != nil {
return fmt.Errorf("failed to start gossipsub router: %w", err) return fmt.Errorf("failed to start gossipsub router: %w", err)
} }
n.gsOut, err = JoinGossip(resourcesCtx, n.host.ID(), setup.TopicScoringParams(), n.gs, log, rollupCfg, runCfg, gossipIn)
n.gsOut, err = JoinGossip(resourcesCtx, n.host.ID(), n.gs, log, rollupCfg, runCfg, gossipIn)
if err != nil { if err != nil {
return fmt.Errorf("failed to join blocks gossip topic: %w", err) return fmt.Errorf("failed to join blocks gossip topic: %w", err)
} }
......
package p2p
import (
log "github.com/ethereum/go-ethereum/log"
peer "github.com/libp2p/go-libp2p/core/peer"
slices "golang.org/x/exp/slices"
)
// ConnectionFactor is the factor by which we multiply the connection score.
const ConnectionFactor = -10
// PeerScoreThreshold is the threshold at which we block a peer.
const PeerScoreThreshold = -100
// gater is an internal implementation of the [PeerGater] interface.
type gater struct {
connGater ConnectionGater
log log.Logger
banEnabled bool
}
// PeerGater manages the connection gating of peers.
//
//go:generate mockery --name PeerGater --output mocks/
type PeerGater interface {
// Update handles a peer score update and blocks/unblocks the peer if necessary.
Update(peer.ID, float64)
}
// NewPeerGater returns a new peer gater.
func NewPeerGater(connGater ConnectionGater, log log.Logger, banEnabled bool) PeerGater {
return &gater{
connGater: connGater,
log: log,
banEnabled: banEnabled,
}
}
// Update handles a peer score update and blocks/unblocks the peer if necessary.
func (s *gater) Update(id peer.ID, score float64) {
// Check if the peer score is below the threshold
// If so, we need to block the peer
if score < PeerScoreThreshold && s.banEnabled {
s.log.Warn("peer blocking enabled, blocking peer", "id", id.String(), "score", score)
err := s.connGater.BlockPeer(id)
s.log.Warn("connection gater failed to block peer", id.String(), "err", err)
}
// Unblock peers whose score has recovered to an acceptable level
if (score > PeerScoreThreshold) && slices.Contains(s.connGater.ListBlockedPeers(), id) {
err := s.connGater.UnblockPeer(id)
s.log.Warn("connection gater failed to unblock peer", id.String(), "err", err)
}
}
package p2p_test
import (
"testing"
p2p "github.com/ethereum-optimism/optimism/op-node/p2p"
p2pMocks "github.com/ethereum-optimism/optimism/op-node/p2p/mocks"
testlog "github.com/ethereum-optimism/optimism/op-node/testlog"
log "github.com/ethereum/go-ethereum/log"
peer "github.com/libp2p/go-libp2p/core/peer"
suite "github.com/stretchr/testify/suite"
)
// PeerGaterTestSuite tests peer parameterization.
type PeerGaterTestSuite struct {
suite.Suite
mockGater *p2pMocks.ConnectionGater
logger log.Logger
}
// SetupTest sets up the test suite.
func (testSuite *PeerGaterTestSuite) SetupTest() {
testSuite.mockGater = &p2pMocks.ConnectionGater{}
testSuite.logger = testlog.Logger(testSuite.T(), log.LvlError)
}
// TestPeerGater runs the PeerGaterTestSuite.
func TestPeerGater(t *testing.T) {
suite.Run(t, new(PeerGaterTestSuite))
}
// TestPeerScoreConstants validates the peer score constants.
func (testSuite *PeerGaterTestSuite) TestPeerScoreConstants() {
testSuite.Equal(-10, p2p.ConnectionFactor)
testSuite.Equal(-100, p2p.PeerScoreThreshold)
}
// TestPeerGaterUpdate tests the peer gater update hook.
func (testSuite *PeerGaterTestSuite) TestPeerGaterUpdate() {
gater := p2p.NewPeerGater(
testSuite.mockGater,
testSuite.logger,
true,
)
// Mock a connection gater peer block call
// Since the peer score is below the [PeerScoreThreshold] of -100,
// the [BlockPeer] method should be called
testSuite.mockGater.On("BlockPeer", peer.ID("peer1")).Return(nil)
// Apply the peer gater update
gater.Update(peer.ID("peer1"), float64(-100))
}
// TestPeerGaterUpdateNoBanning tests the peer gater update hook without banning set
func (testSuite *PeerGaterTestSuite) TestPeerGaterUpdateNoBanning() {
gater := p2p.NewPeerGater(
testSuite.mockGater,
testSuite.logger,
false,
)
// Notice: [BlockPeer] should not be called since banning is not enabled
gater.Update(peer.ID("peer1"), float64(-100000))
}
package p2p
import (
"fmt"
"math"
"time"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/peer"
)
// DecayToZero is the decay factor for a peer's score to zero.
const DecayToZero = 0.01
// ScoreDecay returns the decay factor for a given duration.
func ScoreDecay(duration time.Duration, slot time.Duration) float64 {
numOfTimes := duration / slot
return math.Pow(DecayToZero, 1/float64(numOfTimes))
}
// LightPeerScoreParams is an instantiation of [pubsub.PeerScoreParams] with light penalties.
// See [PeerScoreParams] for detailed documentation.
//
// [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams
var LightPeerScoreParams = func(blockTime uint64) pubsub.PeerScoreParams {
slot := time.Duration(blockTime) * time.Second
if slot == 0 {
slot = 2 * time.Second
}
// We initialize an "epoch" as 6 blocks suggesting 6 blocks,
// each taking ~ 2 seconds, is 12 seconds
epoch := 6 * slot
tenEpochs := 10 * epoch
oneHundredEpochs := 100 * epoch
return pubsub.PeerScoreParams{
Topics: make(map[string]*pubsub.TopicScoreParams),
TopicScoreCap: 34,
AppSpecificScore: func(p peer.ID) float64 {
return 0
},
AppSpecificWeight: 1,
IPColocationFactorWeight: -35,
IPColocationFactorThreshold: 10,
IPColocationFactorWhitelist: nil,
BehaviourPenaltyWeight: -16,
BehaviourPenaltyThreshold: 6,
BehaviourPenaltyDecay: ScoreDecay(tenEpochs, slot),
DecayInterval: slot,
DecayToZero: DecayToZero,
RetainScore: oneHundredEpochs,
}
}
// DisabledPeerScoreParams is an instantiation of [pubsub.PeerScoreParams] where all scoring is disabled.
// See [PeerScoreParams] for detailed documentation.
//
// [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams
var DisabledPeerScoreParams = func(blockTime uint64) pubsub.PeerScoreParams {
slot := time.Duration(blockTime) * time.Second
if slot == 0 {
slot = 2 * time.Second
}
// We initialize an "epoch" as 6 blocks suggesting 6 blocks,
// each taking ~ 2 seconds, is 12 seconds
epoch := 6 * slot
tenEpochs := 10 * epoch
oneHundredEpochs := 100 * epoch
return pubsub.PeerScoreParams{
Topics: make(map[string]*pubsub.TopicScoreParams),
// 0 represent no cap
TopicScoreCap: 0,
AppSpecificScore: func(p peer.ID) float64 {
return 0
},
AppSpecificWeight: 1,
// ignore colocation scoring
IPColocationFactorWeight: 0,
IPColocationFactorWhitelist: nil,
// 0 disables the behaviour penalty
BehaviourPenaltyWeight: 0,
BehaviourPenaltyDecay: ScoreDecay(tenEpochs, slot),
DecayInterval: slot,
DecayToZero: DecayToZero,
RetainScore: oneHundredEpochs,
}
}
// PeerScoreParamsByName is a map of name to function that returns a [pubsub.PeerScoreParams] based on the provided [rollup.Config].
var PeerScoreParamsByName = map[string](func(blockTime uint64) pubsub.PeerScoreParams){
"light": LightPeerScoreParams,
"none": DisabledPeerScoreParams,
}
// AvailablePeerScoreParams returns a list of available peer score params.
// These can be used as an input to [GetPeerScoreParams] which returns the
// corresponding [pubsub.PeerScoreParams].
func AvailablePeerScoreParams() []string {
var params []string
for name := range PeerScoreParamsByName {
params = append(params, name)
}
return params
}
// GetPeerScoreParams returns the [pubsub.PeerScoreParams] for the given name.
func GetPeerScoreParams(name string, blockTime uint64) (pubsub.PeerScoreParams, error) {
params, ok := PeerScoreParamsByName[name]
if !ok {
return pubsub.PeerScoreParams{}, fmt.Errorf("invalid params %s", name)
}
return params(blockTime), nil
}
// NewPeerScoreThresholds returns a default [pubsub.PeerScoreThresholds].
// See [PeerScoreThresholds] for detailed documentation.
//
// [PeerScoreThresholds]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreThresholds
func NewPeerScoreThresholds() pubsub.PeerScoreThresholds {
return pubsub.PeerScoreThresholds{
SkipAtomicValidation: false,
GossipThreshold: -10,
PublishThreshold: -40,
GraylistThreshold: -40,
AcceptPXThreshold: 20,
OpportunisticGraftThreshold: 0.05,
}
}
package p2p
import (
"math"
"sort"
"testing"
"time"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/stretchr/testify/suite"
)
// PeerParamsTestSuite tests peer parameterization.
type PeerParamsTestSuite struct {
suite.Suite
}
// TestPeerParams runs the PeerParamsTestSuite.
func TestPeerParams(t *testing.T) {
suite.Run(t, new(PeerParamsTestSuite))
}
// TestPeerScoreConstants validates the peer score constants.
func (testSuite *PeerParamsTestSuite) TestPeerScoreConstants() {
testSuite.Equal(0.01, DecayToZero)
}
// TestAvailablePeerScoreParams validates the available peer score parameters.
func (testSuite *PeerParamsTestSuite) TestAvailablePeerScoreParams() {
available := AvailablePeerScoreParams()
sort.Strings(available)
expected := []string{"light", "none"}
testSuite.Equal(expected, available)
}
// TestNewPeerScoreThresholds validates the peer score thresholds.
//
// This is tested to ensure that the thresholds are not modified and missed in review.
func (testSuite *PeerParamsTestSuite) TestNewPeerScoreThresholds() {
thresholds := NewPeerScoreThresholds()
expected := pubsub.PeerScoreThresholds{
SkipAtomicValidation: false,
GossipThreshold: -10,
PublishThreshold: -40,
GraylistThreshold: -40,
AcceptPXThreshold: 20,
OpportunisticGraftThreshold: 0.05,
}
testSuite.Equal(expected, thresholds)
}
// TestGetPeerScoreParams validates the peer score parameters.
func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams() {
params, err := GetPeerScoreParams("light", 1)
testSuite.NoError(err)
expected := LightPeerScoreParams(1)
testSuite.Equal(expected.DecayInterval, params.DecayInterval)
testSuite.Equal(time.Duration(1)*time.Second, params.DecayInterval)
params, err = GetPeerScoreParams("none", 1)
testSuite.NoError(err)
expected = DisabledPeerScoreParams(1)
testSuite.Equal(expected.DecayInterval, params.DecayInterval)
testSuite.Equal(time.Duration(1)*time.Second, params.DecayInterval)
_, err = GetPeerScoreParams("invalid", 1)
testSuite.Error(err)
}
// TestLightPeerScoreParams validates the light peer score params.
func (testSuite *PeerParamsTestSuite) TestLightPeerScoreParams() {
blockTime := uint64(1)
slot := time.Duration(blockTime) * time.Second
epoch := 6 * slot
oneHundredEpochs := 100 * epoch
// calculate the behavior penalty decay
duration := 10 * epoch
decay := math.Pow(DecayToZero, 1/float64(duration/slot))
testSuite.Equal(0.9261187281287935, decay)
// Test the params
params, err := GetPeerScoreParams("light", blockTime)
testSuite.NoError(err)
testSuite.Equal(params.Topics, make(map[string]*pubsub.TopicScoreParams))
testSuite.Equal(params.TopicScoreCap, float64(34))
// testSuite.Equal(params.AppSpecificScore("alice"), float(0))
testSuite.Equal(params.AppSpecificWeight, float64(1))
testSuite.Equal(params.IPColocationFactorWeight, float64(-35))
testSuite.Equal(params.IPColocationFactorThreshold, int(10))
testSuite.Nil(params.IPColocationFactorWhitelist)
testSuite.Equal(params.BehaviourPenaltyWeight, float64(-16))
testSuite.Equal(params.BehaviourPenaltyThreshold, float64(6))
testSuite.Equal(params.BehaviourPenaltyDecay, decay)
testSuite.Equal(params.DecayInterval, slot)
testSuite.Equal(params.DecayToZero, DecayToZero)
testSuite.Equal(params.RetainScore, oneHundredEpochs)
}
// TestDisabledPeerScoreParams validates the disabled peer score params.
func (testSuite *PeerParamsTestSuite) TestDisabledPeerScoreParams() {
blockTime := uint64(1)
slot := time.Duration(blockTime) * time.Second
epoch := 6 * slot
oneHundredEpochs := 100 * epoch
// calculate the behavior penalty decay
duration := 10 * epoch
decay := math.Pow(DecayToZero, 1/float64(duration/slot))
testSuite.Equal(0.9261187281287935, decay)
// Test the params
params, err := GetPeerScoreParams("none", blockTime)
testSuite.NoError(err)
testSuite.Equal(params.Topics, make(map[string]*pubsub.TopicScoreParams))
testSuite.Equal(params.TopicScoreCap, float64(0))
testSuite.Equal(params.AppSpecificWeight, float64(1))
testSuite.Equal(params.IPColocationFactorWeight, float64(0))
testSuite.Nil(params.IPColocationFactorWhitelist)
testSuite.Equal(params.BehaviourPenaltyWeight, float64(0))
testSuite.Equal(params.BehaviourPenaltyDecay, decay)
testSuite.Equal(params.DecayInterval, slot)
testSuite.Equal(params.DecayToZero, DecayToZero)
testSuite.Equal(params.RetainScore, oneHundredEpochs)
}
// TestParamsZeroBlockTime validates peer score params use default slot for 0 block time.
func (testSuite *PeerParamsTestSuite) TestParamsZeroBlockTime() {
slot := 2 * time.Second
params, err := GetPeerScoreParams("none", uint64(0))
testSuite.NoError(err)
testSuite.Equal(params.DecayInterval, slot)
params, err = GetPeerScoreParams("light", uint64(0))
testSuite.NoError(err)
testSuite.Equal(params.DecayInterval, slot)
}
package p2p
import (
log "github.com/ethereum/go-ethereum/log"
pubsub "github.com/libp2p/go-libp2p-pubsub"
peer "github.com/libp2p/go-libp2p/core/peer"
)
type scorer struct {
peerStore Peerstore
metricer GossipMetricer
log log.Logger
gater PeerGater
}
// Peerstore is a subset of the libp2p peerstore.Peerstore interface.
//
//go:generate mockery --name Peerstore --output mocks/
type Peerstore interface {
// PeerInfo returns a peer.PeerInfo struct for given peer.ID.
// This is a small slice of the information Peerstore has on
// that peer, useful to other services.
PeerInfo(peer.ID) peer.AddrInfo
// Peers returns all of the peer IDs stored across all inner stores.
Peers() peer.IDSlice
}
// Scorer is a peer scorer that scores peers based on application-specific metrics.
type Scorer interface {
OnConnect()
OnDisconnect()
SnapshotHook() pubsub.ExtendedPeerScoreInspectFn
}
// NewScorer returns a new peer scorer.
func NewScorer(peerGater PeerGater, peerStore Peerstore, metricer GossipMetricer, log log.Logger) Scorer {
return &scorer{
peerStore: peerStore,
metricer: metricer,
log: log,
gater: peerGater,
}
}
// SnapshotHook returns a function that is called periodically by the pubsub library to inspect the peer scores.
// It is passed into the pubsub library as a [pubsub.ExtendedPeerScoreInspectFn] in the [pubsub.WithPeerScoreInspect] option.
// The returned [pubsub.ExtendedPeerScoreInspectFn] is called with a mapping of peer IDs to peer score snapshots.
func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
return func(m map[peer.ID]*pubsub.PeerScoreSnapshot) {
for id, snap := range m {
// Record peer score in the metricer
s.metricer.RecordPeerScoring(id, snap.Score)
// Update with the peer gater
s.gater.Update(id, snap.Score)
}
}
}
// OnConnect is called when a peer connects.
// See [p2p.NotificationsMetricer] for invocation.
func (s *scorer) OnConnect() {
// no-op
}
// OnDisconnect is called when a peer disconnects.
// See [p2p.NotificationsMetricer] for invocation.
func (s *scorer) OnDisconnect() {
// no-op
}
package p2p_test
import (
"testing"
p2p "github.com/ethereum-optimism/optimism/op-node/p2p"
p2pMocks "github.com/ethereum-optimism/optimism/op-node/p2p/mocks"
"github.com/ethereum-optimism/optimism/op-node/testlog"
log "github.com/ethereum/go-ethereum/log"
pubsub "github.com/libp2p/go-libp2p-pubsub"
peer "github.com/libp2p/go-libp2p/core/peer"
suite "github.com/stretchr/testify/suite"
)
// PeerScorerTestSuite tests peer parameterization.
type PeerScorerTestSuite struct {
suite.Suite
// mockConnGater *p2pMocks.ConnectionGater
mockGater *p2pMocks.PeerGater
mockStore *p2pMocks.Peerstore
mockMetricer *p2pMocks.GossipMetricer
logger log.Logger
}
// SetupTest sets up the test suite.
func (testSuite *PeerScorerTestSuite) SetupTest() {
testSuite.mockGater = &p2pMocks.PeerGater{}
// testSuite.mockConnGater = &p2pMocks.ConnectionGater{}
testSuite.mockStore = &p2pMocks.Peerstore{}
testSuite.mockMetricer = &p2pMocks.GossipMetricer{}
testSuite.logger = testlog.Logger(testSuite.T(), log.LvlError)
}
// TestPeerScorer runs the PeerScorerTestSuite.
func TestPeerScorer(t *testing.T) {
suite.Run(t, new(PeerScorerTestSuite))
}
// TestPeerScorerOnConnect ensures we can call the OnConnect method on the peer scorer.
func (testSuite *PeerScorerTestSuite) TestPeerScorerOnConnect() {
scorer := p2p.NewScorer(
testSuite.mockGater,
testSuite.mockStore,
testSuite.mockMetricer,
testSuite.logger,
)
scorer.OnConnect()
}
// TestPeerScorerOnDisconnect ensures we can call the OnDisconnect method on the peer scorer.
func (testSuite *PeerScorerTestSuite) TestPeerScorerOnDisconnect() {
scorer := p2p.NewScorer(
testSuite.mockGater,
testSuite.mockStore,
testSuite.mockMetricer,
testSuite.logger,
)
scorer.OnDisconnect()
}
// TestSnapshotHook tests running the snapshot hook on the peer scorer.
func (testSuite *PeerScorerTestSuite) TestSnapshotHook() {
scorer := p2p.NewScorer(
testSuite.mockGater,
testSuite.mockStore,
testSuite.mockMetricer,
testSuite.logger,
)
inspectFn := scorer.SnapshotHook()
// Mock the snapshot updates
// This doesn't return anything
testSuite.mockMetricer.On("RecordPeerScoring", peer.ID("peer1"), float64(-100)).Return(nil)
// Mock the peer gater call
testSuite.mockGater.On("Update", peer.ID("peer1"), float64(-100)).Return(nil)
// Apply the snapshot
snapshotMap := map[peer.ID]*pubsub.PeerScoreSnapshot{
peer.ID("peer1"): {
Score: -100,
},
}
inspectFn(snapshotMap)
}
// TestSnapshotHookBlockPeer tests running the snapshot hook on the peer scorer with a peer score below the threshold.
// This implies that the peer should be blocked.
func (testSuite *PeerScorerTestSuite) TestSnapshotHookBlockPeer() {
scorer := p2p.NewScorer(
testSuite.mockGater,
testSuite.mockStore,
testSuite.mockMetricer,
testSuite.logger,
)
inspectFn := scorer.SnapshotHook()
// Mock the snapshot updates
// This doesn't return anything
testSuite.mockMetricer.On("RecordPeerScoring", peer.ID("peer1"), float64(-101)).Return(nil)
// Mock the peer gater call
testSuite.mockGater.On("Update", peer.ID("peer1"), float64(-101)).Return(nil)
// Apply the snapshot
snapshotMap := map[peer.ID]*pubsub.PeerScoreSnapshot{
peer.ID("peer1"): {
Score: -101,
},
}
inspectFn(snapshotMap)
}
package p2p
import (
log "github.com/ethereum/go-ethereum/log"
pubsub "github.com/libp2p/go-libp2p-pubsub"
host "github.com/libp2p/go-libp2p/core/host"
)
// ConfigurePeerScoring configures the peer scoring parameters for the pubsub
func ConfigurePeerScoring(h host.Host, g ConnectionGater, gossipConf GossipSetupConfigurables, m GossipMetricer, log log.Logger) []pubsub.Option {
// If we want to completely disable scoring config here, we can use the [peerScoringParams]
// to return early without returning any [pubsub.Option].
peerScoreParams := gossipConf.PeerScoringParams()
peerScoreThresholds := NewPeerScoreThresholds()
banEnabled := gossipConf.BanPeers()
peerGater := NewPeerGater(g, log, banEnabled)
scorer := NewScorer(peerGater, h.Peerstore(), m, log)
opts := []pubsub.Option{}
// Check the app specific score since libp2p doesn't export it's [validate] function :/
if peerScoreParams != nil && peerScoreParams.AppSpecificScore != nil {
opts = []pubsub.Option{
pubsub.WithPeerScore(peerScoreParams, &peerScoreThresholds),
pubsub.WithPeerScoreInspect(scorer.SnapshotHook(), peerScoreInspectFrequency),
}
} else {
log.Warn("Proceeding with no peer scoring...\nMissing AppSpecificScore in peer scoring params")
}
return opts
}
package p2p_test
import (
"context"
"fmt"
"math/rand"
"testing"
"time"
p2p "github.com/ethereum-optimism/optimism/op-node/p2p"
p2pMocks "github.com/ethereum-optimism/optimism/op-node/p2p/mocks"
testlog "github.com/ethereum-optimism/optimism/op-node/testlog"
mock "github.com/stretchr/testify/mock"
suite "github.com/stretchr/testify/suite"
log "github.com/ethereum/go-ethereum/log"
pubsub "github.com/libp2p/go-libp2p-pubsub"
host "github.com/libp2p/go-libp2p/core/host"
peer "github.com/libp2p/go-libp2p/core/peer"
bhost "github.com/libp2p/go-libp2p/p2p/host/blank"
tswarm "github.com/libp2p/go-libp2p/p2p/net/swarm/testing"
)
// PeerScoresTestSuite tests peer parameterization.
type PeerScoresTestSuite struct {
suite.Suite
mockGater *p2pMocks.ConnectionGater
mockStore *p2pMocks.Peerstore
mockMetricer *p2pMocks.GossipMetricer
logger log.Logger
}
// SetupTest sets up the test suite.
func (testSuite *PeerScoresTestSuite) SetupTest() {
testSuite.mockGater = &p2pMocks.ConnectionGater{}
testSuite.mockStore = &p2pMocks.Peerstore{}
testSuite.mockMetricer = &p2pMocks.GossipMetricer{}
testSuite.logger = testlog.Logger(testSuite.T(), log.LvlError)
}
// TestPeerScores runs the PeerScoresTestSuite.
func TestPeerScores(t *testing.T) {
suite.Run(t, new(PeerScoresTestSuite))
}
// getNetHosts generates a slice of hosts using the [libp2p/go-libp2p] library.
func getNetHosts(testSuite *PeerScoresTestSuite, ctx context.Context, n int) []host.Host {
var out []host.Host
for i := 0; i < n; i++ {
netw := tswarm.GenSwarm(testSuite.T())
h := bhost.NewBlankHost(netw)
testSuite.T().Cleanup(func() { h.Close() })
out = append(out, h)
}
return out
}
func newGossipSubs(testSuite *PeerScoresTestSuite, ctx context.Context, hosts []host.Host) []*pubsub.PubSub {
var psubs []*pubsub.PubSub
logger := testlog.Logger(testSuite.T(), log.LvlCrit)
// For each host, create a default gossipsub router.
for _, h := range hosts {
rt := pubsub.DefaultGossipSubRouter(h)
opts := []pubsub.Option{}
opts = append(opts, p2p.ConfigurePeerScoring(h, testSuite.mockGater, &p2p.Config{
PeerScoring: pubsub.PeerScoreParams{
AppSpecificScore: func(p peer.ID) float64 {
if p == hosts[0].ID() {
return -1000
} else {
return 0
}
},
AppSpecificWeight: 1,
DecayInterval: time.Second,
DecayToZero: 0.01,
},
}, testSuite.mockMetricer, logger)...)
ps, err := pubsub.NewGossipSubWithRouter(ctx, h, rt, opts...)
if err != nil {
panic(err)
}
psubs = append(psubs, ps)
}
return psubs
}
func connectHosts(t *testing.T, hosts []host.Host, d int) {
for i, a := range hosts {
for j := 0; j < d; j++ {
n := rand.Intn(len(hosts))
if n == i {
j--
continue
}
b := hosts[n]
pinfo := a.Peerstore().PeerInfo(a.ID())
err := b.Connect(context.Background(), pinfo)
if err != nil {
t.Fatal(err)
}
}
}
}
// TestNegativeScores tests blocking peers with negative scores.
//
// This follows the testing done in libp2p's gossipsub_test.go [TestGossipsubNegativeScore] function.
func (testSuite *PeerScoresTestSuite) TestNegativeScores() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testSuite.mockMetricer.On("RecordPeerScoring", mock.Anything, float64(0)).Return(nil)
testSuite.mockMetricer.On("RecordPeerScoring", mock.Anything, float64(-1000)).Return(nil)
testSuite.mockGater.On("ListBlockedPeers").Return([]peer.ID{})
// Construct 20 hosts using the [getNetHosts] function.
hosts := getNetHosts(testSuite, ctx, 20)
testSuite.Equal(20, len(hosts))
// Construct 20 gossipsub routers using the [newGossipSubs] function.
pubsubs := newGossipSubs(testSuite, ctx, hosts)
testSuite.Equal(20, len(pubsubs))
// Connect the hosts in a dense network
connectHosts(testSuite.T(), hosts, 10)
// Create subscriptions
var subs []*pubsub.Subscription
var topics []*pubsub.Topic
for _, ps := range pubsubs {
topic, err := ps.Join("test")
testSuite.NoError(err)
sub, err := topic.Subscribe()
testSuite.NoError(err)
subs = append(subs, sub)
topics = append(topics, topic)
}
// Wait and then publish messages
time.Sleep(3 * time.Second)
for i := 0; i < 20; i++ {
msg := []byte(fmt.Sprintf("message %d", i))
topic := topics[i]
err := topic.Publish(ctx, msg)
testSuite.NoError(err)
time.Sleep(20 * time.Millisecond)
}
// Allow gossip to propagate
time.Sleep(2 * time.Second)
// Collects all messages from a subscription
collectAll := func(sub *pubsub.Subscription) []*pubsub.Message {
var res []*pubsub.Message
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
for {
msg, err := sub.Next(ctx)
if err != nil {
break
}
res = append(res, msg)
}
return res
}
// Collect messages for the first host subscription
// This host should only receive 1 message from itself
count := len(collectAll(subs[0]))
testSuite.Equal(1, count)
// Validate that all messages were received from the first peer
for _, sub := range subs[1:] {
all := collectAll(sub)
for _, m := range all {
testSuite.NotEqual(hosts[0].ID(), m.ReceivedFrom)
}
}
}
...@@ -64,6 +64,18 @@ func (p *Prepared) ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Opti ...@@ -64,6 +64,18 @@ func (p *Prepared) ConfigureGossip(params *pubsub.GossipSubParams) []pubsub.Opti
return nil return nil
} }
func (p *Prepared) PeerScoringParams() *pubsub.PeerScoreParams {
return nil
}
func (p *Prepared) BanPeers() bool {
return false
}
func (p *Prepared) TopicScoringParams() *pubsub.TopicScoreParams {
return nil
}
func (p *Prepared) Disabled() bool { func (p *Prepared) Disabled() bool {
return false return false
} }
...@@ -30,9 +30,9 @@ import ( ...@@ -30,9 +30,9 @@ import (
// - banning peers based on score // - banning peers based on score
var ( var (
DisabledDiscovery = errors.New("discovery disabled") ErrDisabledDiscovery = errors.New("discovery disabled")
NoConnectionManager = errors.New("no connection manager") ErrNoConnectionManager = errors.New("no connection manager")
NoConnectionGater = errors.New("no connection gater") ErrNoConnectionGater = errors.New("no connection gater")
) )
type Node interface { type Node interface {
...@@ -236,7 +236,7 @@ func (s *APIBackend) DiscoveryTable(_ context.Context) ([]*enode.Node, error) { ...@@ -236,7 +236,7 @@ func (s *APIBackend) DiscoveryTable(_ context.Context) ([]*enode.Node, error) {
if dv5 := s.node.Dv5Udp(); dv5 != nil { if dv5 := s.node.Dv5Udp(); dv5 != nil {
return dv5.AllNodes(), nil return dv5.AllNodes(), nil
} else { } else {
return nil, DisabledDiscovery return nil, ErrDisabledDiscovery
} }
} }
...@@ -244,7 +244,7 @@ func (s *APIBackend) BlockPeer(_ context.Context, p peer.ID) error { ...@@ -244,7 +244,7 @@ func (s *APIBackend) BlockPeer(_ context.Context, p peer.ID) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_blockPeer") recordDur := s.m.RecordRPCServerRequest("opp2p_blockPeer")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return NoConnectionGater return ErrNoConnectionGater
} else { } else {
return gater.BlockPeer(p) return gater.BlockPeer(p)
} }
...@@ -254,7 +254,7 @@ func (s *APIBackend) UnblockPeer(_ context.Context, p peer.ID) error { ...@@ -254,7 +254,7 @@ func (s *APIBackend) UnblockPeer(_ context.Context, p peer.ID) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_unblockPeer") recordDur := s.m.RecordRPCServerRequest("opp2p_unblockPeer")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return NoConnectionGater return ErrNoConnectionGater
} else { } else {
return gater.UnblockPeer(p) return gater.UnblockPeer(p)
} }
...@@ -264,7 +264,7 @@ func (s *APIBackend) ListBlockedPeers(_ context.Context) ([]peer.ID, error) { ...@@ -264,7 +264,7 @@ func (s *APIBackend) ListBlockedPeers(_ context.Context) ([]peer.ID, error) {
recordDur := s.m.RecordRPCServerRequest("opp2p_listBlockedPeers") recordDur := s.m.RecordRPCServerRequest("opp2p_listBlockedPeers")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return nil, NoConnectionGater return nil, ErrNoConnectionGater
} else { } else {
return gater.ListBlockedPeers(), nil return gater.ListBlockedPeers(), nil
} }
...@@ -276,7 +276,7 @@ func (s *APIBackend) BlockAddr(_ context.Context, ip net.IP) error { ...@@ -276,7 +276,7 @@ func (s *APIBackend) BlockAddr(_ context.Context, ip net.IP) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_blockAddr") recordDur := s.m.RecordRPCServerRequest("opp2p_blockAddr")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return NoConnectionGater return ErrNoConnectionGater
} else { } else {
return gater.BlockAddr(ip) return gater.BlockAddr(ip)
} }
...@@ -286,7 +286,7 @@ func (s *APIBackend) UnblockAddr(_ context.Context, ip net.IP) error { ...@@ -286,7 +286,7 @@ func (s *APIBackend) UnblockAddr(_ context.Context, ip net.IP) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_unblockAddr") recordDur := s.m.RecordRPCServerRequest("opp2p_unblockAddr")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return NoConnectionGater return ErrNoConnectionGater
} else { } else {
return gater.UnblockAddr(ip) return gater.UnblockAddr(ip)
} }
...@@ -296,7 +296,7 @@ func (s *APIBackend) ListBlockedAddrs(_ context.Context) ([]net.IP, error) { ...@@ -296,7 +296,7 @@ func (s *APIBackend) ListBlockedAddrs(_ context.Context) ([]net.IP, error) {
recordDur := s.m.RecordRPCServerRequest("opp2p_listBlockedAddrs") recordDur := s.m.RecordRPCServerRequest("opp2p_listBlockedAddrs")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return nil, NoConnectionGater return nil, ErrNoConnectionGater
} else { } else {
return gater.ListBlockedAddrs(), nil return gater.ListBlockedAddrs(), nil
} }
...@@ -308,7 +308,7 @@ func (s *APIBackend) BlockSubnet(_ context.Context, ipnet *net.IPNet) error { ...@@ -308,7 +308,7 @@ func (s *APIBackend) BlockSubnet(_ context.Context, ipnet *net.IPNet) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_blockSubnet") recordDur := s.m.RecordRPCServerRequest("opp2p_blockSubnet")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return NoConnectionGater return ErrNoConnectionGater
} else { } else {
return gater.BlockSubnet(ipnet) return gater.BlockSubnet(ipnet)
} }
...@@ -318,7 +318,7 @@ func (s *APIBackend) UnblockSubnet(_ context.Context, ipnet *net.IPNet) error { ...@@ -318,7 +318,7 @@ func (s *APIBackend) UnblockSubnet(_ context.Context, ipnet *net.IPNet) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_unblockSubnet") recordDur := s.m.RecordRPCServerRequest("opp2p_unblockSubnet")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return NoConnectionGater return ErrNoConnectionGater
} else { } else {
return gater.UnblockSubnet(ipnet) return gater.UnblockSubnet(ipnet)
} }
...@@ -328,7 +328,7 @@ func (s *APIBackend) ListBlockedSubnets(_ context.Context) ([]*net.IPNet, error) ...@@ -328,7 +328,7 @@ func (s *APIBackend) ListBlockedSubnets(_ context.Context) ([]*net.IPNet, error)
recordDur := s.m.RecordRPCServerRequest("opp2p_listBlockedSubnets") recordDur := s.m.RecordRPCServerRequest("opp2p_listBlockedSubnets")
defer recordDur() defer recordDur()
if gater := s.node.ConnectionGater(); gater == nil { if gater := s.node.ConnectionGater(); gater == nil {
return nil, NoConnectionGater return nil, ErrNoConnectionGater
} else { } else {
return gater.ListBlockedSubnets(), nil return gater.ListBlockedSubnets(), nil
} }
...@@ -338,7 +338,7 @@ func (s *APIBackend) ProtectPeer(_ context.Context, p peer.ID) error { ...@@ -338,7 +338,7 @@ func (s *APIBackend) ProtectPeer(_ context.Context, p peer.ID) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_protectPeer") recordDur := s.m.RecordRPCServerRequest("opp2p_protectPeer")
defer recordDur() defer recordDur()
if manager := s.node.ConnectionManager(); manager == nil { if manager := s.node.ConnectionManager(); manager == nil {
return NoConnectionManager return ErrNoConnectionManager
} else { } else {
manager.Protect(p, "api-protected") manager.Protect(p, "api-protected")
return nil return nil
...@@ -349,7 +349,7 @@ func (s *APIBackend) UnprotectPeer(_ context.Context, p peer.ID) error { ...@@ -349,7 +349,7 @@ func (s *APIBackend) UnprotectPeer(_ context.Context, p peer.ID) error {
recordDur := s.m.RecordRPCServerRequest("opp2p_unprotectPeer") recordDur := s.m.RecordRPCServerRequest("opp2p_unprotectPeer")
defer recordDur() defer recordDur()
if manager := s.node.ConnectionManager(); manager == nil { if manager := s.node.ConnectionManager(); manager == nil {
return NoConnectionManager return ErrNoConnectionManager
} else { } else {
manager.Unprotect(p, "api-protected") manager.Unprotect(p, "api-protected")
return nil return nil
......
package p2p
import (
"fmt"
"time"
pubsub "github.com/libp2p/go-libp2p-pubsub"
)
// MeshWeight is the weight of the mesh delivery topic.
const MeshWeight = -0.7
// MaxInMeshScore is the maximum score for being in the mesh.
const MaxInMeshScore = 10
// DecayEpoch is the number of epochs to decay the score over.
const DecayEpoch = time.Duration(5)
// LightTopicScoreParams is a default instantiation of [pubsub.TopicScoreParams].
// See [TopicScoreParams] for detailed documentation.
//
// [TopicScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#TopicScoreParams
var LightTopicScoreParams = func(blockTime uint64) pubsub.TopicScoreParams {
slot := time.Duration(blockTime) * time.Second
if slot == 0 {
slot = 2 * time.Second
}
epoch := 6 * slot
invalidDecayPeriod := 50 * epoch
return pubsub.TopicScoreParams{
TopicWeight: 0.8,
TimeInMeshWeight: MaxInMeshScore / inMeshCap(slot),
TimeInMeshQuantum: slot,
TimeInMeshCap: inMeshCap(slot),
FirstMessageDeliveriesWeight: 1,
FirstMessageDeliveriesDecay: ScoreDecay(20*epoch, slot),
FirstMessageDeliveriesCap: 23,
MeshMessageDeliveriesWeight: MeshWeight,
MeshMessageDeliveriesDecay: ScoreDecay(DecayEpoch*epoch, slot),
MeshMessageDeliveriesCap: float64(uint64(epoch/slot) * uint64(DecayEpoch)),
MeshMessageDeliveriesThreshold: float64(uint64(epoch/slot) * uint64(DecayEpoch) / 10),
MeshMessageDeliveriesWindow: 2 * time.Second,
MeshMessageDeliveriesActivation: 4 * epoch,
MeshFailurePenaltyWeight: MeshWeight,
MeshFailurePenaltyDecay: ScoreDecay(DecayEpoch*epoch, slot),
InvalidMessageDeliveriesWeight: -140.4475,
InvalidMessageDeliveriesDecay: ScoreDecay(invalidDecayPeriod, slot),
}
}
// the cap for `inMesh` time scoring.
func inMeshCap(slot time.Duration) float64 {
return float64((3600 * time.Second) / slot)
}
// DisabledTopicScoreParams is an instantiation of [pubsub.TopicScoreParams] where all scoring is disabled.
// See [TopicScoreParams] for detailed documentation.
//
// [TopicScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#TopicScoreParams
var DisabledTopicScoreParams = func(blockTime uint64) pubsub.TopicScoreParams {
slot := time.Duration(blockTime) * time.Second
if slot == 0 {
slot = 2 * time.Second
}
epoch := 6 * slot
invalidDecayPeriod := 50 * epoch
return pubsub.TopicScoreParams{
TopicWeight: 0, // disabled
TimeInMeshWeight: 0, // disabled
TimeInMeshQuantum: slot,
TimeInMeshCap: inMeshCap(slot),
FirstMessageDeliveriesWeight: 0, // disabled
FirstMessageDeliveriesDecay: ScoreDecay(20*epoch, slot),
FirstMessageDeliveriesCap: 23,
MeshMessageDeliveriesWeight: 0, // disabled
MeshMessageDeliveriesDecay: ScoreDecay(DecayEpoch*epoch, slot),
MeshMessageDeliveriesCap: float64(uint64(epoch/slot) * uint64(DecayEpoch)),
MeshMessageDeliveriesThreshold: float64(uint64(epoch/slot) * uint64(DecayEpoch) / 10),
MeshMessageDeliveriesWindow: 2 * time.Second,
MeshMessageDeliveriesActivation: 4 * epoch,
MeshFailurePenaltyWeight: 0, // disabled
MeshFailurePenaltyDecay: ScoreDecay(DecayEpoch*epoch, slot),
InvalidMessageDeliveriesWeight: 0, // disabled
InvalidMessageDeliveriesDecay: ScoreDecay(invalidDecayPeriod, slot),
}
}
// TopicScoreParamsByName is a map of name to [pubsub.TopicScoreParams].
var TopicScoreParamsByName = map[string](func(blockTime uint64) pubsub.TopicScoreParams){
"light": LightTopicScoreParams,
"none": DisabledTopicScoreParams,
}
// AvailableTopicScoreParams returns a list of available topic score params.
// These can be used as an input to [GetTopicScoreParams] which returns the
// corresponding [pubsub.TopicScoreParams].
func AvailableTopicScoreParams() []string {
var params []string
for name := range TopicScoreParamsByName {
params = append(params, name)
}
return params
}
// GetTopicScoreParams returns the [pubsub.TopicScoreParams] for the given name.
func GetTopicScoreParams(name string, blockTime uint64) (pubsub.TopicScoreParams, error) {
params, ok := TopicScoreParamsByName[name]
if !ok {
return pubsub.TopicScoreParams{}, fmt.Errorf("invalid topic params %s", name)
}
return params(blockTime), nil
}
...@@ -104,7 +104,7 @@ type EngineQueue struct { ...@@ -104,7 +104,7 @@ type EngineQueue struct {
finalizedL1 eth.L1BlockRef finalizedL1 eth.L1BlockRef
safeAttributes []*eth.PayloadAttributes safeAttributes *eth.PayloadAttributes
unsafePayloads PayloadsQueue // queue of unsafe payloads, ordered by ascending block number, may have gaps unsafePayloads PayloadsQueue // queue of unsafe payloads, ordered by ascending block number, may have gaps
// Tracks which L2 blocks where last derived from which L1 block. At most finalityLookback large. // Tracks which L2 blocks where last derived from which L1 block. At most finalityLookback large.
...@@ -167,11 +167,6 @@ func (eq *EngineQueue) AddUnsafePayload(payload *eth.ExecutionPayload) { ...@@ -167,11 +167,6 @@ func (eq *EngineQueue) AddUnsafePayload(payload *eth.ExecutionPayload) {
eq.log.Trace("Next unsafe payload to process", "next", p.ID(), "timestamp", uint64(p.Timestamp)) eq.log.Trace("Next unsafe payload to process", "next", p.ID(), "timestamp", uint64(p.Timestamp))
} }
func (eq *EngineQueue) AddSafeAttributes(attributes *eth.PayloadAttributes) {
eq.log.Trace("Adding next safe attributes", "timestamp", attributes.Timestamp)
eq.safeAttributes = append(eq.safeAttributes, attributes)
}
func (eq *EngineQueue) Finalize(l1Origin eth.L1BlockRef) { func (eq *EngineQueue) Finalize(l1Origin eth.L1BlockRef) {
if l1Origin.Number < eq.finalizedL1.Number { if l1Origin.Number < eq.finalizedL1.Number {
eq.log.Error("ignoring old L1 finalized block signal! Is the L1 provider corrupted?", "prev_finalized_l1", eq.finalizedL1, "signaled_finalized_l1", l1Origin) eq.log.Error("ignoring old L1 finalized block signal! Is the L1 provider corrupted?", "prev_finalized_l1", eq.finalizedL1, "signaled_finalized_l1", l1Origin)
...@@ -212,27 +207,27 @@ func (eq *EngineQueue) Step(ctx context.Context) error { ...@@ -212,27 +207,27 @@ func (eq *EngineQueue) Step(ctx context.Context) error {
if eq.needForkchoiceUpdate { if eq.needForkchoiceUpdate {
return eq.tryUpdateEngine(ctx) return eq.tryUpdateEngine(ctx)
} }
if len(eq.safeAttributes) > 0 { if eq.safeAttributes != nil {
return eq.tryNextSafeAttributes(ctx) return eq.tryNextSafeAttributes(ctx)
} }
outOfData := false outOfData := false
if len(eq.safeAttributes) == 0 { newOrigin := eq.prev.Origin()
newOrigin := eq.prev.Origin() // Check if the L2 unsafe head origin is consistent with the new origin
// Check if the L2 unsafe head origin is consistent with the new origin if err := eq.verifyNewL1Origin(ctx, newOrigin); err != nil {
if err := eq.verifyNewL1Origin(ctx, newOrigin); err != nil { return err
return err }
} eq.origin = newOrigin
eq.origin = newOrigin eq.postProcessSafeL2() // make sure we track the last L2 safe head for every new L1 block
eq.postProcessSafeL2() // make sure we track the last L2 safe head for every new L1 block if next, err := eq.prev.NextAttributes(ctx, eq.safeHead); err == io.EOF {
if next, err := eq.prev.NextAttributes(ctx, eq.safeHead); err == io.EOF { outOfData = true
outOfData = true } else if err != nil {
} else if err != nil { return err
return err } else {
} else { eq.safeAttributes = next
eq.safeAttributes = append(eq.safeAttributes, next) eq.log.Debug("Adding next safe attributes", "safe_head", eq.safeHead, "next", eq.safeAttributes)
return NotEnoughData return NotEnoughData
}
} }
if eq.unsafePayloads.Len() > 0 { if eq.unsafePayloads.Len() > 0 {
return eq.tryNextUnsafePayload(ctx) return eq.tryNextUnsafePayload(ctx)
} }
...@@ -459,7 +454,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error ...@@ -459,7 +454,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error
} }
return NewTemporaryError(fmt.Errorf("failed to get existing unsafe payload to compare against derived attributes from L1: %w", err)) return NewTemporaryError(fmt.Errorf("failed to get existing unsafe payload to compare against derived attributes from L1: %w", err))
} }
if err := AttributesMatchBlock(eq.safeAttributes[0], eq.safeHead.Hash, payload, eq.log); err != nil { if err := AttributesMatchBlock(eq.safeAttributes, eq.safeHead.Hash, payload, eq.log); err != nil {
eq.log.Warn("L2 reorg: existing unsafe block does not match derived attributes from L1", "err", err) eq.log.Warn("L2 reorg: existing unsafe block does not match derived attributes from L1", "err", err)
// geth cannot wind back a chain without reorging to a new, previously non-canonical, block // geth cannot wind back a chain without reorging to a new, previously non-canonical, block
return eq.forceNextSafeAttributes(ctx) return eq.forceNextSafeAttributes(ctx)
...@@ -472,7 +467,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error ...@@ -472,7 +467,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error
eq.needForkchoiceUpdate = true eq.needForkchoiceUpdate = true
eq.metrics.RecordL2Ref("l2_safe", ref) eq.metrics.RecordL2Ref("l2_safe", ref)
// unsafe head stays the same, we did not reorg the chain. // unsafe head stays the same, we did not reorg the chain.
eq.safeAttributes = eq.safeAttributes[1:] eq.safeAttributes = nil
eq.postProcessSafeL2() eq.postProcessSafeL2()
eq.logSyncProgress("reconciled with L1") eq.logSyncProgress("reconciled with L1")
...@@ -481,10 +476,10 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error ...@@ -481,10 +476,10 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error
// forceNextSafeAttributes inserts the provided attributes, reorging away any conflicting unsafe chain. // forceNextSafeAttributes inserts the provided attributes, reorging away any conflicting unsafe chain.
func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error { func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
if len(eq.safeAttributes) == 0 { if eq.safeAttributes == nil {
return nil return nil
} }
attrs := eq.safeAttributes[0] attrs := eq.safeAttributes
errType, err := eq.StartPayload(ctx, eq.safeHead, attrs, true) errType, err := eq.StartPayload(ctx, eq.safeHead, attrs, true)
if err == nil { if err == nil {
_, errType, err = eq.ConfirmPayload(ctx) _, errType, err = eq.ConfirmPayload(ctx)
...@@ -513,7 +508,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error { ...@@ -513,7 +508,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
return NewCriticalError(fmt.Errorf("failed to process block with only deposit transactions: %w", err)) return NewCriticalError(fmt.Errorf("failed to process block with only deposit transactions: %w", err))
} }
// drop the payload without inserting it // drop the payload without inserting it
eq.safeAttributes = eq.safeAttributes[1:] eq.safeAttributes = nil
// suppress the error b/c we want to retry with the next batch from the batch queue // suppress the error b/c we want to retry with the next batch from the batch queue
// If there is no valid batch the node will eventually force a deposit only block. If // If there is no valid batch the node will eventually force a deposit only block. If
// the deposit only block fails, this will return the critical error above. // the deposit only block fails, this will return the critical error above.
...@@ -523,7 +518,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error { ...@@ -523,7 +518,7 @@ func (eq *EngineQueue) forceNextSafeAttributes(ctx context.Context) error {
return NewCriticalError(fmt.Errorf("unknown InsertHeadBlock error type %d: %w", errType, err)) return NewCriticalError(fmt.Errorf("unknown InsertHeadBlock error type %d: %w", errType, err))
} }
} }
eq.safeAttributes = eq.safeAttributes[1:] eq.safeAttributes = nil
eq.logSyncProgress("processed safe block derived from L1") eq.logSyncProgress("processed safe block derived from L1")
return nil return nil
......
...@@ -50,7 +50,6 @@ type EngineQueueStage interface { ...@@ -50,7 +50,6 @@ type EngineQueueStage interface {
SetUnsafeHead(head eth.L2BlockRef) SetUnsafeHead(head eth.L2BlockRef)
Finalize(l1Origin eth.L1BlockRef) Finalize(l1Origin eth.L1BlockRef)
AddSafeAttributes(attributes *eth.PayloadAttributes)
AddUnsafePayload(payload *eth.ExecutionPayload) AddUnsafePayload(payload *eth.ExecutionPayload)
Step(context.Context) error Step(context.Context) error
} }
......
...@@ -46,7 +46,7 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { ...@@ -46,7 +46,7 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
return nil, fmt.Errorf("failed to load p2p signer: %w", err) return nil, fmt.Errorf("failed to load p2p signer: %w", err)
} }
p2pConfig, err := p2pcli.NewConfig(ctx) p2pConfig, err := p2pcli.NewConfig(ctx, rollupConfig.BlockTime)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load p2p config: %w", err) return nil, fmt.Errorf("failed to load p2p config: %w", err)
} }
......
...@@ -115,7 +115,6 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error { ...@@ -115,7 +115,6 @@ func (ibc *IterativeBatchCall[K, V]) Fetch(ctx context.Context) error {
} }
return ctx.Err() return ctx.Err()
default: default:
break
} }
break break
} }
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
# atst # atst
atst is a typescript sdk and cli around the attestation station atst is a typescript / javascript sdk and cli around AttestationStation
### Visit [Docs](https://community.optimism.io/docs/governance/attestation-station/) for general documentation on the attestation station! **Visit [Docs](https://community.optimism.io/docs/governance/attestation-station/) for general documentation on AttestationStation.**
## Getting started ## Getting started
...@@ -28,42 +28,50 @@ Install ...@@ -28,42 +28,50 @@ Install
npm install @eth-optimism/atst wagmi @wagmi/core ethers@5.7.0 npm install @eth-optimism/atst wagmi @wagmi/core ethers@5.7.0
``` ```
## atst typescript sdk ## atst typescript/javascript sdk
The typescript sdk provides a clean [wagmi](https://wagmi.sh/) based interface for reading and writing to the attestation station The typescript sdk provides a clean [wagmi](https://wagmi.sh/) based interface for reading and writing to AttestationStation.
### See [sdk docs](https://github.com/ethereum-optimism/optimism/blob/develop/packages/atst/docs/sdk.md) for usage instructions **See [sdk docs](https://github.com/ethereum-optimism/optimism/blob/develop/packages/atst/docs/sdk.md) for usage instructions.**
## atst cli ## atst cli
The cli provides a convenient cli for interacting with the attestation station contract The cli provides a convenient cli for interacting with the AttestationStation contract
![preview](./assets/preview.gif) ![preview](./assets/preview.gif)
## React API **See [cli docs](https://github.com/ethereum-optimism/optimism/blob/develop/packages/atst/docs/cli.md) for usage instructions.**
For react hooks we recomend using the [wagmi cli](https://wagmi.sh/cli/getting-started) with the [etherscan plugin](https://wagmi.sh/cli/plugins/etherscan) and [react plugin](https://wagmi.sh/cli/plugins/react) to automatically generate react hooks around the attestation station. ## React API
Use `createKey` and `createValue` to convert your raw keys and values into bytes that can be used in the attestation station contract calls For react hooks we recomend using the [wagmi cli](https://wagmi.sh/cli/getting-started) with the [etherscan plugin](https://wagmi.sh/cli/plugins/etherscan) and [react plugin](https://wagmi.sh/cli/plugins/react) to automatically generate react hooks around AttestationStation.
Use `parseString`, `parseBool`, `parseAddress` and `parseNumber` to convert values returned by attestation station to their correct data type. Use `createKey` and `createValue` to convert your raw keys and values into bytes that can be used in AttestationStation contract calls
For convenience we also export the hooks here. Use `parseString`, `parseBool`, `parseAddress` and `parseNumber` to convert values returned by AttestationStation to their correct data type.
`useAttestationStationAttestation` - Reads attestations with useContractRead For convenience we also [export the hooks here](https://github.com/ethereum-optimism/optimism/blob/develop/packages/atst/src/index.ts):
- `useAttestationStationAttestation` - Reads attestations with useContractRead
- `useAttestationStationVersion` - Reads attestation version
- `useAttestationStationAttest` - Wraps useContractWrite with AttestationStation abi calling attest
- `usePrepareAttestationStationAttest` - Wraps usePrepare with AttestationStation abi calling attest
- `useAttestationStationAttestationCreatedEvent` - Wraps useContractEvents for Created events
`useAttestationStationVersion` - Reads attestation version Also some more hooks exported by the cli but these are likely the only ones you need.
`useAttestationStationAttest` - Wraps useContractWrite with attestation station abi calling attest ## Contributing
`usePrepareAttestationStationAttest` - Wraps usePrepare with attestation station abi calling attest Please see our [contributing.md](https://github.com/ethereum-optimism/optimism/blob/develop/CONTRIBUTING.md). No contribution is too small.
`useAttestationStationAttestationCreatedEvent` - Wraps useContractEvents for Created events Having your contribution denied feels bad.
Please consider [opening an issue](https://github.com/ethereum-optimism/optimism/issues) before adding any new features or apis.
Also some more hooks exported by the cli but these are likely the only ones you need.
## Contributing ## Getting help
Please see our [contributing.md](docs/contributing.md). No contribution is too small. If you have any problems, these resources could help you:
Having your contribution denied feels bad. Please consider opening an issue before adding any new features or apis - [sdk documentation](https://github.com/ethereum-optimism/optimism/blob/develop/packages/atst/docs/sdk.md)
- [cli documentation](https://github.com/ethereum-optimism/optimism/blob/develop/packages/atst/docs/cli.md)
- [Optimism Discord](https://discord-gateway.optimism.io/)
- [Telegram group](https://t.me/+zwpJ8Ohqgl8yNjNh)
...@@ -63,9 +63,9 @@ npx atst read --key "optimist.base-uri" --about 0x2335022c740d17c2837f9C884Bfe4f ...@@ -63,9 +63,9 @@ npx atst read --key "optimist.base-uri" --about 0x2335022c740d17c2837f9C884Bfe4f
Example: Example:
```bash ```bash
atst write --key "optimist.base-uri" \ npx atst write --key "optimist.base-uri" \
--about 0x2335022c740d17c2837f9C884Bfe4fFdbf0A95D5 \ --about 0x2335022c740d17c2837f9C884Bfe4fFdbf0A95D5 \
--value "my attestation" \ --value "my attestation" \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--rpc-url http://localhost:8545 --rpc-url http://goerli.optimism.io
``` ```
# atst sdk docs # AttestationStation sdk docs
Typescript sdk for interacting with the ATST based on [@wagmi/core](https://wagmi.sh/core/getting-started) Typescript sdk for interacting with the ATST based on [@wagmi/core](https://wagmi.sh/core/getting-started)
...@@ -150,7 +150,7 @@ const attestation = await readAttestation( ...@@ -150,7 +150,7 @@ const attestation = await readAttestation(
about, // Address: The about topic of the attestation about, // Address: The about topic of the attestation
key, // string: The key of the attestation key, // string: The key of the attestation
dataType, // Optional, the data type of the attestation, 'string' | 'bytes' | 'number' | 'bool' | 'address' dataType, // Optional, the data type of the attestation, 'string' | 'bytes' | 'number' | 'bool' | 'address'
contractAddress // Optional address: the contract address of the attestation station contractAddress // Optional address: the contract address of AttestationStation
) )
``` ```
...@@ -193,7 +193,7 @@ These definitions allow you to communicate with AttestationStation, but are not ...@@ -193,7 +193,7 @@ These definitions allow you to communicate with AttestationStation, but are not
#### `ATTESTATION_STATION_ADDRESS` #### `ATTESTATION_STATION_ADDRESS`
The deployment address for the attestation station currently deployed with create2 on Optimism and Optimism Goerli `0xEE36eaaD94d1Cc1d0eccaDb55C38bFfB6Be06C77`. The deployment address for AttestationStation currently deployed with create2 on Optimism and Optimism Goerli `0xEE36eaaD94d1Cc1d0eccaDb55C38bFfB6Be06C77`.
```typescript ```typescript
import { ATTESTATION_STATION_ADDRESS } from '@eth-optimism/atst' import { ATTESTATION_STATION_ADDRESS } from '@eth-optimism/atst'
...@@ -201,7 +201,7 @@ import { ATTESTATION_STATION_ADDRESS } from '@eth-optimism/atst' ...@@ -201,7 +201,7 @@ import { ATTESTATION_STATION_ADDRESS } from '@eth-optimism/atst'
#### `abi` #### `abi`
The abi of the attestation station contract The abi of the AttestationStation contract
```typescript ```typescript
import { abi } from '@eth-optimism/atst' import { abi } from '@eth-optimism/atst'
...@@ -265,24 +265,26 @@ const bigNumberAttestation = stringifyAttestationBytes( ...@@ -265,24 +265,26 @@ const bigNumberAttestation = stringifyAttestationBytes(
) )
``` ```
**Note:** `writeAttestation` already does this for you so this is only needed if using a library other than the attestation station. **Note:** `writeAttestation` already does this for you so this is only needed if using a library other than `atst`.
### React API ### React API
For react hooks we recomend using the [wagmi cli](https://wagmi.sh/cli/getting-started) with the [etherscan plugin](https://wagmi.sh/cli/plugins/etherscan) and [react plugin](https://wagmi.sh/cli/plugins/react) to automatically generate react hooks around the attestation station. For react hooks we recomend using the [wagmi cli](https://wagmi.sh/cli/getting-started) with the [etherscan plugin](https://wagmi.sh/cli/plugins/etherscan) and [react plugin](https://wagmi.sh/cli/plugins/react) to automatically generate react hooks around AttestationStation.
Use `createKey` and `createValue` to convert your raw keys and values into bytes that can be used in the attestation station contract calls. Use `createKey` and `createValue` to convert your raw keys and values into bytes that can be used in AttestationStation contract calls.
Use `parseString`, `parseBool`, `parseAddress` and `parseNumber` to convert values returned by attestation station to their correct data type. Use `parseString`, `parseBool`, `parseAddress` and `parseNumber` to convert values returned by AttestationStation to their correct data type.
For convenience we also [export the hooks](../src/react.ts) here: For convenience we also [export the hooks here](../src/react.ts):
- `useAttestationStationAttestation` - Reads attestations with useContractRead - `useAttestationStationAttestation` - Reads attestations with useContractRead
- `useAttestationStationVersion` - Reads attestation version - `useAttestationStationVersion` - Reads attestation version
- `useAttestationStationAttest` - Wraps useContractWrite with attestation station abi calling attest - `useAttestationStationAttest` - Wraps useContractWrite with AttestationStation abi calling attest
- `usePrepareAttestationStationAttest` - Wraps usePrepare with attestation station abi calling attest - `usePrepareAttestationStationAttest` - Wraps usePrepare with AttestationStation abi calling attest
- `useAttestationStationAttestationCreatedEvent` - Wraps useContractEvents for Created events - `useAttestationStationAttestationCreatedEvent` - Wraps useContractEvents for Created events
## Tutorial ## Tutorial
For a tutorial on using the attestation station in general, see out tutorial as well as other Optimism related tutorials in our [optimism-tutorial](https://github.com/ethereum-optimism/optimism-tutorial/tree/main/ecosystem/attestation-station#key-values) repo. - [General atst tutorial](https://github.com/ethereum-optimism/optimism-tutorial/tree/main/ecosystem/attestation-station).
- [React atst starter](https://github.com/ethereum-optimism/optimism-starter).
...@@ -59,5 +59,15 @@ ...@@ -59,5 +59,15 @@
"@wagmi/core": "^0.9.2", "@wagmi/core": "^0.9.2",
"@wagmi/cli": "~0.1.5", "@wagmi/cli": "~0.1.5",
"wagmi": "~0.11.0" "wagmi": "~0.11.0"
} },
"keywords": [
"react",
"hooks",
"eth",
"ethereum",
"dapps",
"web3",
"optimism",
"attestation"
]
} }
...@@ -22,23 +22,23 @@ CrossDomainOwnable3_Test:test_transferOwnershipNoLocal_succeeds() (gas: 48610) ...@@ -22,23 +22,23 @@ CrossDomainOwnable3_Test:test_transferOwnershipNoLocal_succeeds() (gas: 48610)
CrossDomainOwnable3_Test:test_transferOwnership_noLocalZeroAddress_reverts() (gas: 12015) CrossDomainOwnable3_Test:test_transferOwnership_noLocalZeroAddress_reverts() (gas: 12015)
CrossDomainOwnable3_Test:test_transferOwnership_notOwner_reverts() (gas: 13437) CrossDomainOwnable3_Test:test_transferOwnership_notOwner_reverts() (gas: 13437)
CrossDomainOwnable3_Test:test_transferOwnership_zeroAddress_reverts() (gas: 12081) CrossDomainOwnable3_Test:test_transferOwnership_zeroAddress_reverts() (gas: 12081)
CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 72504) CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 72502)
CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10597) CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10597)
CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883) CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883)
DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582) DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582)
DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395) DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395)
FeeVault_Test:test_constructor_succeeds() (gas: 10736) FeeVault_Test:test_constructor_succeeds() (gas: 10736)
FeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 10713) FeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 10713)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 266726) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 266896)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2100049) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2100047)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 452677) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 452675)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 3199814) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 3199812)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 353934) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 353932)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 2634777) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 2634775)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40409) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40409)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 75085) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 75083)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 77809) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 77807)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 169237) GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 169237)
GasPriceOracle_Test:test_baseFee_succeeds() (gas: 8325) GasPriceOracle_Test:test_baseFee_succeeds() (gas: 8325)
GasPriceOracle_Test:test_decimals_succeeds() (gas: 6167) GasPriceOracle_Test:test_decimals_succeeds() (gas: 6167)
...@@ -81,32 +81,32 @@ L1CrossDomainMessenger_Test:test_relayMessage_succeeds() (gas: 76665) ...@@ -81,32 +81,32 @@ L1CrossDomainMessenger_Test:test_relayMessage_succeeds() (gas: 76665)
L1CrossDomainMessenger_Test:test_relayMessage_toSystemContract_reverts() (gas: 101282) L1CrossDomainMessenger_Test:test_relayMessage_toSystemContract_reverts() (gas: 101282)
L1CrossDomainMessenger_Test:test_relayMessage_v2_reverts() (gas: 12365) L1CrossDomainMessenger_Test:test_relayMessage_v2_reverts() (gas: 12365)
L1CrossDomainMessenger_Test:test_replayMessage_withValue_reverts() (gas: 53445) L1CrossDomainMessenger_Test:test_replayMessage_withValue_reverts() (gas: 53445)
L1CrossDomainMessenger_Test:test_sendMessage_succeeds() (gas: 304768) L1CrossDomainMessenger_Test:test_sendMessage_succeeds() (gas: 304766)
L1CrossDomainMessenger_Test:test_sendMessage_twice_succeeds() (gas: 1496208) L1CrossDomainMessenger_Test:test_sendMessage_twice_succeeds() (gas: 1496204)
L1CrossDomainMessenger_Test:test_xDomainMessageSender_reset_succeeds() (gas: 87194) L1CrossDomainMessenger_Test:test_xDomainMessageSender_reset_succeeds() (gas: 87194)
L1CrossDomainMessenger_Test:test_xDomainSender_notSet_reverts() (gas: 24296) L1CrossDomainMessenger_Test:test_xDomainSender_notSet_reverts() (gas: 24296)
L1ERC721Bridge_Test:test_bridgeERC721To_localTokenZeroAddress_reverts() (gas: 52707) L1ERC721Bridge_Test:test_bridgeERC721To_localTokenZeroAddress_reverts() (gas: 52707)
L1ERC721Bridge_Test:test_bridgeERC721To_remoteTokenZeroAddress_reverts() (gas: 27310) L1ERC721Bridge_Test:test_bridgeERC721To_remoteTokenZeroAddress_reverts() (gas: 27310)
L1ERC721Bridge_Test:test_bridgeERC721To_succeeds() (gas: 359863) L1ERC721Bridge_Test:test_bridgeERC721To_succeeds() (gas: 359861)
L1ERC721Bridge_Test:test_bridgeERC721To_wrongOwner_reverts() (gas: 60934) L1ERC721Bridge_Test:test_bridgeERC721To_wrongOwner_reverts() (gas: 60934)
L1ERC721Bridge_Test:test_bridgeERC721_fromContract_reverts() (gas: 25666) L1ERC721Bridge_Test:test_bridgeERC721_fromContract_reverts() (gas: 25666)
L1ERC721Bridge_Test:test_bridgeERC721_localTokenZeroAddress_reverts() (gas: 50564) L1ERC721Bridge_Test:test_bridgeERC721_localTokenZeroAddress_reverts() (gas: 50564)
L1ERC721Bridge_Test:test_bridgeERC721_remoteTokenZeroAddress_reverts() (gas: 25124) L1ERC721Bridge_Test:test_bridgeERC721_remoteTokenZeroAddress_reverts() (gas: 25124)
L1ERC721Bridge_Test:test_bridgeERC721_succeeds() (gas: 357443) L1ERC721Bridge_Test:test_bridgeERC721_succeeds() (gas: 357441)
L1ERC721Bridge_Test:test_bridgeERC721_wrongOwner_reverts() (gas: 60830) L1ERC721Bridge_Test:test_bridgeERC721_wrongOwner_reverts() (gas: 60830)
L1ERC721Bridge_Test:test_constructor_succeeds() (gas: 10200) L1ERC721Bridge_Test:test_constructor_succeeds() (gas: 10200)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_notEscrowed_reverts() (gas: 22119) L1ERC721Bridge_Test:test_finalizeBridgeERC721_notEscrowed_reverts() (gas: 22119)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() (gas: 19797) L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() (gas: 19797)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16049) L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16049)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17615) L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17615)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 328955) L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 328953)
L1StandardBridge_BridgeETHTo_Test:test_bridgeETHTo_succeeds() (gas: 424692) L1StandardBridge_BridgeETHTo_Test:test_bridgeETHTo_succeeds() (gas: 424690)
L1StandardBridge_BridgeETH_Test:test_bridgeETH_succeeds() (gas: 411913) L1StandardBridge_BridgeETH_Test:test_bridgeETH_succeeds() (gas: 411911)
L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 629996) L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 629994)
L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 627697) L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 627695)
L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320) L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320)
L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 424769) L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 424767)
L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 412007) L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 412005)
L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780) L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780)
L1StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 51674) L1StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 51674)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207) L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207)
...@@ -118,7 +118,7 @@ L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_n ...@@ -118,7 +118,7 @@ L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_n
L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 61722) L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 61722)
L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 32173) L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 32173)
L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22050) L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22050)
L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 525310) L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 525308)
L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8411) L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8411)
L2CrossDomainMessenger_Test:test_relayMessage_reentrancyDiffMessage_succeeds() (gas: 680395) L2CrossDomainMessenger_Test:test_relayMessage_reentrancyDiffMessage_succeeds() (gas: 680395)
L2CrossDomainMessenger_Test:test_relayMessage_reentrancySameMessage_reverts() (gas: 626456) L2CrossDomainMessenger_Test:test_relayMessage_reentrancySameMessage_reverts() (gas: 626456)
...@@ -284,19 +284,19 @@ OptimismPortal_FinalizeWithdrawal_Test:test_proveWithdrawalTransaction_replayPro ...@@ -284,19 +284,19 @@ OptimismPortal_FinalizeWithdrawal_Test:test_proveWithdrawalTransaction_replayPro
OptimismPortal_FinalizeWithdrawal_Test:test_proveWithdrawalTransaction_validWithdrawalProof_succeeds() (gas: 180486) OptimismPortal_FinalizeWithdrawal_Test:test_proveWithdrawalTransaction_validWithdrawalProof_succeeds() (gas: 180486)
OptimismPortal_Test:test_constructor_succeeds() (gas: 19440) OptimismPortal_Test:test_constructor_succeeds() (gas: 19440)
OptimismPortal_Test:test_depositTransaction_contractCreation_reverts() (gas: 14330) OptimismPortal_Test:test_depositTransaction_contractCreation_reverts() (gas: 14330)
OptimismPortal_Test:test_depositTransaction_createWithZeroValueForContract_succeeds() (gas: 76758) OptimismPortal_Test:test_depositTransaction_createWithZeroValueForContract_succeeds() (gas: 76756)
OptimismPortal_Test:test_depositTransaction_createWithZeroValueForEOA_succeeds() (gas: 77124) OptimismPortal_Test:test_depositTransaction_createWithZeroValueForEOA_succeeds() (gas: 77122)
OptimismPortal_Test:test_depositTransaction_noValueContract_succeeds() (gas: 76776) OptimismPortal_Test:test_depositTransaction_noValueContract_succeeds() (gas: 76774)
OptimismPortal_Test:test_depositTransaction_noValueEOA_succeeds() (gas: 77121) OptimismPortal_Test:test_depositTransaction_noValueEOA_succeeds() (gas: 77119)
OptimismPortal_Test:test_depositTransaction_smallGasLimit_reverts() (gas: 14276) OptimismPortal_Test:test_depositTransaction_smallGasLimit_reverts() (gas: 14276)
OptimismPortal_Test:test_depositTransaction_withEthValueAndContractContractCreation_succeeds() (gas: 83782) OptimismPortal_Test:test_depositTransaction_withEthValueAndContractContractCreation_succeeds() (gas: 83780)
OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation_succeeds() (gas: 75935) OptimismPortal_Test:test_depositTransaction_withEthValueAndEOAContractCreation_succeeds() (gas: 75933)
OptimismPortal_Test:test_depositTransaction_withEthValueFromContract_succeeds() (gas: 83462) OptimismPortal_Test:test_depositTransaction_withEthValueFromContract_succeeds() (gas: 83460)
OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA_succeeds() (gas: 84078) OptimismPortal_Test:test_depositTransaction_withEthValueFromEOA_succeeds() (gas: 84076)
OptimismPortal_Test:test_isOutputFinalized_succeeds() (gas: 121711) OptimismPortal_Test:test_isOutputFinalized_succeeds() (gas: 121711)
OptimismPortal_Test:test_pause_onlyGuardian_reverts() (gas: 22205) OptimismPortal_Test:test_pause_onlyGuardian_reverts() (gas: 22205)
OptimismPortal_Test:test_pause_succeeds() (gas: 42184) OptimismPortal_Test:test_pause_succeeds() (gas: 42184)
OptimismPortal_Test:test_receive_succeeds() (gas: 127554) OptimismPortal_Test:test_receive_succeeds() (gas: 127552)
OptimismPortal_Test:test_simple_isOutputFinalized_succeeds() (gas: 32934) OptimismPortal_Test:test_simple_isOutputFinalized_succeeds() (gas: 32934)
OptimismPortal_Test:test_unpause_onlyGuardian_reverts() (gas: 46151) OptimismPortal_Test:test_unpause_onlyGuardian_reverts() (gas: 46151)
OptimismPortal_Test:test_unpause_succeeds() (gas: 31763) OptimismPortal_Test:test_unpause_succeeds() (gas: 31763)
...@@ -397,14 +397,17 @@ RLPWriter_writeUint_Test:test_writeUint_smallint_succeeds() (gas: 7280) ...@@ -397,14 +397,17 @@ RLPWriter_writeUint_Test:test_writeUint_smallint_succeeds() (gas: 7280)
RLPWriter_writeUint_Test:test_writeUint_zero_succeeds() (gas: 7749) RLPWriter_writeUint_Test:test_writeUint_zero_succeeds() (gas: 7749)
ResolvedDelegateProxy_Test:test_fallback_addressManagerNotSet_reverts() (gas: 605906) ResolvedDelegateProxy_Test:test_fallback_addressManagerNotSet_reverts() (gas: 605906)
ResolvedDelegateProxy_Test:test_fallback_delegateCallBar_reverts() (gas: 24783) ResolvedDelegateProxy_Test:test_fallback_delegateCallBar_reverts() (gas: 24783)
ResourceMetering_Test:test_meter_initialResourceParams_succeeds() (gas: 8983) ResourceMetering_Test:test_meter_initialBaseFee_succeeds() (gas: 7003)
ResourceMetering_Test:test_meter_updateNoGasDelta_succeeds() (gas: 2008142) ResourceMetering_Test:test_meter_initialResourceParams_succeeds() (gas: 9028)
ResourceMetering_Test:test_meter_updateOneEmptyBlock_succeeds() (gas: 18369) ResourceMetering_Test:test_meter_maxValue_succeeds() (gas: 7015)
ResourceMetering_Test:test_meter_updateParamsNoChange_succeeds() (gas: 13903) ResourceMetering_Test:test_meter_minBaseFeeLessThanMaxBaseFee_succeeds() (gas: 6194)
ResourceMetering_Test:test_meter_updateTenEmptyBlocks_succeeds() (gas: 21161) ResourceMetering_Test:test_meter_updateNoGasDelta_succeeds() (gas: 2008204)
ResourceMetering_Test:test_meter_updateTwoEmptyBlocks_succeeds() (gas: 21117) ResourceMetering_Test:test_meter_updateOneEmptyBlock_succeeds() (gas: 18441)
ResourceMetering_Test:test_meter_useMax_succeeds() (gas: 8017416) ResourceMetering_Test:test_meter_updateParamsNoChange_succeeds() (gas: 14005)
ResourceMetering_Test:test_meter_useMoreThanMax_reverts() (gas: 16045) ResourceMetering_Test:test_meter_updateTenEmptyBlocks_succeeds() (gas: 21243)
ResourceMetering_Test:test_meter_updateTwoEmptyBlocks_succeeds() (gas: 21199)
ResourceMetering_Test:test_meter_useMax_succeeds() (gas: 20017464)
ResourceMetering_Test:test_meter_useMoreThanMax_reverts() (gas: 16120)
SafeCall_call_Test:test_callWithMinGas_noLeakageHigh_succeeds() (gas: 2075873614) SafeCall_call_Test:test_callWithMinGas_noLeakageHigh_succeeds() (gas: 2075873614)
SafeCall_call_Test:test_callWithMinGas_noLeakageLow_succeeds() (gas: 753665282) SafeCall_call_Test:test_callWithMinGas_noLeakageLow_succeeds() (gas: 753665282)
Semver_Test:test_behindProxy_succeeds() (gas: 506748) Semver_Test:test_behindProxy_succeeds() (gas: 506748)
......
...@@ -11,3 +11,4 @@ tmp-artifacts ...@@ -11,3 +11,4 @@ tmp-artifacts
deployments/mainnet-forked deployments/mainnet-forked
deploy-config/mainnet-forked.json deploy-config/mainnet-forked.json
test-case-generator/fuzz test-case-generator/fuzz
.resource-metering.csv
...@@ -29,13 +29,14 @@ abstract contract ResourceMetering is Initializable { ...@@ -29,13 +29,14 @@ abstract contract ResourceMetering is Initializable {
/** /**
* @notice Maximum amount of the resource that can be used within this block. * @notice Maximum amount of the resource that can be used within this block.
* This value cannot be larger than the L2 block gas limit.
*/ */
int256 public constant MAX_RESOURCE_LIMIT = 8_000_000; int256 public constant MAX_RESOURCE_LIMIT = 20_000_000;
/** /**
* @notice Along with the resource limit, determines the target resource limit. * @notice Along with the resource limit, determines the target resource limit.
*/ */
int256 public constant ELASTICITY_MULTIPLIER = 4; int256 public constant ELASTICITY_MULTIPLIER = 10;
/** /**
* @notice Target amount of the resource that should be used within this block. * @notice Target amount of the resource that should be used within this block.
...@@ -50,17 +51,21 @@ abstract contract ResourceMetering is Initializable { ...@@ -50,17 +51,21 @@ abstract contract ResourceMetering is Initializable {
/** /**
* @notice Minimum base fee value, cannot go lower than this. * @notice Minimum base fee value, cannot go lower than this.
*/ */
int256 public constant MINIMUM_BASE_FEE = 10_000; int256 public constant MINIMUM_BASE_FEE = 1 gwei;
/** /**
* @notice Maximum base fee value, cannot go higher than this. * @notice Maximum base fee value, cannot go higher than this.
* It is possible for the MAXIMUM_BASE_FEE to raise to a value
* that is so large it will consume the entire gas limit of
* an L1 block.
*/ */
int256 public constant MAXIMUM_BASE_FEE = int256(uint256(type(uint128).max)); int256 public constant MAXIMUM_BASE_FEE = int256(uint256(type(uint128).max));
/** /**
* @notice Initial base fee value. * @notice Initial base fee value. This value must be smaller than the
* MAXIMUM_BASE_FEE.
*/ */
uint128 public constant INITIAL_BASE_FEE = 1_000_000_000; uint128 public constant INITIAL_BASE_FEE = 1 gwei;
/** /**
* @notice EIP-1559 style gas parameters. * @notice EIP-1559 style gas parameters.
...@@ -84,6 +89,17 @@ abstract contract ResourceMetering is Initializable { ...@@ -84,6 +89,17 @@ abstract contract ResourceMetering is Initializable {
// Run the underlying function. // Run the underlying function.
_; _;
// Run the metering function.
_metered(_amount, initialGas);
}
/**
* @notice An internal function that holds all of the logic for metering a resource.
*
* @param _amount Amount of the resource requested.
* @param _initialGas The amount of gas before any modifier execution.
*/
function _metered(uint64 _amount, uint256 _initialGas) internal {
// Update block number and base fee if necessary. // Update block number and base fee if necessary.
uint256 blockDiff = block.number - params.prevBlockNum; uint256 blockDiff = block.number - params.prevBlockNum;
if (blockDiff > 0) { if (blockDiff > 0) {
...@@ -134,7 +150,7 @@ abstract contract ResourceMetering is Initializable { ...@@ -134,7 +150,7 @@ abstract contract ResourceMetering is Initializable {
); );
// Determine the amount of ETH to be paid. // Determine the amount of ETH to be paid.
uint256 resourceCost = _amount * params.prevBaseFee; uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee);
// We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount
// into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid
...@@ -146,7 +162,7 @@ abstract contract ResourceMetering is Initializable { ...@@ -146,7 +162,7 @@ abstract contract ResourceMetering is Initializable {
// Give the user a refund based on the amount of gas they used to do all of the work up to // Give the user a refund based on the amount of gas they used to do all of the work up to
// this point. Since we're at the end of the modifier, this should be pretty accurate. Acts // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts
// effectively like a dynamic stipend (with a minimum value). // effectively like a dynamic stipend (with a minimum value).
uint256 usedGas = initialGas - gasleft(); uint256 usedGas = _initialGas - gasleft();
if (gasCost > usedGas) { if (gasCost > usedGas) {
Burn.gas(gasCost - usedGas); Burn.gas(gasCost - usedGas);
} }
......
...@@ -32,7 +32,7 @@ contract SetPrevBaseFee_Test is Portal_Initializer { ...@@ -32,7 +32,7 @@ contract SetPrevBaseFee_Test is Portal_Initializer {
// In order to achieve this we make no assertions, and handle everything else in the setUp() // In order to achieve this we make no assertions, and handle everything else in the setUp()
// function. // function.
contract GasBenchMark_OptimismPortal is Portal_Initializer { contract GasBenchMark_OptimismPortal is Portal_Initializer {
uint128 INITIAL_BASE_FEE; uint128 internal INITIAL_BASE_FEE;
// Reusable default values for a test withdrawal // Reusable default values for a test withdrawal
Types.WithdrawalTransaction _defaultTx; Types.WithdrawalTransaction _defaultTx;
...@@ -124,7 +124,7 @@ contract GasBenchMark_OptimismPortal is Portal_Initializer { ...@@ -124,7 +124,7 @@ contract GasBenchMark_OptimismPortal is Portal_Initializer {
} }
contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer { contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer {
uint128 INITIAL_BASE_FEE; uint128 internal INITIAL_BASE_FEE;
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
...@@ -153,7 +153,7 @@ contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer { ...@@ -153,7 +153,7 @@ contract GasBenchMark_L1CrossDomainMessenger is Messenger_Initializer {
} }
contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer { contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer {
uint128 INITIAL_BASE_FEE; uint128 internal INITIAL_BASE_FEE;
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { CommonTest } from "./CommonTest.t.sol"; import { Test } from "forge-std/Test.sol";
import { ResourceMetering } from "../L1/ResourceMetering.sol"; import { ResourceMetering } from "../L1/ResourceMetering.sol";
import { Proxy } from "../universal/Proxy.sol"; import { Proxy } from "../universal/Proxy.sol";
...@@ -15,18 +15,50 @@ contract MeterUser is ResourceMetering { ...@@ -15,18 +15,50 @@ contract MeterUser is ResourceMetering {
} }
function use(uint64 _amount) public metered(_amount) {} function use(uint64 _amount) public metered(_amount) {}
function set(
uint128 _prevBaseFee,
uint64 _prevBoughtGas,
uint64 _prevBlockNum
) public {
params = ResourceMetering.ResourceParams({
prevBaseFee: _prevBaseFee,
prevBoughtGas: _prevBoughtGas,
prevBlockNum: _prevBlockNum
});
}
} }
contract ResourceMetering_Test is CommonTest { contract ResourceMetering_Test is Test {
MeterUser internal meter; MeterUser internal meter;
uint64 initialBlockNum; uint64 initialBlockNum;
function setUp() public virtual override { function setUp() public {
super.setUp();
meter = new MeterUser(); meter = new MeterUser();
initialBlockNum = uint64(block.number); initialBlockNum = uint64(block.number);
} }
/**
* @notice The INITIAL_BASE_FEE must be less than the MAXIMUM_BASE_FEE
* and greater than the MINIMUM_BASE_FEE.
*/
function test_meter_initialBaseFee_succeeds() external {
uint256 max = uint256(meter.MAXIMUM_BASE_FEE());
uint256 min = uint256(meter.MINIMUM_BASE_FEE());
uint256 initial = uint256(meter.INITIAL_BASE_FEE());
assertTrue(max >= initial);
assertTrue(min <= initial);
}
/**
* @notice The MINIMUM_BASE_FEE must be less than the MAXIMUM_BASE_FEE.
*/
function test_meter_minBaseFeeLessThanMaxBaseFee_succeeds() external {
uint256 max = uint256(meter.MAXIMUM_BASE_FEE());
uint256 min = uint256(meter.MINIMUM_BASE_FEE());
assertTrue(max > min);
}
function test_meter_initialResourceParams_succeeds() external { function test_meter_initialResourceParams_succeeds() external {
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
...@@ -35,6 +67,13 @@ contract ResourceMetering_Test is CommonTest { ...@@ -35,6 +67,13 @@ contract ResourceMetering_Test is CommonTest {
assertEq(prevBlockNum, initialBlockNum); assertEq(prevBlockNum, initialBlockNum);
} }
function test_meter_maxValue_succeeds() external {
uint256 max = uint256(meter.MAX_RESOURCE_LIMIT());
uint256 target = uint256(meter.TARGET_RESOURCE_LIMIT());
uint256 elasticity = uint256(meter.ELASTICITY_MULTIPLIER());
assertEq(max / elasticity, target);
}
function test_meter_updateParamsNoChange_succeeds() external { function test_meter_updateParamsNoChange_succeeds() external {
meter.use(0); // equivalent to just updating the base fee and block number meter.use(0); // equivalent to just updating the base fee and block number
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
...@@ -51,8 +90,7 @@ contract ResourceMetering_Test is CommonTest { ...@@ -51,8 +90,7 @@ contract ResourceMetering_Test is CommonTest {
meter.use(0); meter.use(0);
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
// Base fee decreases by 12.5% assertEq(prevBaseFee, 1 gwei);
assertEq(prevBaseFee, 875000000);
assertEq(prevBoughtGas, 0); assertEq(prevBoughtGas, 0);
assertEq(prevBlockNum, initialBlockNum + 1); assertEq(prevBlockNum, initialBlockNum + 1);
} }
...@@ -62,7 +100,7 @@ contract ResourceMetering_Test is CommonTest { ...@@ -62,7 +100,7 @@ contract ResourceMetering_Test is CommonTest {
meter.use(0); meter.use(0);
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
assertEq(prevBaseFee, 765624999); assertEq(prevBaseFee, 1 gwei);
assertEq(prevBoughtGas, 0); assertEq(prevBoughtGas, 0);
assertEq(prevBlockNum, initialBlockNum + 2); assertEq(prevBlockNum, initialBlockNum + 2);
} }
...@@ -72,7 +110,7 @@ contract ResourceMetering_Test is CommonTest { ...@@ -72,7 +110,7 @@ contract ResourceMetering_Test is CommonTest {
meter.use(0); meter.use(0);
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = meter.params();
assertEq(prevBaseFee, 263075576); assertEq(prevBaseFee, 1 gwei);
assertEq(prevBoughtGas, 0); assertEq(prevBoughtGas, 0);
assertEq(prevBlockNum, initialBlockNum + 10); assertEq(prevBlockNum, initialBlockNum + 10);
} }
...@@ -98,8 +136,7 @@ contract ResourceMetering_Test is CommonTest { ...@@ -98,8 +136,7 @@ contract ResourceMetering_Test is CommonTest {
vm.roll(initialBlockNum + 1); vm.roll(initialBlockNum + 1);
meter.use(0); meter.use(0);
(uint128 postBaseFee, , ) = meter.params(); (uint128 postBaseFee, , ) = meter.params();
// Base fee increases by 1/8 the difference assertEq(postBaseFee, 2125000000);
assertEq(postBaseFee, 1375000000);
} }
function test_meter_useMoreThanMax_reverts() external { function test_meter_useMoreThanMax_reverts() external {
...@@ -123,3 +160,206 @@ contract ResourceMetering_Test is CommonTest { ...@@ -123,3 +160,206 @@ contract ResourceMetering_Test is CommonTest {
meter.use(_amount); meter.use(_amount);
} }
} }
/**
* @title CustomMeterUser
* @notice A simple wrapper around `ResourceMetering` that allows the initial
* params to be set in the constructor.
*/
contract CustomMeterUser is ResourceMetering {
uint256 public startGas;
uint256 public endGas;
constructor(
uint128 _prevBaseFee,
uint64 _prevBoughtGas,
uint64 _prevBlockNum
) {
params = ResourceMetering.ResourceParams({
prevBaseFee: _prevBaseFee,
prevBoughtGas: _prevBoughtGas,
prevBlockNum: _prevBlockNum
});
}
function use(uint64 _amount) public returns (uint256) {
uint256 initialGas = gasleft();
_metered(_amount, initialGas);
return initialGas - gasleft();
}
}
/**
* @title ArtifactResourceMetering_Test
* @notice A table test that sets the state of the ResourceParams and then requests
* various amounts of gas. This test ensures that a wide range of values
* can safely be used with the `ResourceMetering` contract.
* It also writes a CSV file to disk that includes useful information
* about how much gas is used and how expensive it is in USD terms to
* purchase the deposit gas.
*/
contract ArtifactResourceMetering_Test is Test {
uint128 internal minimumBaseFee;
uint128 internal maximumBaseFee;
uint64 internal maxResourceLimit;
uint64 internal targetResourceLimit;
string internal outfile;
// keccak256(abi.encodeWithSignature("Error(string)", "ResourceMetering: cannot buy more gas than available gas limit"))
bytes32 internal cannotBuyMoreGas =
0x84edc668cfd5e050b8999f43ff87a1faaa93e5f935b20bc1dd4d3ff157ccf429;
// keccak256(abi.encodeWithSignature("Panic(uint256)", 0x11))
bytes32 internal overflowErr =
0x1ca389f2c8264faa4377de9ce8e14d6263ef29c68044a9272d405761bab2db27;
// keccak256(hex"")
bytes32 internal emptyReturnData =
0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
/**
* @notice Sets up the tests by getting constants from the ResourceMetering
* contract.
*/
function setUp() public {
vm.roll(1_000_000);
MeterUser base = new MeterUser();
minimumBaseFee = uint128(uint256(base.MINIMUM_BASE_FEE()));
maximumBaseFee = uint128(uint256(base.MAXIMUM_BASE_FEE()));
maxResourceLimit = uint64(uint256(base.MAX_RESOURCE_LIMIT()));
targetResourceLimit = uint64(uint256(base.TARGET_RESOURCE_LIMIT()));
outfile = string.concat(vm.projectRoot(), "/.resource-metering.csv");
try vm.removeFile(outfile) {} catch {}
}
/**
* @notice Generate a CSV file. The call to `meter` should be called with at
* most the L1 block gas limit. Without specifying the amount of
* gas, it can take very long to execute.
*/
function test_meter_generateArtifact_succeeds() external {
vm.writeLine(
outfile,
"prevBaseFee,prevBoughtGas,prevBlockNumDiff,l1BaseFee,requestedGas,gasConsumed,ethPrice,usdCost,success"
);
// prevBaseFee value in ResourceParams
uint128[] memory prevBaseFees = new uint128[](5);
prevBaseFees[0] = minimumBaseFee;
prevBaseFees[1] = maximumBaseFee;
prevBaseFees[2] = uint128(50 gwei);
prevBaseFees[3] = uint128(100 gwei);
prevBaseFees[4] = uint128(200 gwei);
// prevBoughtGas value in ResourceParams
uint64[] memory prevBoughtGases = new uint64[](1);
prevBoughtGases[0] = uint64(0);
// prevBlockNum diff, simulates blocks with no deposits when non zero
uint64[] memory prevBlockNumDiffs = new uint64[](2);
prevBlockNumDiffs[0] = 0;
prevBlockNumDiffs[1] = 1;
// The amount of L2 gas that a user requests
uint64[] memory requestedGases = new uint64[](3);
requestedGases[0] = maxResourceLimit;
requestedGases[1] = targetResourceLimit;
requestedGases[2] = uint64(100_000);
// The L1 base fee
uint256[] memory l1BaseFees = new uint256[](4);
l1BaseFees[0] = 1 gwei;
l1BaseFees[1] = 50 gwei;
l1BaseFees[2] = 75 gwei;
l1BaseFees[3] = 100 gwei;
// USD price of 1 ether
uint256[] memory ethPrices = new uint256[](2);
ethPrices[0] = 1600;
ethPrices[1] = 3200;
// Iterate over all of the test values and run a test
for (uint256 i; i < prevBaseFees.length; i++) {
for (uint256 j; j < prevBoughtGases.length; j++) {
for (uint256 k; k < prevBlockNumDiffs.length; k++) {
for (uint256 l; l < requestedGases.length; l++) {
for (uint256 m; m < l1BaseFees.length; m++) {
for (uint256 n; n < ethPrices.length; n++) {
uint256 snapshotId = vm.snapshot();
uint128 prevBaseFee = prevBaseFees[i];
uint64 prevBoughtGas = prevBoughtGases[j];
uint64 prevBlockNumDiff = prevBlockNumDiffs[k];
uint64 requestedGas = requestedGases[l];
uint256 l1BaseFee = l1BaseFees[m];
uint256 ethPrice = ethPrices[n];
string memory result = "success";
vm.fee(l1BaseFee);
CustomMeterUser meter = new CustomMeterUser({
_prevBaseFee: prevBaseFee,
_prevBoughtGas: prevBoughtGas,
_prevBlockNum: uint64(block.number)
});
vm.roll(block.number + prevBlockNumDiff);
// Call the metering code and catch the various
// types of errors.
uint256 gasConsumed = 0;
try meter.use{ gas: 30_000_000 }(requestedGas) returns (
uint256 _gasConsumed
) {
gasConsumed = _gasConsumed;
} catch (bytes memory err) {
bytes32 hash = keccak256(err);
if (hash == cannotBuyMoreGas) {
result = "ResourceMetering: cannot buy more gas than available gas limit";
} else if (hash == overflowErr) {
result = "arithmetic overflow/underflow";
} else if (hash == emptyReturnData) {
result = "out of gas";
} else {
result = "UNKNOWN ERROR";
}
}
// Compute the USD cost of the gas used
uint256 usdCost = (gasConsumed * l1BaseFee * ethPrice) / 1 ether;
vm.writeLine(
outfile,
string.concat(
vm.toString(prevBaseFee),
",",
vm.toString(prevBoughtGas),
",",
vm.toString(prevBlockNumDiff),
",",
vm.toString(l1BaseFee),
",",
vm.toString(requestedGas),
",",
vm.toString(gasConsumed),
",",
"$",
vm.toString(ethPrice),
",",
"$",
vm.toString(usdCost),
",",
result
)
);
assertTrue(vm.revertTo(snapshotId));
}
}
}
}
}
}
}
}
...@@ -19,6 +19,9 @@ ffi = true ...@@ -19,6 +19,9 @@ ffi = true
fuzz_runs = 16 fuzz_runs = 16
no_match_contract = 'EchidnaFuzz' no_match_contract = 'EchidnaFuzz'
fs_permissions = [
{ 'access'='read-write', 'path'='./.resource-metering.csv' },
]
[profile.ci] [profile.ci]
fuzz_runs = 512 fuzz_runs = 512
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
"test": "yarn build:differential && yarn build:fuzz && forge test", "test": "yarn build:differential && yarn build:fuzz && forge test",
"coverage": "yarn build:differential && yarn build:fuzz && forge coverage", "coverage": "yarn build:differential && yarn build:fuzz && forge coverage",
"coverage:lcov": "yarn build:differential && yarn build:fuzz && forge coverage --report lcov", "coverage:lcov": "yarn build:differential && yarn build:fuzz && forge coverage --report lcov",
"gas-snapshot": "yarn build:differential && yarn build:fuzz && forge snapshot --no-match-test 'testDiff|testFuzz|invariant'", "gas-snapshot": "yarn build:differential && yarn build:fuzz && forge snapshot --no-match-test 'testDiff|testFuzz|invariant|generateArtifact'",
"storage-snapshot": "./scripts/storage-snapshot.sh", "storage-snapshot": "./scripts/storage-snapshot.sh",
"validate-spacers": "hardhat compile && hardhat validate-spacers", "validate-spacers": "hardhat compile && hardhat validate-spacers",
"slither": "./scripts/slither.sh", "slither": "./scripts/slither.sh",
......
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