diff --git a/specs/fjord/derivation.md b/specs/fjord/derivation.md index 4bbc09ff4..d6e702139 100644 --- a/specs/fjord/derivation.md +++ b/specs/fjord/derivation.md @@ -13,6 +13,10 @@ - [Rationale](#rationale-1) - [Security Considerations](#security-considerations-1) - [Brotli Channel Compression](#brotli-channel-compression) +- [Network upgrade automation transactions](#network-upgrade-automation-transactions) + - [GasPriceOracle Deployment](#gaspriceoracle-deployment) + - [GasPriceOracle Proxy Update](#gaspriceoracle-proxy-update) + - [GasPriceOracle Enable Fjord](#gaspriceoracle-enable-fjord) @@ -34,6 +38,9 @@ Changes to derivation are applied when it is considering data from a L1 Block wh is greater than or equal to the activation timestamp. The change of the `max_sequencer_drift` parameter activates with the L1 origin block timestamp. +If Fjord is not activated at genesis, it must be activated at least one block after the Ecotone +activation block. This ensures that the network upgrade transactions don't conflict. + ## Constant Maximum Sequencer Drift With Fjord, the `max_sequencer_drift` parameter becomes a constant of value `1800` _seconds_, @@ -137,3 +144,118 @@ Brotli compression algorithm (as specified in [RFC-7932][rfc7932]) with no custo [rfc7932]: https://datatracker.ietf.org/doc/html/rfc7932 [rfc1950]: https://www.rfc-editor.org/rfc/rfc1950.html + +# Network upgrade automation transactions + +The Fjord hardfork activation block contains the following transactions, in this order: + +- L1 Attributes Transaction +- User deposits from L1 +- Network Upgrade Transactions + - GasPriceOracle deployment + - Update GasPriceOracle Proxy ERC-1967 Implementation Slot + - GasPriceOracle Enable Fjord + +To not modify or interrupt the system behavior around gas computation, this block will not include any sequenced +transactions by setting `noTxPool: true`. + +## GasPriceOracle Deployment + +The `GasPriceOracle` contract is upgraded to support the new Fjord L1 data fee computation. Post fork this contract +will use FastLZ to compute the L1 data fee. + +To perform this upgrade, a deposit transaction is derived with the following attributes: + +- `from`: `0x4210000000000000000000000000000000000002` +- `to`: `null`, +- `mint`: `0` +- `value`: `0` +- `gasLimit`: `1,450,000` +- `data`: `0x60806040523...` ([full bytecode](../static/bytecode/fjord-gas-price-oracle-deployment.txt)) +- `sourceHash`: `0x86122c533fdcb89b16d8713174625e44578a89751d96c098ec19ab40a51a8ea3` + computed with the "Upgrade-deposited" type, with `intent = "Fjord: Gas Price Oracle Deployment" + +This results in the Fjord GasPriceOracle contract being deployed to `0xa919894851548179A0750865e7974DA599C0Fac7`, +to verify: + +```bash +cast compute-address --nonce=0 0x4210000000000000000000000000000000000002 +Computed Address: 0xa919894851548179A0750865e7974DA599C0Fac7 +``` + +Verify `sourceHash`: + +```bash +cast keccak $(cast concat-hex 0x0000000000000000000000000000000000000000000000000000000000000002 $(cast keccak "Fjord: Gas Price Oracle Deployment")) +# 0x86122c533fdcb89b16d8713174625e44578a89751d96c098ec19ab40a51a8ea3 +``` + +Verify `data`: + +```bash +git checkout 52abfb507342191ae1f960b443ae8aec7598755c +pnpm clean && pnpm install && pnpm build +jq -r ".bytecode.object" packages/contracts-bedrock/forge-artifacts/GasPriceOracle.sol/GasPriceOracle.json +``` + +This transaction MUST deploy a contract with the following code hash +`0xa88fa50a2745b15e6794247614b5298483070661adacb8d32d716434ed24c6b2`. + +## GasPriceOracle Proxy Update + +This transaction updates the GasPriceOracle Proxy ERC-1967 implementation slot to point to the new GasPriceOracle +deployment. + +A deposit transaction is derived with the following attributes: + +- `from`: `0x0000000000000000000000000000000000000000` +- `to`: `0x420000000000000000000000000000000000000F` (Gas Price Oracle Proxy) +- `mint`: `0` +- `value`: `0` +- `gasLimit`: `50,000` +- `data`: `0x3659cfe6000000000000000000000000a919894851548179a0750865e7974da599c0fac7` +- `sourceHash`: `0x1e6bb0c28bfab3dc9b36ffb0f721f00d6937f33577606325692db0965a7d58c6` + computed with the "Upgrade-deposited" type, with `intent = "Fjord: Gas Price Oracle Proxy Update"` + +Verify data: + +```bash +cast concat-hex $(cast sig "upgradeTo(address)") $(cast abi-encode "upgradeTo(address)" 0xa919894851548179A0750865e7974DA599C0Fac7) +# 0x3659cfe6000000000000000000000000a919894851548179a0750865e7974da599c0fac7 +``` + +Verify `sourceHash`: + +```bash +cast keccak $(cast concat-hex 0x0000000000000000000000000000000000000000000000000000000000000002 $(cast keccak "Fjord: Gas Price Oracle Proxy Update")) +# 0x1e6bb0c28bfab3dc9b36ffb0f721f00d6937f33577606325692db0965a7d58c6 +``` + +## GasPriceOracle Enable Fjord + +This transaction informs the GasPriceOracle to start using the Fjord gas calculation formula. + +A deposit transaction is derived with the following attributes: + +- `from`: `0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001` (Depositer Account) +- `to`: `0x420000000000000000000000000000000000000F` (Gas Price Oracle Proxy) +- `mint`: `0` +- `value`: `0` +- `gasLimit`: `90,000` +- `data`: `0x8e98b106` +- `sourceHash`: `0xbac7bb0d5961cad209a345408b0280a0d4686b1b20665e1b0f9cdafd73b19b6b`, + computed with the "Upgrade-deposited" type, with `intent = "Fjord: Gas Price Oracle Set Fjord" + +Verify data: + +```bash +cast sig "setFjord()" +0x8e98b106 +``` + +Verify `sourceHash`: + +```bash +cast keccak $(cast concat-hex 0x0000000000000000000000000000000000000000000000000000000000000002 $(cast keccak "Fjord: Gas Price Oracle Set Fjord")) +# 0xbac7bb0d5961cad209a345408b0280a0d4686b1b20665e1b0f9cdafd73b19b6b +``` diff --git a/specs/fjord/exec-engine.md b/specs/fjord/exec-engine.md new file mode 100644 index 000000000..b8671d9b0 --- /dev/null +++ b/specs/fjord/exec-engine.md @@ -0,0 +1,80 @@ +# L2 Execution Engine + + + +**Table of Contents** + +- [Fees](#fees) + - [L1-Cost fees (L1 Fee Vault)](#l1-cost-fees-l1-fee-vault) + - [Fjord L1-Cost fee changes (FastLZ estimator)](#fjord-l1-cost-fee-changes-fastlz-estimator) + - [FastLZ Implementation](#fastlz-implementation) + - [L1-Cost linear regression details](#l1-cost-linear-regression-details) + - [L1 Gas Usage Estimation](#l1-gas-usage-estimation) + + + +## Fees + +### L1-Cost fees (L1 Fee Vault) + +#### Fjord L1-Cost fee changes (FastLZ estimator) + +Fjord updates the L1 cost calculation function to use a FastLZ-based compression estimator. +The L1 cost is computed as: + +```pseudocode +l1FeeScaled = baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee +estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) +l1Cost = estimatedSize * l1FeeScaled / 1e12 +``` + +The final `l1Cost` computation is an unlimited precision unsigned integer computation, with the result in Wei and +having `uint256` range. The values in this computation, are as follows: + +| Input arg | Type | Description | Value | +|----------------------|-----------|-------------------------------------------------------------------|--------------------------| +| `l1BaseFee` | `uint256` | L1 base fee of the latest L1 origin registered in the L2 chain | varies, L1 fee | +| `l1BlobBaseFee` | `uint256` | Blob gas price of the latest L1 origin registered in the L2 chain | varies, L1 fee | +| `fastlzSize` | `uint256` | Size of the FastLZ-compressed RLP-encoded signed tx | varies, per transaction | +| `baseFeeScalar` | `uint32` | L1 base fee scalar, scaled by `1e6` | varies, L2 configuration | +| `blobFeeScalar` | `uint32` | L1 blob fee scalar, scaled by `1e6` | varies, L2 configuration | +| `intercept` | `int32` | Intercept constant, scaled by `1e6` (can be negative) | -42_585_600 | +| `fastlzCoef` | `uint32` | FastLZ coefficient, scaled by `1e6` | 836_500 | +| `minTransactionSize` | `uint32` | A lower bound on transaction size, in bytes | 100 | + +Previously, `baseFeeScalar` and `blobFeeScalar` were used to encode the compression ratio, due to the inaccuracy of +the L1 cost function. However, the new cost function takes into account the compression ratio, so these scalars should +be adjusted to account for any previous compression ratio they encoded. + +##### FastLZ Implementation + +All compression algorithms must be implemented equivalently to the `fastlz_compress` function in `fastlz.c` at the +following [commit](https://github.com/ariya/FastLZ/blob/344eb4025f9ae866ebf7a2ec48850f7113a97a42/fastlz.c#L482-L506). + +##### L1-Cost linear regression details + +The `intercept` and `fastlzCoef` constants are calculated by linear regression using a dataset +of previous L2 transactions. The dataset is generated by iterating over all transactions in a given time range, and +performing the following actions. For each transaction: + +1. Compress the payload using FastLZ. Record the size of the compressed payload as `fastlzSize`. +2. Emulate the change in batch size adding the transaction to a batch, compressed with Brotli 10. Record the change in + batch size as `bestEstimateSize`. + +Once this dataset is generated, a linear regression can be calculated using the `bestEstimateSize` as +the dependent variable and `fastlzSize` as the independent variable. + +We generated a dataset from two weeks of post-Ecotone transactions on Optimism Mainnet, as we found that was +the most representative of performance across multiple chains and time periods. More details on the linear regression +and datasets used can be found in this [repository](https://github.com/roberto-bayardo/compression-analysis/tree/main). + +### L1 Gas Usage Estimation + +The `L1GasUsed` property on the transaction receipt is updated to take into account the improvement in +[compression estimation](./exec-engine.md#fees) accuracy. The value will be calculated by +multiplying the `estimatedSize` of the transaction from the above L1 cost formula by 16. The value of 16 assumes most +of the bytes in the compressed data are non-zero. + +The `L1GasUsed` property will be deprecated due to it not accurately calculating the L1 gas used +by a transaction. Users can continue to use the `L1Fee` field to retrieve the L1 fee for a given transaction. This field +will be removed in a future network upgrade. diff --git a/specs/fjord/overview.md b/specs/fjord/overview.md index 7702197a9..09e8503c8 100644 --- a/specs/fjord/overview.md +++ b/specs/fjord/overview.md @@ -14,6 +14,9 @@ This document is not finalized and should be considered experimental. ## Execution Layer - [RIP-7212: Precompile for secp256r1 Curve Support](../protocol/precompiles.md#P256VERIFY) +- [FastLZ compression for L1 data fee calculation](./exec-engine.md#fees) +- [Deprecate the `getL1GasUsed` method on the `GasPriceOracle` contract](./predeploys.md#l1-gas-usage-estimation) +- [Deprecate the `L1GasUsed` field on the transaction receipt](./exec-engine.md#l1-gas-usage-estimation) ## Consensus Layer diff --git a/specs/fjord/predeploys.md b/specs/fjord/predeploys.md new file mode 100644 index 000000000..7cc7bcf99 --- /dev/null +++ b/specs/fjord/predeploys.md @@ -0,0 +1,77 @@ +# Predeploys + + + +**Table of Contents** + +- [GasPriceOracle](#gaspriceoracle) + - [L1 Gas Usage Estimation](#l1-gas-usage-estimation) + + + +## GasPriceOracle + +Following the Fjord upgrade, three additional values used for L1 fee computation are: + +- costIntercept +- costFastlzCoef +- minTransactionSize + +These values are hard-coded constants in the `GasPriceOracle` contract. The +calculation follows the same formula outlined in the +[Fjord L1-Cost fee changes (FastLZ estimator)](./exec-engine.md#fjord-l1-cost-fee-changes-fastlz-estimator) +section. + +A new method is introduced: `getL1FeeUpperBound(uint256)`. This method returns an upper bound for the L1 fee +for a given transaction size. It is provided for callers who wish to estimate L1 transaction costs in the +write path, and is much more gas efficient than `getL1Fee`. + +The upper limit overhead is assumed to be `original/255+16`, borrowed from LZ4. According to historical data, this +approach can encompass more than 99.99% of transactions. + +This is implemented as follows: + +```solidity +function getL1FeeUpperBound(uint256 unsignedTxSize) external view returns (uint256) { + // Add 68 to account for unsigned tx + uint256 txSize = unsignedTxSize + 68; + // txSize / 255 + 16 is the pratical fastlz upper-bound covers 99.99% txs. + uint256 flzUpperBound = txSize + txSize / 255 + 16; + + int256 estimatedSize = costIntercept + costFastlzCoef * flzUpperBound; + if (estimatedSize < minTransactionSize) { + estimatedSize = minTransactionSize; + } + + uint256 l1FeeScaled = baseFeeScalar() * l1BaseFee() * 16 + blobBaseFeeScalar() * blobBaseFee(); + return uint256(estimatedSize) * feeScaled / (10 ** (DECIMALS * 2)); +} +``` + +### L1 Gas Usage Estimation + +The `getL1GasUsed` method is updated to take into account the improved [compression estimation](./exec-engine.md#fees) +accuracy as part of the Fjord upgrade. + +```solidity +function getL1GasUsed(bytes memory _data) public view returns (uint256) { + if (isFjord) { + // Add 68 to the size to account for the unsigned tx + int256 flzSize = LibZip.flzCompress(_data).length + 68; + + int256 estimatedSize = costIntercept + costFastlzCoef * flzSize; + if (estimatedSize < minTransactionSize) { + estimatedSize = minTransactionSize; + } + + // Assume the compressed data is mostly non-zero, and would pay 16 gas per calldata byte + return estimatedSize * 16; + } + // ... +} +``` + +The `getL1GasUsed` method will be deprecated. This is due to it not accurately estimating the +L1 gas used, for a transaction. In a future network upgrade this function will revert when called. + +Users can continue to use the `getL1FeeUpperBound` or `getL1Fee` method to estimate the L1 fee for a given transaction. diff --git a/specs/protocol/derivation.md b/specs/protocol/derivation.md index 2db0d3d47..3d5ca6119 100644 --- a/specs/protocol/derivation.md +++ b/specs/protocol/derivation.md @@ -1040,7 +1040,7 @@ special transactions may be inserted as part of the derivation process. #### Ecotone -The Ecotone hardfork activation block, contains the following transactions in this order: +The Ecotone hardfork activation block contains the following transactions, in this order: - L1 Attributes Transaction, using the pre-Ecotone `setL1BlockValues` - User deposits from L1 diff --git a/specs/protocol/predeploys.md b/specs/protocol/predeploys.md index 3cfba9099..8a4b2efdd 100644 --- a/specs/protocol/predeploys.md +++ b/specs/protocol/predeploys.md @@ -244,8 +244,8 @@ has been hardcoded to 6. Following the Ecotone upgrade, the values used for L1 fee computation are: -- l1BaseFeeScalar -- l1BlobBaseFeeScalar +- baseFeeScalar +- blobBaseFeeScalar - decimals [ecotone-scalars]: system_config.md#ecotone-scalar-overhead-uint256uint256-change diff --git a/specs/static/bytecode/fjord-gas-price-oracle-deployment.txt b/specs/static/bytecode/fjord-gas-price-oracle-deployment.txt new file mode 100644 index 000000000..210c3b6b1 --- /dev/null +++ b/specs/static/bytecode/fjord-gas-price-oracle-deployment.txt @@ -0,0 +1 @@ +0x608060405234801561001057600080fd5b506117f6806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80636ef25c3a116100b2578063de26c4a111610081578063f45e65d811610066578063f45e65d81461025b578063f820614014610263578063fe173b971461020d57600080fd5b8063de26c4a114610235578063f1c7a58b1461024857600080fd5b80636ef25c3a1461020d5780638e98b10614610213578063960e3a231461021b578063c59859181461022d57600080fd5b806349948e0e11610109578063519b4bd3116100ee578063519b4bd31461019f57806354fd4d50146101a757806368d5dca6146101f057600080fd5b806349948e0e1461016f5780634ef6e2241461018257600080fd5b80630c18c1621461013b57806322b90ab3146101565780632e0f262514610160578063313ce56714610168575b600080fd5b61014361026b565b6040519081526020015b60405180910390f35b61015e61038c565b005b610143600681565b6006610143565b61014361017d3660046112a1565b610515565b60005461018f9060ff1681565b604051901515815260200161014d565b610143610552565b6101e36040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60405161014d9190611370565b6101f86105b3565b60405163ffffffff909116815260200161014d565b48610143565b61015e610638565b60005461018f90610100900460ff1681565b6101f8610832565b6101436102433660046112a1565b610893565b6101436102563660046113e3565b61098d565b610143610a69565b610143610b5c565b6000805460ff1615610304576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038791906113fc565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a4016102fb565b60005460ff16156104e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f616374697665000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60008054610100900460ff16156105355761052f82610bbd565b92915050565b60005460ff16156105495761052f82610bdc565b61052f82610c80565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103879190611415565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146106db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c61670060648201526084016102fb565b60005460ff1661076d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e650000000000000060648201526084016102fb565b600054610100900460ff1615610804576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f746976650000000000000000000000000000000000000000000000000000000060648201526084016102fb565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b60008054610100900460ff16156108da57620f42406108c56108b484610dd4565b516108c090604461146a565b6110f1565b6108d0906010611482565b61052f91906114bf565b60006108e583611150565b60005490915060ff16156108f95792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906113fc565b610986908261146a565b9392505050565b60008054610100900460ff16610a25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f72640000000000000000000060648201526084016102fb565b6000610a3283604461146a565b90506000610a4160ff836114bf565b610a4b908361146a565b610a5690601061146a565b9050610a61816111e0565b949350505050565b6000805460ff1615610afd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f656361746564000000000000000000000000000000000000000000000000000060648201526084016102fb565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b600061052f610bcb83610dd4565b51610bd790604461146a565b6111e0565b600080610be883611150565b90506000610bf4610552565b610bfc610832565b610c079060106114fa565b63ffffffff16610c179190611482565b90506000610c23610b5c565b610c2b6105b3565b63ffffffff16610c3b9190611482565b90506000610c49828461146a565b610c539085611482565b9050610c616006600a611646565b610c6c906010611482565b610c7690826114bf565b9695505050505050565b600080610c8c83611150565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1391906113fc565b610d1b610552565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9e91906113fc565b610da8908561146a565b610db29190611482565b610dbc9190611482565b9050610dca6006600a611646565b610a6190826114bf565b6060610f63565b818153600101919050565b600082840393505b838110156109865782810151828201511860001a1590930292600101610dee565b825b60208210610e5b578251610e26601f83610ddb565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190602101610e11565b8115610986578251610e706001840383610ddb565b520160010192915050565b60006001830392505b6101078210610ebc57610eae8360ff16610ea960fd610ea98760081c60e00189610ddb565b610ddb565b935061010682039150610e84565b60078210610ee957610ee28360ff16610ea960078503610ea98760081c60e00189610ddb565b9050610986565b610a618360ff16610ea98560081c8560051b0187610ddb565b610f5b828203610f3f610f2f84600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b81811015611096576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b90911890915284019081830390848410610feb5750611026565b600184019350611fff8211611020578251600081901a600182901a60081b1760029190911a60101b1781036110205750611026565b50610f8f565b838310611034575050611096565b600183039250858311156110525761104f8787888603610e0f565b96505b611066600985016003850160038501610de6565b9150611073878284610e7b565b96505061108b8461108686848601610f02565b610f02565b915050809350610f83565b50506110a88383848851850103610e0f565b925050506040519150618000820180820391508183526020830160005b838110156110dd5782810151828201526020016110c5565b506000920191825250602001604052919050565b60008061110183620cc394611482565b61112b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611652565b905061113b6064620f42406116c6565b81121561052f576109866064620f42406116c6565b80516000908190815b818110156111d35784818151811061117357611173611782565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036111b3576111ac60048461146a565b92506111c1565b6111be60108461146a565b92505b806111cb816117b1565b915050611159565b50610a618261044061146a565b6000806111ec836110f1565b905060006111f8610b5c565b6112006105b3565b63ffffffff166112109190611482565b611218610552565b611220610832565b61122b9060106114fa565b63ffffffff1661123b9190611482565b611245919061146a565b905061125360066002611482565b61125e90600a611646565b6112688284611482565b610a6191906114bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156112b357600080fd5b813567ffffffffffffffff808211156112cb57600080fd5b818401915084601f8301126112df57600080fd5b8135818111156112f1576112f1611272565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561133757611337611272565b8160405282815287602084870101111561135057600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561139d57858101830151858201604001528201611381565b818111156113af576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000602082840312156113f557600080fd5b5035919050565b60006020828403121561140e57600080fd5b5051919050565b60006020828403121561142757600080fd5b815163ffffffff8116811461098657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561147d5761147d61143b565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156114ba576114ba61143b565b500290565b6000826114f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600063ffffffff8083168185168183048111821515161561151d5761151d61143b565b02949350505050565b600181815b8085111561157f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156115655761156561143b565b8085161561157257918102915b93841c939080029061152b565b509250929050565b6000826115965750600161052f565b816115a35750600061052f565b81600181146115b957600281146115c3576115df565b600191505061052f565b60ff8411156115d4576115d461143b565b50506001821b61052f565b5060208310610133831016604e8410600b8410161715611602575081810a61052f565b61160c8383611526565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561163e5761163e61143b565b029392505050565b60006109868383611587565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561168c5761168c61143b565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156116c0576116c061143b565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000841360008413858304851182821616156117075761170761143b565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156117425761174261143b565b6000871292508782058712848416161561175e5761175e61143b565b878505871281841616156117745761177461143b565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117e2576117e261143b565b506001019056fea164736f6c634300080f000a \ No newline at end of file