From 823dcbe86599a58dd7baccdb6e2b8128034909b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 11 Nov 2020 18:38:25 +0100 Subject: [PATCH 01/74] bench: Add internal benchmarks for jumpdest map build --- test/internal_benchmarks/CMakeLists.txt | 1 + test/internal_benchmarks/analysis_bench.cpp | 461 ++++++++++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 test/internal_benchmarks/analysis_bench.cpp diff --git a/test/internal_benchmarks/CMakeLists.txt b/test/internal_benchmarks/CMakeLists.txt index 4b5228d687..587ef7d2e0 100644 --- a/test/internal_benchmarks/CMakeLists.txt +++ b/test/internal_benchmarks/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable( evmone-bench-internal + analysis_bench.cpp evmmax_bench.cpp find_jumpdest_bench.cpp memory_allocation.cpp diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp new file mode 100644 index 0000000000..2c034237b2 --- /dev/null +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -0,0 +1,461 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "evmone/baseline.hpp" +#include "test/utils/utils.hpp" +#include + + +namespace +{ +const auto test_bytecode = from_hex( + "608060405234801561001057600080fd5b50600436106100365760003560e01c80631e0924231461003b578063d299" + "dac0146102bb575b600080fd5b610282600480360360a081101561005157600080fd5b810190602081018135640100" + "00000081111561006c57600080fd5b82018360208201111561007e57600080fd5b8035906020019184600183028401" + "11640100000000831117156100a057600080fd5b91908080601f016020809104026020016040519081016040528093" + "9291908181526020018383808284376000920191909152509295949360208101935035915050640100000000811115" + "6100f357600080fd5b82018360208201111561010557600080fd5b8035906020019184600183028401116401000000" + "008311171561012757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152" + "602001838380828437600092019190915250929594936020810193503591505064010000000081111561017a576000" + "80fd5b82018360208201111561018c57600080fd5b8035906020019184600183028401116401000000008311171561" + "01ae57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380" + "828437600092019190915250929594936020810193503591505064010000000081111561020157600080fd5b820183" + "60208201111561021357600080fd5b8035906020019184600183028401116401000000008311171561023557600080" + "fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092" + "0191909152509295505050903567ffffffffffffffff1691506103f49050565b604051808261010080838360005b83" + "8110156102a8578181015183820152602001610290565b5050505090500191505060405180910390f35b6102826004" + "80360360608110156102d157600080fd5b8101906020810181356401000000008111156102ec57600080fd5b820183" + "6020820111156102fe57600080fd5b8035906020019184600183028401116401000000008311171561032057600080" + "fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092" + "019190915250929594936020810193503591505064010000000081111561037357600080fd5b820183602082011115" + "61038557600080fd5b803590602001918460018302840111640100000000831117156103a757600080fd5b91908080" + "601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250" + "9295505050903567ffffffffffffffff1691506104489050565b6103fc61156d565b61040461158d565b61040c6115" + "6d565b61042982858961041b8a610485565b6104248a610485565b610538565b61043382896106dc565b61043d8282" + "61079b565b979650505050505050565b61045061156d565b61047d8484602060405190810160405280600081525060" + "20604051908101604052806000815250866103f4565b949350505050565b61048d6115ca565b60005b825181101561" + "04fb5760088184018101519067ffffffffffffffff82166007841660010182026040031b9084908404600281106104" + "c957fe5b6020020151188360088404600281106104de57fe5b67ffffffffffffffff90921660209290920201525060" + "0101610490565b5061050d8160005b60200201516108cd565b67ffffffffffffffff16815261052481600161050356" + "5b67ffffffffffffffff166020820152919050565b67ffffffffffffffff84161580610559575060408467ffffffff" + "ffffffff16115b80610565575060408351115b1561056f57600080fd5b61057761156d565b50604080516101008101" + "8252676a09e667f3bcc908815267bb67ae8584caa73b6020820152673c6ef372fe94f82b9181019190915267a54ff5" + "3a5f1d36f1606082015267510e527fade682d16080820152679b05688c2b3e6c1f60a0820152671f83d9abfb41bd6b" + "60c0820152675be0cd19137e217960e082015260005b600881101561063d5781816008811061060a57fe5b60200201" + "5187602001518260088110151561062157fe5b67ffffffffffffffff90921660209290920201526001016105f5565b" + "50835160208781018051805167ffffffffffffffff94851660081b1889186301010000188416905285518151608090" + "81018051909218851690915286830151825160a0018051909118851690528551825160c00180519091188516905291" + "850151905160e00180519091188316905286821690880152845190600090821611156106d3576106cb87866106dc56" + "5b608060608801525b50505050505050565b60005b815181101561079657826060015167ffffffffffffffff166080" + "141561074057606083015160408401805167ffffffffffffffff9092169091016fffffffffffffffffffffffffffff" + "ffff16905261073883600061094f565b600060608401525b60608301805167ffffffffffffffff6001820181169092" + "52166107616115e5565b508351835160009085908590811061077557fe5b90602001015160f81c60f81b60f81c9050" + "80838301535050506001016106df565b505050565b60608201805160408401805167ffffffffffffffff8084169182" + "016fffffffffffffffffffffffffffffffff1690925260019092011690915260006107de6115e5565b508351825b60" + "808110156107f95782818301536001016107e3565b5061080585600161094f565b60005b6080860151600890048110" + "1561085457602086015161082c90826008811061050357fe5b85826008811061083857fe5b67ffffffffffffffff90" + "92166020929092020152600101610808565b506040856080015110156108c657608085015160208601516008600783" + "16810260400392610889929190046008811061050357fe5b67ffffffffffffffff16901c8460088760800151811515" + "6108a657fe5b04600881106108b157fe5b67ffffffffffffffff90921660209290920201525b5050505050565b6000" + "67010000000000000060ff8316026501000000000061ff00841602630100000062ff000085160261010063ff000000" + "861681029064ff00000000871604630100000065ff00000000008816046501000000000066ff000000000000891604" + "67010000000000000067ff000000000000008a16041818181818181892915050565b610957611604565b61095f6116" + "04565b61096761156d565b506040805161010081018252676a09e667f3bcc908815267bb67ae8584caa73b60208201" + "52673c6ef372fe94f82b9181019190915267a54ff53a5f1d36f1606082015267510e527fade682d16080820152679b" + "05688c2b3e6c1f60a0820152671f83d9abfb41bd6b60c0820152675be0cd19137e217960e082015260005b60088110" + "15610a5f57602086015181600881106109fe57fe5b6020020151848260108110610a0f57fe5b67ffffffffffffffff" + "9092166020929092020152818160088110610a2f57fe5b6020020151846008830160108110610a4357fe5b67ffffff" + "ffffffffff90921660209290920201526001016109e5565b506040850180516101808501805167ffffffffffffffff" + "928316188216905290516101a085018051680100000000000000006fffffffffffffffffffffffffffffffff909316" + "9290920490911890911690528315610acc576101c0830180511967ffffffffffffffff1690525b600080805b601081" + "60ff161015610b56576000925060038116801515610b0c578851600460ff84160460ff16600481101515610b0457fe" + "5b602002015192505b67ffffffffffffffff83826003036040021c169350610b2a846108cd565b8660ff8416601081" + "10610b3957fe5b67ffffffffffffffff909216602092909202015250600101610ad1565b50610b7985600060046008" + "600c89845b60200201518a60015b60200201516113e8565b610b9685600160056009600d8960025b60200201518a60" + "03610b6f565b610bb38560026006600a600e8960045b60200201518a6005610b6f565b610bd08560036007600b600f" + "8960065b60200201518a6007610b6f565b610bed8560006005600a600f8960085b60200201518a6009610b6f565b61" + "0c0a8560016006600b600c89600a5b60200201518a600b610b6f565b610c2785600260076008600d89600c5b602002" + "01518a600d610b6f565b610c4385600360046009600e89815b60200201518a600f610b6f565b610c60856000600460" + "08600c89600e5b60200201518a600a610b6f565b610c7d85600160056009600d8960045b60200201518a6008610b6f" + "565b610c918560026006600a600e896009610c36565b610cae8560036007600b600f89600d5b60200201518a600661" + "0b6f565b610ccb8560006005600a600f8960015b60200201518a600c610b6f565b610ce88560016006600b600c8960" + "005b60200201518a6002610b6f565b610cfc85600260076008600d89600b610bc3565b610d1085600360046009600e" + "896005610b89565b610d2485600060046008600c89600b610c70565b610d4185600160056009600d89600c5b602002" + "01518a6000610b6f565b610d558560026006600a600e896005610cdb565b610d688560036007600b600f8981610c1a" + "565b610d848560006005600a600f89825b60200201518a600e610b6f565b610d988560016006600b600c896003610c" + "a1565b610dab85600260076008600d8983610b66565b610dc785600360046009600e89825b60200201518a6004610b" + "6f565b610ddb85600060046008600c896007610be0565b610def85600160056009600d896003610b66565b610e0385" + "60026006600a600e89600d610cbe565b610e168560036007600b600f8982610d77565b610e2a8560006005600a600f" + "896002610ca1565b610e3e8560016006600b600c896005610c53565b610e5285600260076008600d896004610d3456" + "5b610e6685600360046009600e89600f610c70565b610e7a85600060046008600c896009610d34565b610e8d856001" + "60056009600d8983610bc3565b610ea08560026006600a600e8984610dba565b610eb48560036007600b600f89600a" + "610c36565b610ec88560006005600a600f89600e610b66565b610edb8560016006600b600c8982610cbe565b610eef" + "85600260076008600d896006610c70565b610f0285600360046009600e8984610c1a565b610f168560006004600860" + "0c896002610cbe565b610f2a85600160056009600d896006610c53565b610f3e8560026006600a600e896000610bfd" + "565b610f528560036007600b600f896008610b89565b610f668560006005600a600f896004610c1a565b610f7a8560" + "016006600b600c896007610ba6565b610f8e85600260076008600d89600f610d77565b610fa285600360046009600e" + "896001610be0565b610fb585600060046008600c8981610ba6565b610fc885600160056009600d8984610c36565b61" + "0fdb8560026006600a600e8981610c1a565b610fef8560036007600b600f896004610c53565b611002856000600560" + "0a600f8984610bc3565b6110158560016006600b600c8983610b89565b61102985600260076008600d896009610cdb" + "565b61103d85600360046009600e896008610bfd565b61105185600060046008600c89600d610bfd565b6110658560" + "0160056009600d896007610d77565b6110798560026006600a600e89600c610b66565b61108c8560036007600b600f" + "8984610be0565b61109f8560006005600a600f8983610d34565b6110b38560016006600b600c89600f610dba565b61" + "10c685600260076008600d8982610ca1565b6110da85600360046009600e896002610c53565b6110ee856000600460" + "08600c896006610c36565b61110285600160056009600d89600e610be0565b6111168560026006600a600e89600b61" + "0b89565b61112a8560036007600b600f896000610c70565b61113e8560006005600a600f89600c610cdb565b611152" + "8560016006600b600c89600d610bc3565b61116685600260076008600d896001610dba565b61117a85600360046009" + "600e89600a610ba6565b61118e85600060046008600c89600a610cdb565b6111a285600160056009600d896008610d" + "ba565b6111b68560026006600a600e896007610ca1565b6111ca8560036007600b600f896001610ba6565b6111dd85" + "60006005600a600f8981610bfd565b6111f18560016006600b600c896009610d77565b61120585600260076008600d" + "896003610cbe565b61121985600360046009600e89600d610d34565b61122c85600060046008600c8984610b66565b" + "61124085600160056009600d896002610b89565b6112548560026006600a600e896004610ba6565b61126885600360" + "07600b600f896006610bc3565b61127c8560006005600a600f896008610be0565b6112908560016006600b600c8960" + "0a610bfd565b6112a485600260076008600d89600c610c1a565b6112b785600360046009600e8981610c36565b6112" + "cb85600060046008600c89600e610c53565b6112df85600160056009600d896004610c70565b6112f3856002600660" + "0a600e896009610c36565b6113078560036007600b600f89600d610ca1565b61131b8560006005600a600f89600161" + "0cbe565b61132f8560016006600b600c896000610cdb565b61134385600260076008600d89600b610bc3565b611357" + "85600360046009600e896005610b89565b60005b60088160ff1610156113de578560ff600883011660108110611378" + "57fe5b60200201518660ff83166010811061138c57fe5b602002015189602001518360ff166008811015156113a657" + "fe5b6020020151181888602001518260ff166008811015156113c257fe5b67ffffffffffffffff9092166020929092" + "02015260010161135a565b5050505050505050565b60008787601081106113f657fe5b602002015190506000888760" + "10811061140b57fe5b60200201519050600089876010811061142057fe5b6020020151905060008a87601081106114" + "3557fe5b6020020151905068010000000000000000868486010893508318602081811c91901b67ffffffffffffffff" + "161868010000000000000000818308915067ffffffffffffffff82841860281b1682841860181c1892506801000000" + "0000000000858486010893508318601081901c60309190911b67ffffffffffffffff16186801000000000000000081" + "8308928318603f81901c60019190911b67ffffffffffffffff1618929150838b8b601081106114e957fe5b67ffffff" + "ffffffffff9092166020929092020152828b8a6010811061150a57fe5b67ffffffffffffffff909216602092909202" + "0152818b896010811061152b57fe5b67ffffffffffffffff9092166020929092020152808b886010811061154c57fe" + "5b67ffffffffffffffff90921660209290920201525050505050505050505050565b61010060405190810160405280" + "6008906020820280388339509192915050565b6101e0604051908101604052806115a26115e5565b81526020016115" + "af61156d565b81526000602082018190526040820181905260609091015290565b6040805180820182529060029082" + "9080388339509192915050565b6080604051908101604052806004906020820280388339509192915050565b610200" + "60405190810160405280601090602082028038833950919291505056fea165627a7a72305820a59dc9d098d29bacdd" + "88cb50c25c96ed4ba3047fd46a5c6ecf57e447a3c699100029"); + +using BuilderFn = decltype(&evmone::build_jumpdest_map); + +enum : uint8_t +{ + OP_JUMPDEST = 0x5b, + OP_PUSH1 = 0x60, + OP_PUSH32 = 0x7f, +}; + +[[gnu::noinline]] auto build(const uint8_t* code, size_t code_size) +{ + evmone::bitset m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m.set(i); + + if ((op >> 5) == 0b11) + i += static_cast((op & 0b11111) + 1); + } + return m; +} + +[[gnu::noinline]] auto build_vec(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m[i] = true; + else if (op >= OP_PUSH1 && op <= OP_PUSH32) + i += static_cast(op - OP_PUSH1 + 1); + } + return m; +} + +inline bool is_push(uint8_t op) +{ + // return op >= OP_PUSH1 && op <= OP_PUSH32; + return (op >> 5) == 0b11; + // return (op & uint8_t{0b11100000}) == 0b01100000; + // return (x & 0b1100000) != 0; +} + +// uint8_t get_push_size(uint8_t x) +//{ +// return (x & 0b11111); +//} + +[[gnu::noinline]] auto build_vec2(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m[i] = true; + else if (is_push(op)) + i += static_cast(op - OP_PUSH1 + 1); + } + return m; +} + +[[gnu::noinline]] auto build_vec3(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size;) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m[i] = true; + + i += is_push(op) ? static_cast(op - OP_PUSH1 + 2) : 1; + } + return m; +} + +[[gnu::noinline]] auto build_vec4(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + const auto code_beg = code; + const auto code_end = code + code_size; + for (;code < code_end; ++code) + { + const auto op = *code; + if (op == OP_JUMPDEST) + m[size_t(code - code_beg)] = true; + else if (is_push(op)) + code += static_cast(op - OP_PUSH1 + 1); + } + return m; +} + +[[gnu::noinline]] auto build_vec5(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + const auto s = size_t(op - OP_PUSH1); + if (op == OP_JUMPDEST) + m[i] = true; + else if (s <= 31) + i += s + 1; + } + return m; +} + +[[gnu::noinline]] auto build_vec6(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size;) + { + const auto op = code[i]; + const auto s = size_t(op - OP_PUSH1); + if (op == OP_JUMPDEST) + m[i] = true; + + i += (s <= 31) ? s + 1 : 1; + } + return m; +} + +[[gnu::noinline]] auto build_vec7(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size;) + { + const auto op = code[i]; + const auto s = size_t(op - OP_PUSH1); + if (op == OP_JUMPDEST) + m[i] = true; + + const auto a = (s <= 31) ? s : 0; + + i += a + 1; + } + return m; +} + +[[gnu::noinline]] auto build_bytes(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m[i] = true; + else if (op >= OP_PUSH1 && op <= OP_PUSH32) + i += static_cast(op - OP_PUSH1 + 1); + } + return m; +} + +[[gnu::noinline]] auto build_shadow_code(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + m[i] = op; + if (op >= OP_PUSH1 && op <= OP_PUSH32) + { + const auto s = static_cast(op - OP_PUSH1 + 1); + std::memset(&m[i + 1], 0, s); + i += s; + } + } + return m; +} + +[[gnu::noinline]] auto build_shadow_code2(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + long push_data = 0; + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + m[i] = push_data <= 0 ? op : 0; + --push_data; + if (op >= OP_PUSH1 && op <= OP_PUSH32) + push_data = op - OP_PUSH1 + 1; + } + return m; +} + +[[gnu::noinline]] auto build_shadow_code2p(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + long push_data = 0; + auto p = m.get(); + const auto end = p + code_size; + while (p != end) + { + const auto op = *code; + *p = push_data <= 0 ? op : 0; + --push_data; + if (op >= OP_PUSH1 && op <= OP_PUSH32) + push_data = op - OP_PUSH1 + 1; + ++p; + ++code; + } + return m; +} + +[[gnu::noinline]] auto build_shadow_code3(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + std::memcpy(m.get(), code, code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = m[i]; + if ((op >> 5) == 0b11) + { + const size_t s = static_cast((op & 0b11111) + 1); + std::memset(&m[i + 1], 0, s); + i += s; + } + } + return m; +} + +[[gnu::noinline]] auto build_shadow_code3p(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + std::memcpy(m.get(), code, code_size); + auto p = m.get(); + const auto end = p + code_size; + while (p < end) + { + const auto op = *p++; + if ((op >> 5) == 0b11) + { + const size_t s = (op & 0b11111); + std::memset(p, 0, s + 1); + p += s; + } + } + return m; +} + +[[gnu::noinline]] auto build_shadow_code4(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 33]}; + std::memcpy(m.get(), code, code_size); + long push_data = 0; + for (size_t i = 0; i < code_size; ++i) + { + const auto op = m[i]; + bool is_push_data = push_data > 0; + --push_data; + if (!is_push_data && (op >> 5) == 0b11) + { + push_data = op - OP_PUSH1 + 1; + } + else if (is_push_data && op == OP_JUMPDEST) + { + m[i] = 0; + } + } + return m; +} + +[[gnu::noinline]] auto copy_by1(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + m[i] = op; + } + return m; +} + +#pragma GCC push_options +#pragma GCC optimize("no-tree-loop-distribute-patterns") +[[gnu::noinline]] auto copy_by1p(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + 32]}; + auto p = m.get(); + const auto end = p + code_size; + while (p != end) + *p++ = *code++; + return m; +} +#pragma GCC pop_options + +[[gnu::noinline]] auto memcpy(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size]}; + std::memcpy(m.get(), code, code_size); + return m; +} + +template +void build_jumpdest(benchmark::State& state) +{ + for (auto _ : state) + { + auto r = Fn(test_bytecode.data(), test_bytecode.size()); + benchmark::DoNotOptimize(r); + } +} +} // namespace + +BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::build_jumpdest_map); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec2); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec6); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec7); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_bytes); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3p); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code4); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1p); +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, memcpy); From 4e3a489254f843ec0072140eec7a68eba2d3fc60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 11:35:00 +0100 Subject: [PATCH 02/74] test: Add evmone:experimental library --- test/CMakeLists.txt | 1 + test/experimental/CMakeLists.txt | 9 +++++++++ test/experimental/dummy.cpp | 0 3 files changed, 10 insertions(+) create mode 100644 test/experimental/CMakeLists.txt create mode 100644 test/experimental/dummy.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cfc2dd0f07..4c9e71e230 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(utils) add_subdirectory(bench) add_subdirectory(blockchaintest) add_subdirectory(eofparse) +add_subdirectory(experimental) add_subdirectory(integration) add_subdirectory(internal_benchmarks) add_subdirectory(precompiles_bench) diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt new file mode 100644 index 0000000000..1d0f166167 --- /dev/null +++ b/test/experimental/CMakeLists.txt @@ -0,0 +1,9 @@ +# evmone: Fast Ethereum Virtual Machine implementation +# Copyright 2020 The evmone Authors. +# SPDX-License-Identifier: Apache-2.0 + +add_library(evmone-experimental STATIC) +add_library(evmone::experimental ALIAS evmone-experimental) + +target_sources(evmone-experimental PRIVATE dummy.cpp) +target_include_directories(evmone-experimental PUBLIC ${PROJECT_SOURCE_DIR}) diff --git a/test/experimental/dummy.cpp b/test/experimental/dummy.cpp new file mode 100644 index 0000000000..e69de29bb2 From fc034e26e89fd958ba1cd5a5c8a3318dcdd07c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 12:59:52 +0100 Subject: [PATCH 03/74] test: Add procedure to find PUSHn in 8 bytes at once --- test/experimental/CMakeLists.txt | 2 +- test/experimental/opcode_manip.hpp | 73 ++++++++++++++++++++++++++++ test/unittests/CMakeLists.txt | 5 +- test/unittests/opcode_manip_test.cpp | 73 ++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 test/experimental/opcode_manip.hpp create mode 100644 test/unittests/opcode_manip_test.cpp diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt index 1d0f166167..7ac61b2d63 100644 --- a/test/experimental/CMakeLists.txt +++ b/test/experimental/CMakeLists.txt @@ -5,5 +5,5 @@ add_library(evmone-experimental STATIC) add_library(evmone::experimental ALIAS evmone-experimental) -target_sources(evmone-experimental PRIVATE dummy.cpp) +target_sources(evmone-experimental PRIVATE dummy.cpp opcode_manip.hpp) target_include_directories(evmone-experimental PUBLIC ${PROJECT_SOURCE_DIR}) diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp new file mode 100644 index 0000000000..e018fe830e --- /dev/null +++ b/test/experimental/opcode_manip.hpp @@ -0,0 +1,73 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include + +namespace evmone::experimental +{ +inline constexpr bool is_push(uint8_t opcode) noexcept +{ + return opcode >= OP_PUSH1 && opcode <= OP_PUSH32; +} + +inline constexpr int find_first_push(const uint8_t* code) noexcept +{ + for (int i = 0; i < 8; ++i) + { + if (is_push(code[i])) + return i; + } + return -1; +} + +inline int find_first_push_opt1(const uint8_t* code) noexcept +{ + uint64_t b; + __builtin_memcpy(&b, code, sizeof(b)); + b = __builtin_bswap64(b); + + const auto d = (b << 1) & (b << 2) & 0x8080808080808080; + + if (d == 0) + return -1; + + auto z = __builtin_clzll(d); + auto z2 = z / 8; + return z2; +} + +inline int find_first_push_opt2(const uint8_t* code) noexcept +{ + uint64_t b; + __builtin_memcpy(&b, code, sizeof(b)); + b = __builtin_bswap64(b); + uint64_t mask = 0x8080808080808080; + + auto e2 = b << 2; + auto f2 = b << 1; + auto d1 = e2 & f2 & mask; + + if (d1 == 0) + return -1; + + auto z = __builtin_clzll(d1); + auto z2 = z / 8; + return z2; +} + +inline int find_first_push_opt3(const uint8_t* code) noexcept +{ + uint64_t b; + __builtin_memcpy(&b, code, sizeof(b)); + + const auto d = (b >> 5) & (b >> 6) & 0x0101010101010101; + + if (d == 0) + return -1; + + auto z = __builtin_ctzll(d); + auto z2 = z / 8; + return z2; +} +} // namespace evmone::experimental diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index ec53e8a232..3e011962f0 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -82,8 +82,11 @@ target_sources( statetest_logs_hash_test.cpp statetest_withdrawals_test.cpp tracing_test.cpp + op_table_test.cpp + opcode_manip_test.cpp + utils_test.cpp ) -target_link_libraries(evmone-unittests PRIVATE evmone evmone::evmmax evmone::state evmone::statetestutils testutils evmc::instructions GTest::gtest GTest::gtest_main) +target_link_libraries(evmone-unittests PRIVATE evmone evmone::evmmax evmone::state evmone::experimental evmone::statetestutils testutils evmc::instructions GTest::gtest GTest::gtest_main) target_include_directories(evmone-unittests PRIVATE ${evmone_private_include_dir}) target_compile_options(evmone-unittests PRIVATE # Disable false positive C4789 diff --git a/test/unittests/opcode_manip_test.cpp b/test/unittests/opcode_manip_test.cpp new file mode 100644 index 0000000000..f5e6da28b4 --- /dev/null +++ b/test/unittests/opcode_manip_test.cpp @@ -0,0 +1,73 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "test/experimental/opcode_manip.hpp" +#include "test/utils/bytecode.hpp" +#include + +using namespace evmone::experimental; + +TEST(opcode_manip, find_first_push) +{ + struct TestCase + { + bytecode code; + int expected; + }; + + static TestCase test_cases[]{ + {"0000000000000000", -1}, + {"6000000000000000", 0}, + {"0060000000000000", 1}, + {"0000600000000000", 2}, + {"0000006000000000", 3}, + {"0000000060000000", 4}, + {"0000000000600000", 5}, + {"0000000000006000", 6}, + {"0000000000000060", 7}, + {"6100000000000000", 0}, + {"0061000000000000", 1}, + {"0000610000000000", 2}, + {"0000006100000000", 3}, + {"0000000061000000", 4}, + {"0000000000610000", 5}, + {"0000000000006100", 6}, + {"0000000000000061", 7}, + {"7f00000000000000", 0}, + {"007f000000000000", 1}, + {"00007f0000000000", 2}, + {"0000007f00000000", 3}, + {"000000007f000000", 4}, + {"00000000007f0000", 5}, + {"0000000000007f00", 6}, + {"000000000000007f", 7}, + {"7000000000000000", 0}, + {"0070000000000000", 1}, + {"0000700000000000", 2}, + {"0000007000000000", 3}, + {"0000000070000000", 4}, + {"0000000000700000", 5}, + {"0000000000007000", 6}, + {"0000000000000070", 7}, + {"6060606060606060", 0}, + {"0060606060606060", 1}, + {"0000606060606060", 2}, + {"0000006060606060", 3}, + {"0000000060606060", 4}, + {"0000000000606060", 5}, + {"0000000000006060", 6}, + {"0000000000000060", 7}, + {"e000000000000000", -1}, + {"0000e00000000000", -1}, + {"000000e0e0e0e0e0", -1}, + }; + + for (const auto& [code, expected] : test_cases) + { + EXPECT_EQ(find_first_push(code.data()), expected); + EXPECT_EQ(find_first_push_opt1(code.data()), expected); + EXPECT_EQ(find_first_push_opt2(code.data()), expected); + EXPECT_EQ(find_first_push_opt3(code.data()), expected); + } +} From 8af82b5669c4c67a6ccfb8760cce755111384700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 13:36:42 +0100 Subject: [PATCH 04/74] test: Add jumpdest analysis differential test --- test/unittests/CMakeLists.txt | 1 + test/unittests/jumpdest_analysis_test.cpp | 48 +++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test/unittests/jumpdest_analysis_test.cpp diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 3e011962f0..75d60c5a90 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -82,6 +82,7 @@ target_sources( statetest_logs_hash_test.cpp statetest_withdrawals_test.cpp tracing_test.cpp + jumpdest_analysis_test.cpp op_table_test.cpp opcode_manip_test.cpp utils_test.cpp diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp new file mode 100644 index 0000000000..3e53559828 --- /dev/null +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -0,0 +1,48 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "test/utils/bytecode.hpp" +#include +#include +#include + +using namespace evmone; + +namespace +{ +constexpr auto tail_code_padding = 100; + +inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept +{ + return (index < a.size() && a[index]); +} + +inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept +{ + return find_jumpdest(a, static_cast(index)) >= 0; +} + +const bytecode bytecode_test_cases[]{ + {}, + OP_JUMPDEST, + push(0), + push(0x5b), + push(0x5b) + OP_JUMPDEST, +}; +} // namespace + +TEST(jumpdest_analysis, compare_implementations) +{ + for (const auto& t : bytecode_test_cases) + { + const auto a0 = build_jumpdest_map(t.data(), t.size()); + const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); + + for (size_t i = 0; i < t.size() + tail_code_padding; ++i) + { + const bool expected = is_jumpdest(a0, i); + EXPECT_EQ(is_jumpdest(a1, i), expected); + } + } +} \ No newline at end of file From 6ae6a4f33743b83f590d6432f78b01f04468cc3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 13:54:09 +0100 Subject: [PATCH 05/74] test: Add experimental jumpdest analysis --- test/experimental/CMakeLists.txt | 7 +++++- test/experimental/dummy.cpp | 0 test/experimental/jumpdest_analysis.cpp | 28 +++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 16 ++++++++++++ test/internal_benchmarks/CMakeLists.txt | 2 +- test/internal_benchmarks/analysis_bench.cpp | 17 ++----------- test/unittests/jumpdest_analysis_test.cpp | 4 +++ 7 files changed, 57 insertions(+), 17 deletions(-) delete mode 100644 test/experimental/dummy.cpp create mode 100644 test/experimental/jumpdest_analysis.cpp create mode 100644 test/experimental/jumpdest_analysis.hpp diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt index 7ac61b2d63..356c8af7b4 100644 --- a/test/experimental/CMakeLists.txt +++ b/test/experimental/CMakeLists.txt @@ -5,5 +5,10 @@ add_library(evmone-experimental STATIC) add_library(evmone::experimental ALIAS evmone-experimental) -target_sources(evmone-experimental PRIVATE dummy.cpp opcode_manip.hpp) target_include_directories(evmone-experimental PUBLIC ${PROJECT_SOURCE_DIR}) +target_link_libraries(evmone-experimental PRIVATE evmc::instructions) +target_sources( + evmone-experimental PRIVATE + jumpdest_analysis.cpp + opcode_manip.hpp +) diff --git a/test/experimental/dummy.cpp b/test/experimental/dummy.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp new file mode 100644 index 0000000000..f1382588ae --- /dev/null +++ b/test/experimental/jumpdest_analysis.cpp @@ -0,0 +1,28 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "jumpdest_analysis.hpp" +#include + +namespace evmone::experimental +{ +inline constexpr bool is_push(uint8_t op) noexcept +{ + return (op >> 5) == 0b11; +} + +std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m[i] = true; + else if (is_push(op)) + i += static_cast(op - OP_PUSH1 + 1); + } + return m; +} +} // namespace evmone::experimental \ No newline at end of file diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp new file mode 100644 index 0000000000..8d6eb55d2a --- /dev/null +++ b/test/experimental/jumpdest_analysis.hpp @@ -0,0 +1,16 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +namespace evmone::experimental +{ +inline bool is_jumpdest(const std::vector& jumpdest_map, size_t index) noexcept +{ + return (index < jumpdest_map.size() && jumpdest_map[index]); +} + +std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); +} // namespace evmone::experimental diff --git a/test/internal_benchmarks/CMakeLists.txt b/test/internal_benchmarks/CMakeLists.txt index 587ef7d2e0..6f7bafa617 100644 --- a/test/internal_benchmarks/CMakeLists.txt +++ b/test/internal_benchmarks/CMakeLists.txt @@ -10,4 +10,4 @@ add_executable( memory_allocation.cpp ) -target_link_libraries(evmone-bench-internal PRIVATE evmone::evmmax benchmark::benchmark) +target_link_libraries(evmone-bench-internal PRIVATE evmone::evmmax evmone::experimental benchmark::benchmark) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 2c034237b2..38af94ca78 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -4,6 +4,7 @@ #include "evmone/baseline.hpp" #include "test/utils/utils.hpp" +#include "test/experimental/jumpdest_analysis.hpp" #include @@ -184,20 +185,6 @@ inline bool is_push(uint8_t op) // return (x & 0b11111); //} -[[gnu::noinline]] auto build_vec2(const uint8_t* code, size_t code_size) -{ - std::vector m(code_size); - for (size_t i = 0; i < code_size; ++i) - { - const auto op = code[i]; - if (op == OP_JUMPDEST) - m[i] = true; - else if (is_push(op)) - i += static_cast(op - OP_PUSH1 + 1); - } - return m; -} - [[gnu::noinline]] auto build_vec3(const uint8_t* code, size_t code_size) { std::vector m(code_size); @@ -443,7 +430,7 @@ void build_jumpdest(benchmark::State& state) BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::build_jumpdest_map); BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec2); +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 3e53559828..04dee13867 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -2,12 +2,14 @@ // Copyright 2020 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#include "test/experimental/jumpdest_analysis.hpp" #include "test/utils/bytecode.hpp" #include #include #include using namespace evmone; +using namespace evmone::experimental; namespace { @@ -38,11 +40,13 @@ TEST(jumpdest_analysis, compare_implementations) { const auto a0 = build_jumpdest_map(t.data(), t.size()); const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); + const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { const bool expected = is_jumpdest(a0, i); EXPECT_EQ(is_jumpdest(a1, i), expected); + EXPECT_EQ(is_jumpdest(a2, i), expected); } } } \ No newline at end of file From 56ca120fe82ef009e823f75efc74b22c493dca59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 14:09:44 +0100 Subject: [PATCH 06/74] test: Add experimental optimized jumpdest analysis --- test/experimental/CMakeLists.txt | 4 ++-- test/experimental/jumpdest_analysis.cpp | 15 +++++++++++++++ test/experimental/jumpdest_analysis.hpp | 2 ++ test/internal_benchmarks/analysis_bench.cpp | 5 +++-- test/unittests/jumpdest_analysis_test.cpp | 2 ++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt index 356c8af7b4..0fb08bc843 100644 --- a/test/experimental/CMakeLists.txt +++ b/test/experimental/CMakeLists.txt @@ -5,8 +5,8 @@ add_library(evmone-experimental STATIC) add_library(evmone::experimental ALIAS evmone-experimental) -target_include_directories(evmone-experimental PUBLIC ${PROJECT_SOURCE_DIR}) -target_link_libraries(evmone-experimental PRIVATE evmc::instructions) +target_include_directories(evmone-experimental PUBLIC ${PROJECT_SOURCE_DIR} ${evmone_private_include_dir}) +target_link_libraries(evmone-experimental PRIVATE evmone evmc::instructions) target_sources( evmone-experimental PRIVATE jumpdest_analysis.cpp diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index f1382588ae..9d4a5ae68c 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "jumpdest_analysis.hpp" +#include #include namespace evmone::experimental @@ -25,4 +26,18 @@ std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) } return m; } + +JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) +{ + JumpdestMap m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (op == OP_JUMPDEST) + m.set(i); + else if (is_push(op)) + i += static_cast(op - OP_PUSH1 + 1); + } + return m; +} } // namespace evmone::experimental \ No newline at end of file diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 8d6eb55d2a..d70bbda56e 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -2,6 +2,7 @@ // Copyright 2020 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#include #include #include @@ -13,4 +14,5 @@ inline bool is_jumpdest(const std::vector& jumpdest_map, size_t index) noe } std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); +bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); } // namespace evmone::experimental diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 38af94ca78..108815dd5f 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -143,7 +143,7 @@ enum : uint8_t OP_PUSH32 = 0x7f, }; -[[gnu::noinline]] auto build(const uint8_t* code, size_t code_size) +[[gnu::noinline]] auto build_bitset2(const uint8_t* code, size_t code_size) { evmone::bitset m(code_size); for (size_t i = 0; i < code_size; ++i) @@ -428,7 +428,8 @@ void build_jumpdest(benchmark::State& state) } // namespace BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::build_jumpdest_map); -BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::experimental::build_jumpdest_map_bitset1); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 04dee13867..3e568872a4 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -41,12 +41,14 @@ TEST(jumpdest_analysis, compare_implementations) const auto a0 = build_jumpdest_map(t.data(), t.size()); const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); + const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { const bool expected = is_jumpdest(a0, i); EXPECT_EQ(is_jumpdest(a1, i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); + EXPECT_EQ(is_jumpdest(a3, i), expected); } } } \ No newline at end of file From 34fcda431c44dd5b17afe5e5ee4b078edff8006d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 16:27:20 +0100 Subject: [PATCH 07/74] fuzz: Add jumpdest analysis fuzzer --- test/CMakeLists.txt | 2 +- test/fuzzer/CMakeLists.txt | 6 +++ test/fuzzer/jumpdest_analysis_fuzz.cpp | 52 ++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/fuzzer/jumpdest_analysis_fuzz.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4c9e71e230..06cfd64aee 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,7 +35,7 @@ set(targets evmone-bench evmone-bench-internal evmone-eofparse evmone-blockchain if(EVMONE_FUZZING) add_subdirectory(eofparsefuzz) add_subdirectory(fuzzer) - list(APPEND targets evmone-eofparsefuzz evmone-fuzzer) + list(APPEND targets evmone-eofparsefuzz evmone-fuzzer jumpdest-fuzzer) endif() set_target_properties( diff --git a/test/fuzzer/CMakeLists.txt b/test/fuzzer/CMakeLists.txt index cd8e340136..19625fac30 100644 --- a/test/fuzzer/CMakeLists.txt +++ b/test/fuzzer/CMakeLists.txt @@ -14,5 +14,11 @@ else() string(REPLACE fuzzer-no-link fuzzer CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) endif() +hunter_add_package(intx) +find_package(intx CONFIG REQUIRED) + add_executable(evmone-fuzzer fuzzer.cpp) target_link_libraries(evmone-fuzzer PRIVATE evmone evmone::testutils evmc::mocked_host) + +add_executable(jumpdest-fuzzer jumpdest_analysis_fuzz.cpp) +target_link_libraries(jumpdest-fuzzer PRIVATE evmone evmone::experimental intx::intx) \ No newline at end of file diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp new file mode 100644 index 0000000000..a2036a92f6 --- /dev/null +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -0,0 +1,52 @@ +// evmone-fuzzer: LibFuzzer based testing tool for EVMC-compatible EVM implementations. +// Copyright 2020 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "test/experimental/jumpdest_analysis.hpp" +#include +#include + + +using namespace evmone; +using namespace evmone::experimental; + +namespace +{ +template +inline void expect_eq(T1 a, T2 b) noexcept +{ + if (a != b) + __builtin_trap(); +} + +constexpr auto tail_code_padding = 100; + +inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept +{ + return (index < a.size() && a[index]); +} + +inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept +{ + return find_jumpdest(a, static_cast(index)) >= 0; +} +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noexcept +{ + const auto a0 = build_jumpdest_map(data, data_size); + const auto a1 = analyze(EVMC_FRONTIER, data, data_size); + const auto a2 = build_jumpdest_map_vec1(data, data_size); + const auto a3 = build_jumpdest_map_bitset1(data, data_size); + + for (size_t i = 0; i < data_size + tail_code_padding; ++i) + { + const bool expected = is_jumpdest(a0, i); + expect_eq(is_jumpdest(a1, i), expected); + expect_eq(is_jumpdest(a2, i), expected); + expect_eq(is_jumpdest(a3, i), expected); + } + + + return 0; +} From 78698636ca3373ba1039adec929bcb34e8d96dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 16:57:00 +0100 Subject: [PATCH 08/74] experimental: Add internal code form of jumpdest map --- test/experimental/jumpdest_analysis.cpp | 32 ++++++++++++++++++--- test/experimental/jumpdest_analysis.hpp | 7 +++++ test/fuzzer/jumpdest_analysis_fuzz.cpp | 4 ++- test/internal_benchmarks/analysis_bench.cpp | 30 ++++++------------- test/unittests/jumpdest_analysis_test.cpp | 4 +++ 5 files changed, 50 insertions(+), 27 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 9d4a5ae68c..bf686947b7 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 #include "jumpdest_analysis.hpp" -#include #include +#include namespace evmone::experimental { @@ -13,6 +13,11 @@ inline constexpr bool is_push(uint8_t op) noexcept return (op >> 5) == 0b11; } +inline constexpr size_t get_push_data_size(uint8_t op) noexcept +{ + return op - size_t{OP_PUSH1 - 1}; +} + std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) { std::vector m(code_size); @@ -22,7 +27,7 @@ std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) if (op == OP_JUMPDEST) m[i] = true; else if (is_push(op)) - i += static_cast(op - OP_PUSH1 + 1); + i += get_push_data_size(op); } return m; } @@ -36,8 +41,27 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) if (op == OP_JUMPDEST) m.set(i); else if (is_push(op)) - i += static_cast(op - OP_PUSH1 + 1); + i += get_push_data_size(op); + } + return m; +} + +std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size) +{ + static constexpr size_t padding = 33; + std::unique_ptr m{new uint8_t[code_size + padding]}; + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + m[i] = op; + if (is_push(op)) + { + const auto s = get_push_data_size(op); + std::memset(&m[i + 1], 0, s); + i += s; + } } + std::memset(&m[code_size], 0, padding); return m; } -} // namespace evmone::experimental \ No newline at end of file +} // namespace evmone::experimental diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index d70bbda56e..d75d34fb83 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace evmone::experimental @@ -13,6 +14,12 @@ inline bool is_jumpdest(const std::vector& jumpdest_map, size_t index) noe return (index < jumpdest_map.size() && jumpdest_map[index]); } +inline bool is_jumpdest(const uint8_t* code, size_t code_size, size_t index) noexcept +{ + return (index < code_size && code[index] == 0x5b); +} + std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); +std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); } // namespace evmone::experimental diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index a2036a92f6..12f3142d94 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -26,7 +26,7 @@ inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept return (index < a.size() && a[index]); } -inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept +[[maybe_unused]] inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept { return find_jumpdest(a, static_cast(index)) >= 0; } @@ -38,6 +38,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a1 = analyze(EVMC_FRONTIER, data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); + const auto a4 = build_internal_code_v1(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { @@ -45,6 +46,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a1, i), expected); expect_eq(is_jumpdest(a2, i), expected); expect_eq(is_jumpdest(a3, i), expected); + expect_eq(is_jumpdest(a4.get(), data_size, i), expected); } diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 108815dd5f..f83c17e3a2 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 #include "evmone/baseline.hpp" -#include "test/utils/utils.hpp" #include "test/experimental/jumpdest_analysis.hpp" +#include "test/utils/utils.hpp" #include @@ -204,7 +204,7 @@ inline bool is_push(uint8_t op) std::vector m(code_size); const auto code_beg = code; const auto code_end = code + code_size; - for (;code < code_end; ++code) + for (; code < code_end; ++code) { const auto op = *code; if (op == OP_JUMPDEST) @@ -276,23 +276,6 @@ inline bool is_push(uint8_t op) return m; } -[[gnu::noinline]] auto build_shadow_code(const uint8_t* code, size_t code_size) -{ - std::unique_ptr m{new uint8_t[code_size + 32]}; - for (size_t i = 0; i < code_size; ++i) - { - const auto op = code[i]; - m[i] = op; - if (op >= OP_PUSH1 && op <= OP_PUSH32) - { - const auto s = static_cast(op - OP_PUSH1 + 1); - std::memset(&m[i + 1], 0, s); - i += s; - } - } - return m; -} - [[gnu::noinline]] auto build_shadow_code2(const uint8_t* code, size_t code_size) { std::unique_ptr m{new uint8_t[code_size + 32]}; @@ -428,17 +411,20 @@ void build_jumpdest(benchmark::State& state) } // namespace BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::build_jumpdest_map); -BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::experimental::build_jumpdest_map_bitset1); +BENCHMARK_TEMPLATE( + build_jumpdest, evmone::bitset, evmone::experimental::build_jumpdest_map_bitset1); BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec6); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec7); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_bytes); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code); +BENCHMARK_TEMPLATE( + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v1); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 3e568872a4..b4090b32f8 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -38,17 +38,21 @@ TEST(jumpdest_analysis, compare_implementations) { for (const auto& t : bytecode_test_cases) { + SCOPED_TRACE(hex(t)); const auto a0 = build_jumpdest_map(t.data(), t.size()); const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); + const auto a4 = build_internal_code_v1(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { + SCOPED_TRACE(i); const bool expected = is_jumpdest(a0, i); EXPECT_EQ(is_jumpdest(a1, i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); + EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); } } } \ No newline at end of file From 0dc6a9747b4dc94340abe76d68935f4c51f3f970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 17:31:36 +0100 Subject: [PATCH 09/74] experimental: Different implementation --- test/experimental/jumpdest_analysis.cpp | 39 ++++++++++++++++++++- test/experimental/jumpdest_analysis.hpp | 2 ++ test/fuzzer/jumpdest_analysis_fuzz.cpp | 4 +++ test/internal_benchmarks/analysis_bench.cpp | 38 +++----------------- test/unittests/jumpdest_analysis_test.cpp | 5 +++ 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index bf686947b7..249ee253a1 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -46,9 +46,10 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) return m; } +static constexpr size_t padding = 33; + std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size) { - static constexpr size_t padding = 33; std::unique_ptr m{new uint8_t[code_size + padding]}; for (size_t i = 0; i < code_size; ++i) { @@ -64,4 +65,40 @@ std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t co std::memset(&m[code_size], 0, padding); return m; } + +std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + padding]}; + long push_data = 0; + for (size_t i = 0; i < code_size; ++i) + { + const auto in_push_data = push_data > 0; + --push_data; + const auto op = code[i]; + m[i] = !in_push_data ? op : 0; + if (!in_push_data && is_push(op)) + push_data = static_cast(get_push_data_size(op)); + } + std::memset(&m[code_size], 0, padding); + return m; +} + +std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + padding]}; + std::memcpy(&m[0], code, code_size); + std::memset(&m[code_size], 0, padding); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = m[i]; + if (is_push(op)) + { + const auto s = get_push_data_size(op); + std::memset(&m[i + 1], 0, s); + i += s; + } + } + return m; +} + } // namespace evmone::experimental diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index d75d34fb83..a29ba82ead 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -22,4 +22,6 @@ inline bool is_jumpdest(const uint8_t* code, size_t code_size, size_t index) noe std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); +std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); +std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t code_size); } // namespace evmone::experimental diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 12f3142d94..0ea5474cdd 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -39,6 +39,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); + const auto a5 = build_internal_code_v2(data, data_size); + const auto a6 = build_internal_code_v3(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { @@ -47,6 +49,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a2, i), expected); expect_eq(is_jumpdest(a3, i), expected); expect_eq(is_jumpdest(a4.get(), data_size, i), expected); + expect_eq(is_jumpdest(a5.get(), data_size, i), expected); + expect_eq(is_jumpdest(a6.get(), data_size, i), expected); } diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index f83c17e3a2..6201594834 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -276,21 +276,6 @@ inline bool is_push(uint8_t op) return m; } -[[gnu::noinline]] auto build_shadow_code2(const uint8_t* code, size_t code_size) -{ - std::unique_ptr m{new uint8_t[code_size + 32]}; - long push_data = 0; - for (size_t i = 0; i < code_size; ++i) - { - const auto op = code[i]; - m[i] = push_data <= 0 ? op : 0; - --push_data; - if (op >= OP_PUSH1 && op <= OP_PUSH32) - push_data = op - OP_PUSH1 + 1; - } - return m; -} - [[gnu::noinline]] auto build_shadow_code2p(const uint8_t* code, size_t code_size) { std::unique_ptr m{new uint8_t[code_size + 32]}; @@ -310,23 +295,6 @@ inline bool is_push(uint8_t op) return m; } -[[gnu::noinline]] auto build_shadow_code3(const uint8_t* code, size_t code_size) -{ - std::unique_ptr m{new uint8_t[code_size + 32]}; - std::memcpy(m.get(), code, code_size); - for (size_t i = 0; i < code_size; ++i) - { - const auto op = m[i]; - if ((op >> 5) == 0b11) - { - const size_t s = static_cast((op & 0b11111) + 1); - std::memset(&m[i + 1], 0, s); - i += s; - } - } - return m; -} - [[gnu::noinline]] auto build_shadow_code3p(const uint8_t* code, size_t code_size) { std::unique_ptr m{new uint8_t[code_size + 32]}; @@ -425,9 +393,11 @@ BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec7); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_bytes); BENCHMARK_TEMPLATE( build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v1); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2); +BENCHMARK_TEMPLATE( + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v2); +BENCHMARK_TEMPLATE( + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v3); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3p); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code4); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index b4090b32f8..02173516d4 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -26,6 +26,7 @@ inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept } const bytecode bytecode_test_cases[]{ + push(0x60) + OP_JUMPDEST, {}, OP_JUMPDEST, push(0), @@ -44,6 +45,8 @@ TEST(jumpdest_analysis, compare_implementations) const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); const auto a4 = build_internal_code_v1(t.data(), t.size()); + const auto a5 = build_internal_code_v2(t.data(), t.size()); + const auto a6 = build_internal_code_v3(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { @@ -53,6 +56,8 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); + EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); + EXPECT_EQ(is_jumpdest(a6.get(), t.size(), i), expected); } } } \ No newline at end of file From 16b704cbc53a065874f0fa2d79bac077072a501d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 17:39:32 +0100 Subject: [PATCH 10/74] experimental: Fix find_first_push procedures --- test/experimental/opcode_manip.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp index e018fe830e..350d5e22e2 100644 --- a/test/experimental/opcode_manip.hpp +++ b/test/experimental/opcode_manip.hpp @@ -27,7 +27,7 @@ inline int find_first_push_opt1(const uint8_t* code) noexcept __builtin_memcpy(&b, code, sizeof(b)); b = __builtin_bswap64(b); - const auto d = (b << 1) & (b << 2) & 0x8080808080808080; + const auto d = (~b) & (b << 1) & (b << 2) & 0x8080808080808080; if (d == 0) return -1; @@ -46,7 +46,8 @@ inline int find_first_push_opt2(const uint8_t* code) noexcept auto e2 = b << 2; auto f2 = b << 1; - auto d1 = e2 & f2 & mask; + auto g2 = ~b; + auto d1 = e2 & f2 & g2 & mask; if (d1 == 0) return -1; @@ -61,7 +62,7 @@ inline int find_first_push_opt3(const uint8_t* code) noexcept uint64_t b; __builtin_memcpy(&b, code, sizeof(b)); - const auto d = (b >> 5) & (b >> 6) & 0x0101010101010101; + const auto d = (b >> 5) & (b >> 6) & (~b >> 7) & 0x0101010101010101; if (d == 0) return -1; From bdd681138fe0bd55b6bd35b555f7bda7b1ffa15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 17:55:30 +0100 Subject: [PATCH 11/74] experimental: Rework build_internal_code_v2 --- test/experimental/jumpdest_analysis.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 249ee253a1..659b44ae2f 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -72,12 +72,18 @@ std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t co long push_data = 0; for (size_t i = 0; i < code_size; ++i) { - const auto in_push_data = push_data > 0; - --push_data; - const auto op = code[i]; - m[i] = !in_push_data ? op : 0; - if (!in_push_data && is_push(op)) - push_data = static_cast(get_push_data_size(op)); + if (push_data != 0) [[unlikely]] + { + --push_data; + m[i] = 0; + } + else + { + const auto op = code[i]; + m[i] = op; + if (is_push(op)) + push_data = static_cast(get_push_data_size(op)); + } } std::memset(&m[code_size], 0, padding); return m; From 37c50aaa32f9afa164eab43549791998b50ae040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 13 Nov 2020 18:58:26 +0100 Subject: [PATCH 12/74] experimental: Search PUSHes by 8 bytes --- test/experimental/jumpdest_analysis.cpp | 34 ++++++++++++++++++--- test/experimental/jumpdest_analysis.hpp | 1 + test/experimental/opcode_manip.hpp | 4 +-- test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 ++ test/internal_benchmarks/analysis_bench.cpp | 2 ++ test/unittests/jumpdest_analysis_test.cpp | 6 ++-- 6 files changed, 40 insertions(+), 9 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 659b44ae2f..f4ae771654 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -3,16 +3,12 @@ // SPDX-License-Identifier: Apache-2.0 #include "jumpdest_analysis.hpp" +#include "opcode_manip.hpp" #include #include namespace evmone::experimental { -inline constexpr bool is_push(uint8_t op) noexcept -{ - return (op >> 5) == 0b11; -} - inline constexpr size_t get_push_data_size(uint8_t op) noexcept { return op - size_t{OP_PUSH1 - 1}; @@ -107,4 +103,32 @@ std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t co return m; } +std::unique_ptr build_internal_code_v8(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + padding]}; + std::memcpy(&m[0], code, code_size); + std::memset(&m[code_size], 0, padding); + + size_t i = 0; + + while (i < code_size) + { + const auto pos = find_first_push_opt3(&m[i]); + if (pos < 0) + { + i += 8; + } + else + { + i += static_cast(pos); + const auto op = m[i]; + ++i; + const auto s = get_push_data_size(op); + std::memset(&m[i], 0, s); + i += s; + } + } + return m; +} + } // namespace evmone::experimental diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index a29ba82ead..0c17d611e7 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -24,4 +24,5 @@ bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t code_size); +std::unique_ptr build_internal_code_v8(const uint8_t* code, size_t code_size); } // namespace evmone::experimental diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp index 350d5e22e2..10859ad890 100644 --- a/test/experimental/opcode_manip.hpp +++ b/test/experimental/opcode_manip.hpp @@ -6,9 +6,9 @@ namespace evmone::experimental { -inline constexpr bool is_push(uint8_t opcode) noexcept +inline constexpr bool is_push(uint8_t op) noexcept { - return opcode >= OP_PUSH1 && opcode <= OP_PUSH32; + return (op >> 5) == 0b11; } inline constexpr int find_first_push(const uint8_t* code) noexcept diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 0ea5474cdd..c16e71860e 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -41,6 +41,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); const auto a6 = build_internal_code_v3(data, data_size); + const auto ic8 = build_internal_code_v8(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { @@ -51,6 +52,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); expect_eq(is_jumpdest(a6.get(), data_size, i), expected); + expect_eq(is_jumpdest(ic8.get(), data_size, i), expected); } diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 6201594834..41ef835617 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -397,6 +397,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v2); BENCHMARK_TEMPLATE( build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v3); +BENCHMARK_TEMPLATE( + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v8); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3p); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code4); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 02173516d4..5521431fe6 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -26,12 +26,12 @@ inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept } const bytecode bytecode_test_cases[]{ - push(0x60) + OP_JUMPDEST, + push(0x5b), {}, OP_JUMPDEST, push(0), - push(0x5b), push(0x5b) + OP_JUMPDEST, + push(0x60) + OP_JUMPDEST, }; } // namespace @@ -47,6 +47,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); const auto a6 = build_internal_code_v3(t.data(), t.size()); + const auto ic8 = build_internal_code_v8(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { @@ -58,6 +59,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a6.get(), t.size(), i), expected); + EXPECT_EQ(is_jumpdest(ic8.get(), t.size(), i), expected); } } } \ No newline at end of file From f6929973172319cbc1a7efce5a30e4d035867723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 14 Nov 2020 12:35:39 +0100 Subject: [PATCH 13/74] experimental: Add new impl --- test/experimental/jumpdest_analysis.cpp | 29 +++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 ++ test/internal_benchmarks/analysis_bench.cpp | 2 ++ test/unittests/jumpdest_analysis_test.cpp | 2 ++ 5 files changed, 36 insertions(+) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index f4ae771654..90f26665f0 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -103,6 +103,35 @@ std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t co return m; } +std::unique_ptr build_internal_code_v4(const uint8_t* code, size_t code_size) +{ + std::unique_ptr m{new uint8_t[code_size + padding]}; + auto p = m.get(); + const auto end = p + code_size; + + std::memcpy(p, code, code_size); + std::memset(end, OP_PUSH1, padding); + + while (true) + { + const auto op = *p++; + if (is_push(op)) + { + if (p > end) + break; + const auto s = get_push_data_size(op); + for (size_t i = 0; i < s; ++i) + { + if (*p == OP_JUMPDEST) + *p = 0; + ++p; + } + } + } + std::memset(end, 0, padding); + return m; +} + std::unique_ptr build_internal_code_v8(const uint8_t* code, size_t code_size) { std::unique_ptr m{new uint8_t[code_size + padding]}; diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 0c17d611e7..8883637f9e 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -24,5 +24,6 @@ bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t code_size); +std::unique_ptr build_internal_code_v4(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v8(const uint8_t* code, size_t code_size); } // namespace evmone::experimental diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index c16e71860e..28ba1f9aa7 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -41,6 +41,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); const auto a6 = build_internal_code_v3(data, data_size); + const auto ic4 = build_internal_code_v4(data, data_size); const auto ic8 = build_internal_code_v8(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) @@ -52,6 +53,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); expect_eq(is_jumpdest(a6.get(), data_size, i), expected); + expect_eq(is_jumpdest(ic4.get(), data_size, i), expected); expect_eq(is_jumpdest(ic8.get(), data_size, i), expected); } diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 41ef835617..90f5a6b28d 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -397,6 +397,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v2); BENCHMARK_TEMPLATE( build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v3); +BENCHMARK_TEMPLATE( + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v4); BENCHMARK_TEMPLATE( build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v8); BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 5521431fe6..d66d632af7 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -47,6 +47,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); const auto a6 = build_internal_code_v3(t.data(), t.size()); + const auto ic4 = build_internal_code_v4(t.data(), t.size()); const auto ic8 = build_internal_code_v8(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) @@ -59,6 +60,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a6.get(), t.size(), i), expected); + EXPECT_EQ(is_jumpdest(ic4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(ic8.get(), t.size(), i), expected); } } From 7f5539670083a93a281d4503964c8f2f29ca071c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Apr 2021 21:36:08 +0200 Subject: [PATCH 14/74] Analyze PUSH distribution --- test/internal_benchmarks/analysis_bench.cpp | 42 +++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 90f5a6b28d..f5a9a87505 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -6,6 +6,9 @@ #include "test/experimental/jumpdest_analysis.hpp" #include "test/utils/utils.hpp" #include +#include + +#include namespace @@ -180,6 +183,45 @@ inline bool is_push(uint8_t op) // return (x & 0b1100000) != 0; } +[[maybe_unused]] bool x = []() noexcept { + size_t last_push = size_t(-1); + std::vector dists; + for (size_t i = 0; i < test_bytecode.size();) + { + const auto op = test_bytecode[i]; + + if (is_push(op)) + { + if (last_push != size_t(-1)) + dists.push_back(static_cast(i - last_push)); + last_push = i; + } + + i += is_push(op) ? static_cast(op - OP_PUSH1 + 2) : 1; + } + + auto sum = std::accumulate(dists.begin(), dists.end(), 0); + std::sort(dists.begin(), dists.end()); + + std::cerr << "AVG: " << double(sum) / double(dists.size()) << "\n"; + std::cerr << "MED: " << dists[dists.size() / 2] << "\n"; + + int last = 0; + int count = 0; + for (auto d : dists) + { + if (d == last) + ++count; + else + { + std::cerr << last << " x" << count << "\n"; + count = 1; + last = d; + } + } + return true; +}(); + // uint8_t get_push_size(uint8_t x) //{ // return (x & 0b11111); From f2ea730a4665c8228cc86fead840899d084c940c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 19 Apr 2021 10:08:42 +0200 Subject: [PATCH 15/74] SIMD1 analysis prototype --- test/experimental/jumpdest_analysis.cpp | 33 +++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 4 ++- test/internal_benchmarks/analysis_bench.cpp | 2 ++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 90f26665f0..6f24c2162c 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -42,6 +42,39 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) return m; } +std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) +{ + std::vector push_map; + push_map.resize(code_size); + + std::vector jumpdest_map; + jumpdest_map.resize(code_size + 33); + + for (size_t i = 0; i < code_size; ++i) + { + const auto c = code[i]; + if (is_push(c)) + push_map[i] = static_cast(get_push_data_size(c)); + + if (c == OP_JUMPDEST) + jumpdest_map[i] = true; + } + + for (size_t i = 0; i < code_size; ++i) + { + const auto p = push_map[i]; + if (p > 0) + { + for (size_t j = i + 1; j <= i + p; ++j) + jumpdest_map[j] = false; + i += p; + } + } + + jumpdest_map.resize(code_size); + return jumpdest_map; +} + static constexpr size_t padding = 33; std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size) diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 8883637f9e..cb5ccc6716 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -20,6 +20,7 @@ inline bool is_jumpdest(const uint8_t* code, size_t code_size, size_t index) noe } std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 28ba1f9aa7..131dc40167 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -16,7 +16,7 @@ template inline void expect_eq(T1 a, T2 b) noexcept { if (a != b) - __builtin_trap(); + __builtin_unreachable(); } constexpr auto tail_code_padding = 100; @@ -43,6 +43,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a6 = build_internal_code_v3(data, data_size); const auto ic4 = build_internal_code_v4(data, data_size); const auto ic8 = build_internal_code_v8(data, data_size); + const auto s1 = build_jumpdest_map_simd1(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { @@ -55,6 +56,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a6.get(), data_size, i), expected); expect_eq(is_jumpdest(ic4.get(), data_size, i), expected); expect_eq(is_jumpdest(ic8.get(), data_size, i), expected); + expect_eq(is_jumpdest(s1, i), expected); } diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index f5a9a87505..07b5781804 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -427,6 +427,8 @@ BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); From 458c80126dea090f2bf802b6f9d920382d6b0818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 13:55:32 +0200 Subject: [PATCH 16/74] "vectorize" by 32 --- test/experimental/jumpdest_analysis.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 6f24c2162c..fe263cea8c 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -44,13 +44,31 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) { + constexpr auto v_size = 32; + std::vector push_map; push_map.resize(code_size); std::vector jumpdest_map; jumpdest_map.resize(code_size + 33); - for (size_t i = 0; i < code_size; ++i) + const auto v_code_size = code_size / v_size; + + for (size_t v = 0; v < v_code_size; ++v) + { + const auto v_begin = v * v_size; + for (size_t j = v_begin; j < v_begin + v_size; ++j) + { + const auto c = code[j]; + if (is_push(c)) + push_map[j] = static_cast(get_push_data_size(c)); + + if (c == OP_JUMPDEST) + jumpdest_map[j] = true; + } + } + + for (size_t i = v_code_size; i < code_size; ++i) { const auto c = code[i]; if (is_push(c)) From 46e09bb36c12519b3b9fad50187994dde6d86ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 14:04:22 +0200 Subject: [PATCH 17/74] Use bitset --- test/experimental/jumpdest_analysis.cpp | 13 ++++++------- test/experimental/jumpdest_analysis.hpp | 2 +- test/internal_benchmarks/analysis_bench.cpp | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index fe263cea8c..c6463baabb 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -42,15 +42,14 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) return m; } -std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) +bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) { constexpr auto v_size = 32; std::vector push_map; push_map.resize(code_size); - std::vector jumpdest_map; - jumpdest_map.resize(code_size + 33); + bitset jumpdest_map(code_size + 33); const auto v_code_size = code_size / v_size; @@ -64,7 +63,7 @@ std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size push_map[j] = static_cast(get_push_data_size(c)); if (c == OP_JUMPDEST) - jumpdest_map[j] = true; + jumpdest_map.set(j); } } @@ -75,7 +74,7 @@ std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size push_map[i] = static_cast(get_push_data_size(c)); if (c == OP_JUMPDEST) - jumpdest_map[i] = true; + jumpdest_map.set(i); } for (size_t i = 0; i < code_size; ++i) @@ -84,12 +83,12 @@ std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size if (p > 0) { for (size_t j = i + 1; j <= i + p; ++j) - jumpdest_map[j] = false; + jumpdest_map.unset(j); i += p; } } - jumpdest_map.resize(code_size); + jumpdest_map.set_size(code_size); return jumpdest_map; } diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index cb5ccc6716..2eb5e41820 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -20,7 +20,7 @@ inline bool is_jumpdest(const uint8_t* code, size_t code_size, size_t index) noe } std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); -std::vector build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); +bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 07b5781804..11b73f27ed 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -427,8 +427,7 @@ BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); -BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_simd1); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); From 8624d1cb830dae6e9e49a1dcc3244e65451aa84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 15:01:47 +0200 Subject: [PATCH 18/74] Use AVX2 to find JUMPDESTs --- test/experimental/jumpdest_analysis.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index c6463baabb..d636883bed 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace evmone::experimental { inline constexpr size_t get_push_data_size(uint8_t op) noexcept @@ -56,14 +58,24 @@ bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) for (size_t v = 0; v < v_code_size; ++v) { const auto v_begin = v * v_size; + const auto* p = &code[v_begin]; + + const auto v1 = _mm256_loadu_si256((const __m256i*)p); + const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); + const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); + const auto mask = _mm256_movemask_epi8(v_eq); + + for (size_t i = 0; i < 32; ++i) + { + if ((mask >> i) & 1) + jumpdest_map.set(v_begin + i); + } + for (size_t j = v_begin; j < v_begin + v_size; ++j) { const auto c = code[j]; if (is_push(c)) push_map[j] = static_cast(get_push_data_size(c)); - - if (c == OP_JUMPDEST) - jumpdest_map.set(j); } } From c9186a37813607cffaff3b5c49c6b481af8cee0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 15:10:05 +0200 Subject: [PATCH 19/74] Fixup tail --- test/experimental/jumpdest_analysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index d636883bed..f733b7bb43 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -79,7 +79,7 @@ bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) } } - for (size_t i = v_code_size; i < code_size; ++i) + for (size_t i = v_code_size * v_size; i < code_size; ++i) { const auto c = code[i]; if (is_push(c)) From 0022e20b3b4969c6880a1599372814bc96836ea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 15:15:06 +0200 Subject: [PATCH 20/74] Use bitset32 --- test/experimental/jumpdest_analysis.cpp | 21 ++++++------- test/experimental/jumpdest_analysis.hpp | 34 ++++++++++++++++++++- test/fuzzer/jumpdest_analysis_fuzz.cpp | 5 +++ test/internal_benchmarks/analysis_bench.cpp | 3 +- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index f733b7bb43..e96d07427d 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -44,14 +44,14 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) return m; } -bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) +bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) { constexpr auto v_size = 32; std::vector push_map; push_map.resize(code_size); - bitset jumpdest_map(code_size + 33); + bitset32 jumpdest_map(code_size); const auto v_code_size = code_size / v_size; @@ -63,13 +63,9 @@ bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) const auto v1 = _mm256_loadu_si256((const __m256i*)p); const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); - const auto mask = _mm256_movemask_epi8(v_eq); + const auto mask = static_cast(_mm256_movemask_epi8(v_eq)); - for (size_t i = 0; i < 32; ++i) - { - if ((mask >> i) & 1) - jumpdest_map.set(v_begin + i); - } + jumpdest_map.words_[v] = mask; for (size_t j = v_begin; j < v_begin + v_size; ++j) { @@ -79,15 +75,17 @@ bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) } } + uint32_t w = 0; for (size_t i = v_code_size * v_size; i < code_size; ++i) { const auto c = code[i]; + if (c == OP_JUMPDEST) + w |= (1u << (i - v_code_size * v_size)); + if (is_push(c)) push_map[i] = static_cast(get_push_data_size(c)); - - if (c == OP_JUMPDEST) - jumpdest_map.set(i); } + jumpdest_map.words_[v_code_size] = w; for (size_t i = 0; i < code_size; ++i) { @@ -100,7 +98,6 @@ bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) } } - jumpdest_map.set_size(code_size); return jumpdest_map; } diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 2eb5e41820..35bc2df497 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -19,8 +19,40 @@ inline bool is_jumpdest(const uint8_t* code, size_t code_size, size_t index) noe return (index < code_size && code[index] == 0x5b); } +class bitset32 +{ +public: + static constexpr auto bpw = 32; + using word_type = uint32_t; + std::unique_ptr words_; + std::size_t size_; + + + explicit bitset32(std::size_t size) + : words_{new word_type[(size + 33 + (bpw - 1)) / bpw]}, size_{size} + {} + + std::size_t size() const noexcept { return size_; } + + bool operator[](std::size_t index) const noexcept + { + const auto w = index / bpw; + const auto x = index % bpw; + const auto bitmask = word_type{1} << x; + return (words_[w] & bitmask) != 0; + } + + void unset(std::size_t index) noexcept + { + const auto w = index / bpw; + const auto x = index % bpw; + const auto bitmask = word_type(~(word_type{1} << x)); + words_[w] &= bitmask; + } +}; + std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); -bitset build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); +bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 131dc40167..6dfd08cedf 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -26,6 +26,11 @@ inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept return (index < a.size() && a[index]); } +inline bool is_jumpdest(const bitset32& a, size_t index) noexcept +{ + return (index < a.size() && a[index]); +} + [[maybe_unused]] inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept { return find_jumpdest(a, static_cast(index)) >= 0; diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 11b73f27ed..1507ea8bbb 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -427,7 +427,8 @@ BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); -BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::experimental::build_jumpdest_map_simd1); +BENCHMARK_TEMPLATE( + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); From 8b284518cc572e8ee71c4cba4e4eafaa836d561d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 15:26:54 +0200 Subject: [PATCH 21/74] Clear pushdata by words --- test/experimental/jumpdest_analysis.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index e96d07427d..ab6f752f25 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -92,8 +92,18 @@ bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) const auto p = push_map[i]; if (p > 0) { - for (size_t j = i + 1; j <= i + p; ++j) - jumpdest_map.unset(j); + const auto s = i + 1; + const auto v = s / 32; + const auto u = s % 32; + uint64_t dw = (uint64_t{jumpdest_map.words_[v + 1]} << 32) | jumpdest_map.words_[v]; + + uint64_t mask = ~uint64_t{0}; + mask >>= (64 - p); + mask <<= u; + dw &= ~mask; + + jumpdest_map.words_[v] = static_cast(dw); + jumpdest_map.words_[v + 1] = static_cast(dw >> 32); i += p; } } From 1cc2537b036a28468442e6c7a8f861d43eac48c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 15:33:50 +0200 Subject: [PATCH 22/74] Duplicate SIMD1 -> SIMD2 --- test/experimental/jumpdest_analysis.cpp | 68 +++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 + test/internal_benchmarks/analysis_bench.cpp | 2 + 4 files changed, 73 insertions(+) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index ab6f752f25..95c3dcdae4 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -111,6 +111,74 @@ bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) return jumpdest_map; } + +bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) +{ + constexpr auto v_size = 32; + + std::vector push_map; + push_map.resize(code_size); + + bitset32 jumpdest_map(code_size); + + const auto v_code_size = code_size / v_size; + + for (size_t v = 0; v < v_code_size; ++v) + { + const auto v_begin = v * v_size; + const auto* p = &code[v_begin]; + + const auto v1 = _mm256_loadu_si256((const __m256i*)p); + const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); + const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); + const auto mask = static_cast(_mm256_movemask_epi8(v_eq)); + + jumpdest_map.words_[v] = mask; + + for (size_t j = v_begin; j < v_begin + v_size; ++j) + { + const auto c = code[j]; + if (is_push(c)) + push_map[j] = static_cast(get_push_data_size(c)); + } + } + + uint32_t w = 0; + for (size_t i = v_code_size * v_size; i < code_size; ++i) + { + const auto c = code[i]; + if (c == OP_JUMPDEST) + w |= (1u << (i - v_code_size * v_size)); + + if (is_push(c)) + push_map[i] = static_cast(get_push_data_size(c)); + } + jumpdest_map.words_[v_code_size] = w; + + for (size_t i = 0; i < code_size; ++i) + { + const auto p = push_map[i]; + if (p > 0) + { + const auto s = i + 1; + const auto v = s / 32; + const auto u = s % 32; + uint64_t dw = (uint64_t{jumpdest_map.words_[v + 1]} << 32) | jumpdest_map.words_[v]; + + uint64_t mask = ~uint64_t{0}; + mask >>= (64 - p); + mask <<= u; + dw &= ~mask; + + jumpdest_map.words_[v] = static_cast(dw); + jumpdest_map.words_[v + 1] = static_cast(dw >> 32); + i += p; + } + } + + return jumpdest_map; +} + static constexpr size_t padding = 33; std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size) diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 35bc2df497..b635c6ccfb 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -53,6 +53,7 @@ class bitset32 std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); +bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 6dfd08cedf..3d267110f9 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -49,6 +49,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto ic4 = build_internal_code_v4(data, data_size); const auto ic8 = build_internal_code_v8(data, data_size); const auto s1 = build_jumpdest_map_simd1(data, data_size); + const auto s2 = build_jumpdest_map_simd2(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { @@ -62,6 +63,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(ic4.get(), data_size, i), expected); expect_eq(is_jumpdest(ic8.get(), data_size, i), expected); expect_eq(is_jumpdest(s1, i), expected); + expect_eq(is_jumpdest(s2, i), expected); } diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 1507ea8bbb..ffa1396d40 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -429,6 +429,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); +BENCHMARK_TEMPLATE( + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); From 8c37948853af699969193c3db03ced322ce7cfbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 20 Apr 2021 16:49:08 +0200 Subject: [PATCH 23/74] Change SIMD2 --- test/experimental/jumpdest_analysis.cpp | 70 +++++++++++------------ test/unittests/jumpdest_analysis_test.cpp | 12 +++- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 95c3dcdae4..ac1e1828a2 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -116,65 +116,63 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) { constexpr auto v_size = 32; - std::vector push_map; - push_map.resize(code_size); - bitset32 jumpdest_map(code_size); const auto v_code_size = code_size / v_size; + const auto v_tail_size = code_size % v_size; + uint32_t clear_next = 0; for (size_t v = 0; v < v_code_size; ++v) { const auto v_begin = v * v_size; - const auto* p = &code[v_begin]; + const auto* ptr = &code[v_begin]; - const auto v1 = _mm256_loadu_si256((const __m256i*)p); + const auto v1 = _mm256_loadu_si256((const __m256i*)ptr); const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); - const auto mask = static_cast(_mm256_movemask_epi8(v_eq)); + auto j_mask = static_cast(_mm256_movemask_epi8(v_eq)); - jumpdest_map.words_[v] = mask; - - for (size_t j = v_begin; j < v_begin + v_size; ++j) + uint64_t clear_mask = clear_next; + const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; + for (size_t j = skip; j < v_size; ++j) { - const auto c = code[j]; + const auto c = code[v_begin + j]; if (is_push(c)) - push_map[j] = static_cast(get_push_data_size(c)); + { + const auto p = get_push_data_size(c); + + uint64_t mask = ~uint64_t{0}; + mask >>= (64 - p); + mask <<= ((j + 1) % 64); + + clear_mask |= mask; + + j += p; + } } + + clear_next = static_cast(clear_mask >> 32); + + j_mask &= ~static_cast(clear_mask); + jumpdest_map.words_[v] = j_mask; } - uint32_t w = 0; - for (size_t i = v_code_size * v_size; i < code_size; ++i) + uint32_t j_mask = 0; + const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; + for (size_t j = skip; j < v_tail_size; ++j) { - const auto c = code[i]; + const auto base = code_size - v_tail_size; + const auto c = code[base + j]; if (c == OP_JUMPDEST) - w |= (1u << (i - v_code_size * v_size)); + j_mask |= (1u << j); if (is_push(c)) - push_map[i] = static_cast(get_push_data_size(c)); - } - jumpdest_map.words_[v_code_size] = w; - - for (size_t i = 0; i < code_size; ++i) - { - const auto p = push_map[i]; - if (p > 0) { - const auto s = i + 1; - const auto v = s / 32; - const auto u = s % 32; - uint64_t dw = (uint64_t{jumpdest_map.words_[v + 1]} << 32) | jumpdest_map.words_[v]; - - uint64_t mask = ~uint64_t{0}; - mask >>= (64 - p); - mask <<= u; - dw &= ~mask; - - jumpdest_map.words_[v] = static_cast(dw); - jumpdest_map.words_[v + 1] = static_cast(dw >> 32); - i += p; + const auto p = get_push_data_size(c); + j += p; } } + jumpdest_map.words_[v_code_size] = j_mask; return jumpdest_map; } diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index d66d632af7..07d5dc393c 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -20,6 +20,11 @@ inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept return (index < a.size() && a[index]); } +inline bool is_jumpdest(const bitset32& a, size_t index) noexcept +{ + return (index < a.size() && a[index]); +} + inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept { return find_jumpdest(a, static_cast(index)) >= 0; @@ -32,6 +37,7 @@ const bytecode bytecode_test_cases[]{ push(0), push(0x5b) + OP_JUMPDEST, push(0x60) + OP_JUMPDEST, + "5b00000000000000000000000000000000000000000000000000000000000060", }; } // namespace @@ -49,6 +55,8 @@ TEST(jumpdest_analysis, compare_implementations) const auto a6 = build_internal_code_v3(t.data(), t.size()); const auto ic4 = build_internal_code_v4(t.data(), t.size()); const auto ic8 = build_internal_code_v8(t.data(), t.size()); + const auto s1 = build_jumpdest_map_simd1(t.data(), t.size()); + const auto s2 = build_jumpdest_map_simd2(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { @@ -62,6 +70,8 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a6.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(ic4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(ic8.get(), t.size(), i), expected); + EXPECT_EQ(is_jumpdest(s1, i), expected); + EXPECT_EQ(is_jumpdest(s2, i), expected); } } -} \ No newline at end of file +} From 71e83c4eeae81daa319aff26743044b899f71093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Apr 2021 14:29:01 +0200 Subject: [PATCH 24/74] SIMD: use aligned load (unsafe) --- test/experimental/jumpdest_analysis.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index ac1e1828a2..f089097403 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -60,7 +60,7 @@ bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) const auto v_begin = v * v_size; const auto* p = &code[v_begin]; - const auto v1 = _mm256_loadu_si256((const __m256i*)p); + const auto v1 = _mm256_load_si256((const __m256i*)p); const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); const auto mask = static_cast(_mm256_movemask_epi8(v_eq)); @@ -127,7 +127,7 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) const auto v_begin = v * v_size; const auto* ptr = &code[v_begin]; - const auto v1 = _mm256_loadu_si256((const __m256i*)ptr); + const auto v1 = _mm256_load_si256((const __m256i*)ptr); const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); auto j_mask = static_cast(_mm256_movemask_epi8(v_eq)); From 5ac869df6702c4716165ec736a315ccf0729e1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Apr 2021 15:25:29 +0200 Subject: [PATCH 25/74] SIMD2: Alternative push find --- test/experimental/jumpdest_analysis.cpp | 46 +++++++++++++++++++------ test/experimental/opcode_manip.hpp | 3 +- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index f089097403..5338a943c1 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -60,7 +60,7 @@ bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) const auto v_begin = v * v_size; const auto* p = &code[v_begin]; - const auto v1 = _mm256_load_si256((const __m256i*)p); + const auto v1 = _mm256_loadu_si256((const __m256i*)p); const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); const auto mask = static_cast(_mm256_movemask_epi8(v_eq)); @@ -121,25 +121,29 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) const auto v_code_size = code_size / v_size; const auto v_tail_size = code_size % v_size; + const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); + const auto v_push_mask = _mm256_set1_epi8(static_cast(0xe0)); + const auto v_push_pattern = _mm256_set1_epi8(0x60); uint32_t clear_next = 0; for (size_t v = 0; v < v_code_size; ++v) { const auto v_begin = v * v_size; const auto* ptr = &code[v_begin]; - const auto v1 = _mm256_load_si256((const __m256i*)ptr); - const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); - const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); + const auto v_code = _mm256_loadu_si256((const __m256i*)ptr); + const auto v_eq = _mm256_cmpeq_epi8(v_code, v_jmpd); auto j_mask = static_cast(_mm256_movemask_epi8(v_eq)); + const auto v_push_locs = _mm256_cmpeq_epi8(_mm256_and_si256(v_code, v_push_mask), v_push_pattern); + auto push_locs = static_cast(_mm256_movemask_epi8(v_push_locs)); + + push_locs &= ~clear_next; uint64_t clear_mask = clear_next; - const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; - for (size_t j = skip; j < v_size; ++j) + + for (size_t j = 0; j < 32; ++j) { - const auto c = code[v_begin + j]; - if (is_push(c)) - { - const auto p = get_push_data_size(c); + if ((push_locs >> j) & 1) { + const auto p = get_push_data_size(code[v_begin + j]); uint64_t mask = ~uint64_t{0}; mask >>= (64 - p); @@ -151,6 +155,28 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) } } + // const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; + // for (size_t j = skip; j < v_size; ++j) + // { + // const auto c = code[v_begin + j]; + // + // if (((push_locs >> j) & 1) != is_push(c)) + // __builtin_trap(); + // + // if (is_push(c)) + // { + // const auto p = get_push_data_size(c); + // + // uint64_t mask = ~uint64_t{0}; + // mask >>= (64 - p); + // mask <<= ((j + 1) % 64); + // + // clear_mask |= mask; + // + // j += p; + // } + // } + clear_next = static_cast(clear_mask >> 32); j_mask &= ~static_cast(clear_mask); diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp index 10859ad890..e7e8f51450 100644 --- a/test/experimental/opcode_manip.hpp +++ b/test/experimental/opcode_manip.hpp @@ -8,7 +8,8 @@ namespace evmone::experimental { inline constexpr bool is_push(uint8_t op) noexcept { - return (op >> 5) == 0b11; + return (op & 0xe0) == 0x60; + // TODO: check what is better. return (op >> 5) == 0b11; } inline constexpr int find_first_push(const uint8_t* code) noexcept From 89ae8ea87d83ee126b4ced08c37417803199d0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Apr 2021 15:45:04 +0200 Subject: [PATCH 26/74] SIMD2: Alternative push find --- test/experimental/jumpdest_analysis.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 5338a943c1..2350e0e248 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -134,25 +134,24 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) const auto v_eq = _mm256_cmpeq_epi8(v_code, v_jmpd); auto j_mask = static_cast(_mm256_movemask_epi8(v_eq)); - const auto v_push_locs = _mm256_cmpeq_epi8(_mm256_and_si256(v_code, v_push_mask), v_push_pattern); + const auto v_push_locs = + _mm256_cmpeq_epi8(_mm256_and_si256(v_code, v_push_mask), v_push_pattern); auto push_locs = static_cast(_mm256_movemask_epi8(v_push_locs)); push_locs &= ~clear_next; uint64_t clear_mask = clear_next; - for (size_t j = 0; j < 32; ++j) + while (push_locs) { - if ((push_locs >> j) & 1) { - const auto p = get_push_data_size(code[v_begin + j]); + const size_t j = static_cast(__builtin_ctz(push_locs)); + const auto p = get_push_data_size(code[v_begin + j]); - uint64_t mask = ~uint64_t{0}; - mask >>= (64 - p); - mask <<= ((j + 1) % 64); - - clear_mask |= mask; + uint64_t mask = ~uint64_t{0}; + mask >>= (64 - (p + 1)); + mask <<= j; - j += p; - } + clear_mask |= mask; + push_locs &= ~clear_mask; } // const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; From d50a1a1553b11ab8d665b557f6a4db2ed5004660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Apr 2021 15:51:41 +0200 Subject: [PATCH 27/74] Move to SIMD3 --- test/experimental/jumpdest_analysis.cpp | 88 +++++++++++++++++------ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 + test/unittests/jumpdest_analysis_test.cpp | 1 + 4 files changed, 69 insertions(+), 23 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 2350e0e248..c483fc00e7 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -111,7 +111,6 @@ bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size) return jumpdest_map; } - bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) { constexpr auto v_size = 32; @@ -121,6 +120,71 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) const auto v_code_size = code_size / v_size; const auto v_tail_size = code_size % v_size; + uint32_t clear_next = 0; + for (size_t v = 0; v < v_code_size; ++v) + { + const auto v_begin = v * v_size; + const auto* ptr = &code[v_begin]; + + const auto v1 = _mm256_loadu_si256((const __m256i*)ptr); + const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); + const auto v_eq = _mm256_cmpeq_epi8(v1, v_jmpd); + auto j_mask = static_cast(_mm256_movemask_epi8(v_eq)); + + uint64_t clear_mask = clear_next; + const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; + for (size_t j = skip; j < v_size; ++j) + { + const auto c = code[v_begin + j]; + if (is_push(c)) + { + const auto p = get_push_data_size(c); + + uint64_t mask = ~uint64_t{0}; + mask >>= (64 - p); + mask <<= ((j + 1) % 64); + + clear_mask |= mask; + + j += p; + } + } + + clear_next = static_cast(clear_mask >> 32); + + j_mask &= ~static_cast(clear_mask); + jumpdest_map.words_[v] = j_mask; + } + + uint32_t j_mask = 0; + const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; + for (size_t j = skip; j < v_tail_size; ++j) + { + const auto base = code_size - v_tail_size; + const auto c = code[base + j]; + if (c == OP_JUMPDEST) + j_mask |= (1u << j); + + if (is_push(c)) + { + const auto p = get_push_data_size(c); + j += p; + } + } + jumpdest_map.words_[v_code_size] = j_mask; + + return jumpdest_map; +} + +bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size) +{ + constexpr auto v_size = 32; + + bitset32 jumpdest_map(code_size); + + const auto v_code_size = code_size / v_size; + const auto v_tail_size = code_size % v_size; + const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); const auto v_push_mask = _mm256_set1_epi8(static_cast(0xe0)); const auto v_push_pattern = _mm256_set1_epi8(0x60); @@ -154,28 +218,6 @@ bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size) push_locs &= ~clear_mask; } - // const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; - // for (size_t j = skip; j < v_size; ++j) - // { - // const auto c = code[v_begin + j]; - // - // if (((push_locs >> j) & 1) != is_push(c)) - // __builtin_trap(); - // - // if (is_push(c)) - // { - // const auto p = get_push_data_size(c); - // - // uint64_t mask = ~uint64_t{0}; - // mask >>= (64 - p); - // mask <<= ((j + 1) % 64); - // - // clear_mask |= mask; - // - // j += p; - // } - // } - clear_next = static_cast(clear_mask >> 32); j_mask &= ~static_cast(clear_mask); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index b635c6ccfb..6e497f3754 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -54,6 +54,7 @@ class bitset32 std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); +bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 3d267110f9..1a4adc6463 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -50,6 +50,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto ic8 = build_internal_code_v8(data, data_size); const auto s1 = build_jumpdest_map_simd1(data, data_size); const auto s2 = build_jumpdest_map_simd2(data, data_size); + const auto s3 = build_jumpdest_map_simd3(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { @@ -64,6 +65,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(ic8.get(), data_size, i), expected); expect_eq(is_jumpdest(s1, i), expected); expect_eq(is_jumpdest(s2, i), expected); + expect_eq(is_jumpdest(s3, i), expected); } diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 07d5dc393c..5082687905 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -57,6 +57,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto ic8 = build_internal_code_v8(t.data(), t.size()); const auto s1 = build_jumpdest_map_simd1(t.data(), t.size()); const auto s2 = build_jumpdest_map_simd2(t.data(), t.size()); + const auto s3 = build_jumpdest_map_simd3(t.data(), t.size()); for (size_t i = 0; i < t.size() + tail_code_padding; ++i) { From c61a7fbdce289086374a47ab33ae8213bc618fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Apr 2021 19:12:45 +0200 Subject: [PATCH 28/74] Change is_push --- test/internal_benchmarks/analysis_bench.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index ffa1396d40..20ae226b29 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -178,9 +178,8 @@ enum : uint8_t inline bool is_push(uint8_t op) { // return op >= OP_PUSH1 && op <= OP_PUSH32; - return (op >> 5) == 0b11; - // return (op & uint8_t{0b11100000}) == 0b01100000; - // return (x & 0b1100000) != 0; + // return (op >> 5) == 0b11; + return (op & uint8_t{0b11100000}) == 0b01100000; } [[maybe_unused]] bool x = []() noexcept { From 50501caf3f545aa186240d671031cae1a112c976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Apr 2021 19:16:02 +0200 Subject: [PATCH 29/74] JUMPDEST unlikely --- test/experimental/jumpdest_analysis.cpp | 6 +++--- test/internal_benchmarks/analysis_bench.cpp | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index c483fc00e7..2379ecdd31 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -22,7 +22,7 @@ std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; else if (is_push(op)) i += get_push_data_size(op); @@ -36,7 +36,7 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m.set(i); else if (is_push(op)) i += get_push_data_size(op); @@ -270,7 +270,7 @@ std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t co long push_data = 0; for (size_t i = 0; i < code_size; ++i) { - if (push_data != 0) [[unlikely]] + if (push_data != 0) { --push_data; m[i] = 0; diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 20ae226b29..7b977fe5db 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -167,7 +167,7 @@ enum : uint8_t for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; else if (op >= OP_PUSH1 && op <= OP_PUSH32) i += static_cast(op - OP_PUSH1 + 1); @@ -232,7 +232,7 @@ inline bool is_push(uint8_t op) for (size_t i = 0; i < code_size;) { const auto op = code[i]; - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; i += is_push(op) ? static_cast(op - OP_PUSH1 + 2) : 1; @@ -248,7 +248,7 @@ inline bool is_push(uint8_t op) for (; code < code_end; ++code) { const auto op = *code; - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[size_t(code - code_beg)] = true; else if (is_push(op)) code += static_cast(op - OP_PUSH1 + 1); @@ -263,7 +263,7 @@ inline bool is_push(uint8_t op) { const auto op = code[i]; const auto s = size_t(op - OP_PUSH1); - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; else if (s <= 31) i += s + 1; @@ -278,7 +278,7 @@ inline bool is_push(uint8_t op) { const auto op = code[i]; const auto s = size_t(op - OP_PUSH1); - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; i += (s <= 31) ? s + 1 : 1; @@ -293,7 +293,7 @@ inline bool is_push(uint8_t op) { const auto op = code[i]; const auto s = size_t(op - OP_PUSH1); - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; const auto a = (s <= 31) ? s : 0; @@ -309,7 +309,7 @@ inline bool is_push(uint8_t op) for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; - if (op == OP_JUMPDEST) + if (__builtin_expect(op == OP_JUMPDEST, false)) m[i] = true; else if (op >= OP_PUSH1 && op <= OP_PUSH32) i += static_cast(op - OP_PUSH1 + 1); From 15533766f8394d8f5abdb48a1602631f5c3063dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 22 Apr 2021 07:42:05 +0200 Subject: [PATCH 30/74] Add new vec version --- test/experimental/jumpdest_analysis.cpp | 15 +++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 ++ test/internal_benchmarks/analysis_bench.cpp | 2 ++ 4 files changed, 20 insertions(+) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 2379ecdd31..da8ff27598 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -30,6 +30,21 @@ std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) return m; } +std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) { JumpdestMap m(code_size); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 6e497f3754..f2cdd71f01 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -52,6 +52,7 @@ class bitset32 }; std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 1a4adc6463..224b8d44d4 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -42,6 +42,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a0 = build_jumpdest_map(data, data_size); const auto a1 = analyze(EVMC_FRONTIER, data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); + const auto v2 = build_jumpdest_map_vec2(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); @@ -57,6 +58,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const bool expected = is_jumpdest(a0, i); expect_eq(is_jumpdest(a1, i), expected); expect_eq(is_jumpdest(a2, i), expected); + expect_eq(is_jumpdest(v2, i), expected); expect_eq(is_jumpdest(a3, i), expected); expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 7b977fe5db..711092efac 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -426,6 +426,8 @@ BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE( From 9a0f8efb181de55fa5ec977c5588681ce48e0dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 26 Apr 2021 19:25:36 +0200 Subject: [PATCH 31/74] First version of STTNI version --- test/experimental/CMakeLists.txt | 1 + test/experimental/jumpdest_analysis.cpp | 51 ++++++++++++++++++++- test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 + test/internal_benchmarks/analysis_bench.cpp | 2 + test/unittests/jumpdest_analysis_test.cpp | 8 +++- 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt index 0fb08bc843..0dae07fb1b 100644 --- a/test/experimental/CMakeLists.txt +++ b/test/experimental/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(evmone::experimental ALIAS evmone-experimental) target_include_directories(evmone-experimental PUBLIC ${PROJECT_SOURCE_DIR} ${evmone_private_include_dir}) target_link_libraries(evmone-experimental PRIVATE evmone evmc::instructions) +target_compile_options(evmone-experimental PUBLIC -mavx -mavx2 -msse4) target_sources( evmone-experimental PRIVATE jumpdest_analysis.cpp diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index da8ff27598..5992c847dd 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -45,6 +45,55 @@ std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) return m; } +std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + + __m128i match_ranges{}; + match_ranges = _mm_insert_epi8(match_ranges, OP_PUSH1, 0); + match_ranges = _mm_insert_epi8(match_ranges, OP_PUSH32, 1); + match_ranges = _mm_insert_epi8(match_ranges, OP_JUMPDEST, 2); + match_ranges = _mm_insert_epi8(match_ranges, OP_JUMPDEST, 3); + + const auto match_imm = _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES; + + + size_t v_code_size = code_size >= 16 ? code_size - 15 : 0; + size_t i = 0; + for (; i < v_code_size;) + { + const auto data = _mm_loadu_si128((const __m128i*)&code[i]); + const auto first_match = (unsigned)_mm_cmpestri(match_ranges, 4, data, 16, match_imm); + + if (first_match == 16) + { + i += first_match; + continue; + } + + i += first_match; + + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (__builtin_expect(potential_push_data_len <= 32, true)) + i += potential_push_data_len; + else + m[i] = true; + ++i; + } + + for (; i < code_size; ++i) + { + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) { JumpdestMap m(code_size); @@ -230,7 +279,7 @@ bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size) mask <<= j; clear_mask |= mask; - push_locs &= ~clear_mask; + push_locs &= static_cast(~clear_mask); } clear_next = static_cast(clear_mask >> 32); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index f2cdd71f01..1f3f82b620 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -53,6 +53,7 @@ class bitset32 std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 224b8d44d4..c022b37bdb 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -43,6 +43,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a1 = analyze(EVMC_FRONTIER, data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); + const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); @@ -59,6 +60,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a1, i), expected); expect_eq(is_jumpdest(a2, i), expected); expect_eq(is_jumpdest(v2, i), expected); + expect_eq(is_jumpdest(v3, i), expected); expect_eq(is_jumpdest(a3, i), expected); expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 711092efac..943b4f3d49 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -428,6 +428,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 5082687905..6e4e4a3eed 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -37,7 +37,9 @@ const bytecode bytecode_test_cases[]{ push(0), push(0x5b) + OP_JUMPDEST, push(0x60) + OP_JUMPDEST, - "5b00000000000000000000000000000000000000000000000000000000000060", + "5b000000000000000000000000000000", + "005b0000000000000000000000000000", + // "5b00000000000000000000000000000000000000000000000000000000000060", }; } // namespace @@ -49,6 +51,8 @@ TEST(jumpdest_analysis, compare_implementations) const auto a0 = build_jumpdest_map(t.data(), t.size()); const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); + const auto v2 = build_jumpdest_map_vec2(t.data(), t.size()); + const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); @@ -65,6 +69,8 @@ TEST(jumpdest_analysis, compare_implementations) const bool expected = is_jumpdest(a0, i); EXPECT_EQ(is_jumpdest(a1, i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); + EXPECT_EQ(is_jumpdest(v2, i), expected); + EXPECT_EQ(is_jumpdest(v3, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); From 08d9cbc656899f4104f1891390b81cc12268d5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Apr 2021 15:02:39 +0200 Subject: [PATCH 32/74] Add new str_avx2 impl --- test/experimental/jumpdest_analysis.cpp | 48 +++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 + test/internal_benchmarks/analysis_bench.cpp | 2 + test/unittests/jumpdest_analysis_test.cpp | 2 + 5 files changed, 55 insertions(+) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 5992c847dd..60bb5f89d9 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -94,6 +94,54 @@ std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size return m; } +std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + + const auto all_jumpdest = _mm256_set1_epi8(OP_JUMPDEST); + const auto all_push1 = _mm256_set1_epi8(OP_PUSH1 - 1); + + size_t v_code_size = code_size >= 32 ? code_size - 31 : 0; + size_t i = 0; + for (; i < v_code_size;) + { + const auto data = _mm256_loadu_si256((const __m256i*)&code[i]); + const auto is_push = _mm256_cmpgt_epi8(data, all_push1); + const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); + const auto is_interesting = _mm256_or_si256(is_push, is_jumpdest); + const auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); + const auto first_match = mask ? (unsigned)__builtin_ctz(mask) : 16; + + if (first_match == 16) + { + i += first_match; + continue; + } + + i += first_match; + + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (__builtin_expect(potential_push_data_len <= 32, true)) + i += potential_push_data_len; + else + m[i] = true; + ++i; + } + + for (; i < code_size; ++i) + { + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + + JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) { JumpdestMap m(code_size); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 1f3f82b620..cfaa288560 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -54,6 +54,7 @@ class bitset32 std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index c022b37bdb..476627559b 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -44,6 +44,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); const auto v3 = build_jumpdest_map_sttni(data, data_size); + const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); @@ -61,6 +62,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a2, i), expected); expect_eq(is_jumpdest(v2, i), expected); expect_eq(is_jumpdest(v3, i), expected); + expect_eq(is_jumpdest(v4, i), expected); expect_eq(is_jumpdest(a3, i), expected); expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 943b4f3d49..6d4f9dace4 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -430,6 +430,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 6e4e4a3eed..6d8ff0404a 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -53,6 +53,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); const auto v2 = build_jumpdest_map_vec2(t.data(), t.size()); const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); + const auto v4 = build_jumpdest_map_str_avx2(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); @@ -71,6 +72,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); EXPECT_EQ(is_jumpdest(v3, i), expected); + EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); From 31e2fcadcdc9b3d217de7ce62a9e685200911f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Apr 2021 15:30:41 +0200 Subject: [PATCH 33/74] Add new by byte optimized impl --- test/experimental/jumpdest_analysis.cpp | 20 +++++++++++++++++--- test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 ++ test/internal_benchmarks/analysis_bench.cpp | 2 ++ test/unittests/jumpdest_analysis_test.cpp | 2 ++ 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 60bb5f89d9..27faf5802b 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -22,10 +22,10 @@ std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; - if (__builtin_expect(op == OP_JUMPDEST, false)) - m[i] = true; - else if (is_push(op)) + if (is_push(op)) i += get_push_data_size(op); + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; } return m; } @@ -45,6 +45,20 @@ std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) return m; } +std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (static_cast(op) >= static_cast(OP_PUSH1)) + i += get_push_data_size(op); + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size) { std::vector m(code_size); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index cfaa288560..8da6ba95cb 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -53,6 +53,7 @@ class bitset32 std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 476627559b..ea49f35686 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -43,6 +43,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a1 = analyze(EVMC_FRONTIER, data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); + const auto x3 = build_jumpdest_map_vec3(data, data_size); const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); @@ -61,6 +62,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(a1, i), expected); expect_eq(is_jumpdest(a2, i), expected); expect_eq(is_jumpdest(v2, i), expected); + expect_eq(is_jumpdest(x3, i), expected); expect_eq(is_jumpdest(v3, i), expected); expect_eq(is_jumpdest(v4, i), expected); expect_eq(is_jumpdest(a3, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 6d4f9dace4..25953258d2 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -428,6 +428,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec3); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 6d8ff0404a..8efad036b4 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -52,6 +52,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); const auto v2 = build_jumpdest_map_vec2(t.data(), t.size()); + const auto x3 = build_jumpdest_map_vec3(t.data(), t.size()); const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); const auto v4 = build_jumpdest_map_str_avx2(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); @@ -71,6 +72,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a1, i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); + EXPECT_EQ(is_jumpdest(x3, i), expected); EXPECT_EQ(is_jumpdest(v3, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); From 05d3127fdb619f50f0b8dd2aa6c9074deb075913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Apr 2021 21:15:31 +0200 Subject: [PATCH 34/74] Improve str implementation --- test/experimental/jumpdest_analysis.cpp | 42 +++++++++---------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 27faf5802b..e88a5f1098 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -79,21 +79,15 @@ std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size const auto data = _mm_loadu_si128((const __m128i*)&code[i]); const auto first_match = (unsigned)_mm_cmpestri(match_ranges, 4, data, 16, match_imm); - if (first_match == 16) + i += first_match; + if (first_match < 16) { - i += first_match; - continue; + const auto op = code[i]; + if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) + i += get_push_data_size(op) + 1; + else + m[i++] = true; } - - i += first_match; - - const auto op = code[i]; - const auto potential_push_data_len = get_push_data_size(op); - if (__builtin_expect(potential_push_data_len <= 32, true)) - i += potential_push_data_len; - else - m[i] = true; - ++i; } for (; i < code_size; ++i) @@ -124,23 +118,17 @@ std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_s const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); const auto is_interesting = _mm256_or_si256(is_push, is_jumpdest); const auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); - const auto first_match = mask ? (unsigned)__builtin_ctz(mask) : 16; + const auto first_match = mask ? (unsigned)__builtin_ctz(mask) : 32; - if (first_match == 16) + i += first_match; + if (mask) { - i += first_match; - continue; + const auto op = code[i]; + if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) + i += get_push_data_size(op) + 1; + else + m[i++] = true; } - - i += first_match; - - const auto op = code[i]; - const auto potential_push_data_len = get_push_data_size(op); - if (__builtin_expect(potential_push_data_len <= 32, true)) - i += potential_push_data_len; - else - m[i] = true; - ++i; } for (; i < code_size; ++i) From e94c20253769ec6599028a31492112441e87ded8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Apr 2021 22:00:19 +0200 Subject: [PATCH 35/74] New impl: process whole mask (32 bits) --- test/experimental/jumpdest_analysis.cpp | 65 +++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 + test/internal_benchmarks/analysis_bench.cpp | 2 + test/unittests/jumpdest_analysis_test.cpp | 4 +- 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index e88a5f1098..dd590f5660 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -143,6 +143,71 @@ std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_s return m; } +std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + + const auto all_jumpdest = _mm256_set1_epi8(OP_JUMPDEST); + const auto all_push1 = _mm256_set1_epi8(OP_PUSH1 - 1); + + size_t v_code_size = code_size >= 32 ? code_size - 31 : 0; + size_t i = 0; + for (; i < v_code_size;) + { + const auto data = _mm256_loadu_si256((const __m256i*)&code[i]); + const auto is_push = _mm256_cmpgt_epi8(data, all_push1); + const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); + const auto is_interesting = _mm256_or_si256(is_push, is_jumpdest); + const auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); + + if (!mask) + { + i += 32; + continue; + } + + unsigned pos = 0; + auto mask_left = mask; + while (true) + { + pos += (unsigned)__builtin_ctz(mask_left); + const auto op = code[i + pos]; + if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) + { + pos += unsigned(get_push_data_size(op) + 1); + } + else + { + m[i + pos] = true; + pos += 1; + } + + if (pos >= 32) + break; + + mask_left = mask >> pos; + if (!mask_left) + { + pos = 32; + break; + } + } + + i += pos; + } + + for (; i < code_size; ++i) + { + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) { diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 8da6ba95cb..9ce1be69cd 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -56,6 +56,7 @@ std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index ea49f35686..27c73a4746 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -46,6 +46,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto x3 = build_jumpdest_map_vec3(data, data_size); const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); + const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); @@ -65,6 +66,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(x3, i), expected); expect_eq(is_jumpdest(v3, i), expected); expect_eq(is_jumpdest(v4, i), expected); + expect_eq(is_jumpdest(v5, i), expected); expect_eq(is_jumpdest(a3, i), expected); expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 25953258d2..79ae3c65e8 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -434,6 +434,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 8efad036b4..ad43a60522 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -39,7 +39,7 @@ const bytecode bytecode_test_cases[]{ push(0x60) + OP_JUMPDEST, "5b000000000000000000000000000000", "005b0000000000000000000000000000", - // "5b00000000000000000000000000000000000000000000000000000000000060", + "5b00000000000000000000000000000000000000000000000000000000000060", }; } // namespace @@ -55,6 +55,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto x3 = build_jumpdest_map_vec3(t.data(), t.size()); const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); const auto v4 = build_jumpdest_map_str_avx2(t.data(), t.size()); + const auto v5 = build_jumpdest_map_str_avx2_mask(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); @@ -75,6 +76,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(x3, i), expected); EXPECT_EQ(is_jumpdest(v3, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); + EXPECT_EQ(is_jumpdest(v5, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); From 234cfbf10a3e5f6a1c855d8e114a0ec36f6327a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Apr 2021 23:02:10 +0200 Subject: [PATCH 36/74] ver 2 --- test/experimental/jumpdest_analysis.cpp | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index dd590f5660..21e3e41cdd 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -158,7 +158,7 @@ std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t c const auto is_push = _mm256_cmpgt_epi8(data, all_push1); const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); const auto is_interesting = _mm256_or_si256(is_push, is_jumpdest); - const auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); + auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); if (!mask) { @@ -166,34 +166,34 @@ std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t c continue; } - unsigned pos = 0; - auto mask_left = mask; + const auto end = i + 32; while (true) { - pos += (unsigned)__builtin_ctz(mask_left); - const auto op = code[i + pos]; + auto progress = (unsigned)__builtin_ctz(mask); + i += progress; + const auto op = code[i]; if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) { - pos += unsigned(get_push_data_size(op) + 1); + i += unsigned(get_push_data_size(op) + 1); + progress += unsigned(get_push_data_size(op) + 1); } else { - m[i + pos] = true; - pos += 1; + m[i] = true; + ++i; + progress += 1; } - if (pos >= 32) + if (i >= end) break; - mask_left = mask >> pos; - if (!mask_left) + mask >>= progress; + if (!mask) { - pos = 32; + i = end; break; } } - - i += pos; } for (; i < code_size; ++i) From e0f7328d690a66385b91573a135639fad253e252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Apr 2021 23:03:39 +0200 Subject: [PATCH 37/74] ver 3 --- test/experimental/jumpdest_analysis.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 21e3e41cdd..3c225c74ec 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -170,20 +170,18 @@ std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t c while (true) { auto progress = (unsigned)__builtin_ctz(mask); - i += progress; - const auto op = code[i]; + const auto op = code[i + progress]; if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) { - i += unsigned(get_push_data_size(op) + 1); progress += unsigned(get_push_data_size(op) + 1); } else { - m[i] = true; - ++i; + m[i + progress] = true; progress += 1; } + i += progress; if (i >= end) break; From 3f03ae68aff03f84f2792478ac04e497c396a071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Apr 2021 12:27:11 +0200 Subject: [PATCH 38/74] mask2 version --- test/experimental/jumpdest_analysis.cpp | 80 ++++++++++++++++++++- test/experimental/jumpdest_analysis.hpp | 1 + test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 + test/internal_benchmarks/analysis_bench.cpp | 2 + test/unittests/jumpdest_analysis_test.cpp | 2 + 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 3c225c74ec..d161e4f01d 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -157,8 +157,73 @@ std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t c const auto data = _mm256_loadu_si256((const __m256i*)&code[i]); const auto is_push = _mm256_cmpgt_epi8(data, all_push1); const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); - const auto is_interesting = _mm256_or_si256(is_push, is_jumpdest); - auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); + auto push_mask = (unsigned)_mm256_movemask_epi8(is_push); + auto jumpdest_mask = (unsigned)_mm256_movemask_epi8(is_jumpdest); + auto mask = push_mask | jumpdest_mask; + + if (!mask) + { + i += 32; + continue; + } + + const auto end = i + 32; + while (true) + { + auto progress = (unsigned)__builtin_ctz(mask); + const auto op = code[i + progress]; + if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) + { + progress += unsigned(get_push_data_size(op) + 1); + } + else + { + m[i + progress] = true; + progress += 1; + } + + i += progress; + if (i >= end) + break; + + mask >>= progress; + if (!mask) + { + i = end; + break; + } + } + } + + for (; i < code_size; ++i) + { + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + +std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + + const auto all_jumpdest = _mm256_set1_epi8(OP_JUMPDEST); + const auto all_push1 = _mm256_set1_epi8(OP_PUSH1 - 1); + + size_t v_code_size = code_size >= 32 ? code_size - 31 : 0; + size_t i = 0; + for (; i < v_code_size;) + { + const auto data = _mm256_loadu_si256((const __m256i*)&code[i]); + const auto is_push = _mm256_cmpgt_epi8(data, all_push1); + const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); + auto push_mask = (unsigned)_mm256_movemask_epi8(is_push); + auto jumpdest_mask = (unsigned)_mm256_movemask_epi8(is_jumpdest); + auto mask = push_mask | jumpdest_mask; if (!mask) { @@ -166,6 +231,17 @@ std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t c continue; } + // if (!push_mask && jumpdest_mask) + // { + // unsigned pos = 0; + // const auto mask_left = jumpdest_mask >> pos; + // while (mask_left) + // { + // pos = (unsigned)__builtin_ctz(mask_left); + // m[i + pos] = true; + // } + // } + const auto end = i + 32; while (true) { diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 9ce1be69cd..b0a81606bf 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -57,6 +57,7 @@ std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size) std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 27c73a4746..349ccfc5a8 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -47,6 +47,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); + const auto v6 = build_jumpdest_map_str_avx2_mask2(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); const auto a5 = build_internal_code_v2(data, data_size); @@ -67,6 +68,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe expect_eq(is_jumpdest(v3, i), expected); expect_eq(is_jumpdest(v4, i), expected); expect_eq(is_jumpdest(v5, i), expected); + expect_eq(is_jumpdest(v6, i), expected); expect_eq(is_jumpdest(a3, i), expected); expect_eq(is_jumpdest(a4.get(), data_size, i), expected); expect_eq(is_jumpdest(a5.get(), data_size, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 79ae3c65e8..758f1d0d97 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -436,6 +436,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask2); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index ad43a60522..085518fb9a 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -56,6 +56,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); const auto v4 = build_jumpdest_map_str_avx2(t.data(), t.size()); const auto v5 = build_jumpdest_map_str_avx2_mask(t.data(), t.size()); + const auto v5 = build_jumpdest_map_str_avx2_mask2(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); @@ -77,6 +78,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(v3, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); + EXPECT_EQ(is_jumpdest(v6, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(a5.get(), t.size(), i), expected); From 9a9d29ae8813fcf5fa1b38f998add129c1e76d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Apr 2021 12:33:58 +0200 Subject: [PATCH 39/74] Add 2 more contracts to the internal bench --- test/internal_benchmarks/analysis_bench.cpp | 355 +++++++++++++++++++- 1 file changed, 354 insertions(+), 1 deletion(-) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 758f1d0d97..70d3e9388a 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -13,6 +13,7 @@ namespace { +// blake2_shifts + weierstrudel + sha1_div. const auto test_bytecode = from_hex( "608060405234801561001057600080fd5b50600436106100365760003560e01c80631e0924231461003b578063d299" "dac0146102bb575b600080fd5b610282600480360360a081101561005157600080fd5b810190602081018135640100" @@ -135,7 +136,359 @@ const auto test_bytecode = from_hex( "af61156d565b81526000602082018190526040820181905260609091015290565b6040805180820182529060029082" "9080388339509192915050565b6080604051908101604052806004906020820280388339509192915050565b610200" "60405190810160405280601090602082028038833950919291505056fea165627a7a72305820a59dc9d098d29bacdd" - "88cb50c25c96ed4ba3047fd46a5c6ecf57e447a3c699100029"); + "88cb50c25c96ed4ba3047fd46a5c6ecf57e447a3c699100029" + "346060600036030617156100195761019060005260206000fd5b6060600036030460021b603e016102006136c66000" + "396004810281600302826005020182601e018103838203848203858203868203878203888203606060003603048080" + "01600a1b60e0019060061b6000015b60017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0" + "0000018235067f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190067f30644e72e1" + "31a029b85045b68181585d2833e84879b9709143e1f593f000000180807fffffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffff70024ccef014a773d2cf7a7bd9d4391eb18d850970024ccef014a773d2cf7a7b" + "d9d4391eb18d85028082109103036789d3256894d213e3097f30644e72e131a029b85045b68181585d2833e84879b9" + "709143e1f593f00000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6802d91d" + "232ec7e0b3d786096802d91d232ec7e0b3d786028082109103037f30644e72e131a029b85045b68181585cb8e665ff" + "8b011694c1d039a872b0eed9090891818377b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd090860051b" + "9060051b5b937ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0001938e6005026060" + "600036030461080002610200010390806101e01651565b908e019060041c806101e01651565b8060031c6103e01686" + "01828f019283516002018085528f03015260081c601001806101e01651565b8060021c6103e0168601828d01928351" + "6002018085528d03015260071c601001806101e01651565b8060011c6103e0168601828b019283516002018085528b" + "03015260061c601001806101e01651565b806103e01686018289019283516002018085528903015260051c60100180" + "6101e01651565b601f811161021b57509060018303926101da5750505060200180360361006c575050505050505050" + "5050506000037f912CEB58A394E07D28F0D12384840918C6843FB439555FA7B461A4448976F7D57f60C89CE5C26340" + "5370A08B6D0302B0BB2F02D522D0E3951A7841182DB0F9FA8E7f30644E72E131A029B85045B68181585D97816A9168" + "71CA8D3C208C16D87CFD477759e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe60c0528260a05281608052" + "6000604003600360003603048001038060605280359060200135828080848009840960030883828009146103b65761" + "019060005260206000fd5b82818009838160021b818080838809968009600302818180098783038001018a03806000" + "528701099209840380019180016040528101602052826020518201600051840182808280098061040a5760006000fd" + "5b818184099382828909830383808084800983800101880891820181930982878a09018b03829561052a565b604060" + "6051036060528084808083800980930981606051358190066060516020013582900682808084800984096003088382" + "80091461047a5761019060005260206000fd5b9409920985818009868160021b818082870981038187800960030290" + "82828009818001018060a051036000520109920980010160a051036020528583800182098060405290919286808084" + "8009938409948309878094860984038492838180098480808385096020510984019160005109840185808280098061" + "04fd5760006000fd5b818184099382828909830383808084800983800101880891820181930982878a090160805103" + "8280968199095b83818009848080838509602051098401916000510984018580828009806105515760006000fd5b81" + "8184099382828909830383808084800983800101880891820181930982878a09016080510382809681990983818009" + "848080838509602051098401916000510984018580828009806105a45760006000fd5b818184099382828909830383" + "808084800983800101880891820181930982878a090160805103828096819909838180098480808385096020510984" + "01916000510984018580828009806105f75760006000fd5b8181840993828289098303838080848009838001018808" + "91820181930982878a0901608051038280968199098381800984808083850960205109840191600051098401858082" + "80098061064a5760006000fd5b818184099382828909830383808084800983800101880891820181930982878a0901" + "60805103828096819909838180098480808385096020510984019160005109840185808280098061069d5760006000" + "fd5b818184099382828909830383808084800983800101880891820181930982878a09016080510382809681990983" + "818009848080838509602051098401916000510984018580828009806106f05760006000fd5b818184099382828909" + "830383808084800983800101880891820181930982878a09016080510382808097819a096040510960006060510361" + "0435573d526001600160606000360304600f036101cd0261074501565b91849083098061732052806176e052840380" + "6172e0526177205291839083098303838160c05109806176c05261770052806172c052617300529209930993840980" + "61736052806176a0528203806172a0526177605292830983038360c051820980617680526177405280617280526173" + "405292099309938409806173a0528061766052820380617260526177a05292830983038360c0518209806176405261" + "77805280617240526173805292099309938409806173e0528061762052820380617220526177e05292830983038360" + "c051820980617600526177c05280617200526173c052920993099384098061742052806175e0528203806171e05261" + "78205292830983038360c0518209806175c05261780052806171c05261740052920993099384098061746052806175" + "a0528203806171a0526178605292830983038360c05182098061758052617840528061718052617440529209930993" + "8409806174a0528061756052820380617160526178a05292830983038360c051820980617540526178805280617140" + "526174805292099309938409806174e0528061752052820380617120526178e05292830985038560c0518209806175" + "00526178c05280617100526174c052920992095b918490830980616b205280616ee052840380616ae052616f205291" + "839083098303838160c0510980616ec052616f005280616ac052616b00529209930993840980616b605280616ea052" + "820380616aa052616f605292830983038360c051820980616e8052616f405280616a8052616b405292099309938409" + "80616ba05280616e6052820380616a6052616fa05292830983038360c051820980616e4052616f805280616a405261" + "6b80529209930993840980616be05280616e2052820380616a2052616fe05292830983038360c051820980616e0052" + "616fc05280616a0052616bc0529209930993840980616c205280616de0528203806169e05261702052928309830383" + "60c051820980616dc05261700052806169c052616c00529209930993840980616c605280616da0528203806169a052" + "6170605292830983038360c051820980616d8052617040528061698052616c40529209930993840980616ca0528061" + "6d6052820380616960526170a05292830983038360c051820980616d4052617080528061694052616c805292099309" + "93840980616ce05280616d2052820380616920526170e05292830985038560c051820980616d00526170c052806169" + "0052616cc052920992095b91849083098061632052806166e0528403806162e0526167205291839083098303838160" + "c05109806166c05261670052806162c05261630052920993099384098061636052806166a0528203806162a0526167" + "605292830983038360c051820980616680526167405280616280526163405292099309938409806163a05280616660" + "52820380616260526167a05292830983038360c0518209806166405261678052806162405261638052920993099384" + "09806163e0528061662052820380616220526167e05292830983038360c051820980616600526167c0528061620052" + "6163c052920993099384098061642052806165e0528203806161e0526168205292830983038360c0518209806165c0" + "5261680052806161c05261640052920993099384098061646052806165a0528203806161a052616860529283098303" + "8360c051820980616580526168405280616180526164405292099309938409806164a0528061656052820380616160" + "526168a05292830983038360c051820980616540526168805280616140526164805292099309938409806164e05280" + "61652052820380616120526168e05292830985038560c051820980616500526168c05280616100526164c052920992" + "095b918490830980615b205280615ee052840380615ae052615f205291839083098303838160c0510980615ec05261" + "5f005280615ac052615b00529209930993840980615b605280615ea052820380615aa052615f605292830983038360" + "c051820980615e8052615f405280615a8052615b40529209930993840980615ba05280615e6052820380615a605261" + "5fa05292830983038360c051820980615e4052615f805280615a4052615b80529209930993840980615be05280615e" + "2052820380615a2052615fe05292830983038360c051820980615e0052615fc05280615a0052615bc0529209930993" + "840980615c205280615de0528203806159e0526160205292830983038360c051820980615dc05261600052806159c0" + "52615c00529209930993840980615c605280615da0528203806159a0526160605292830983038360c051820980615d" + "8052616040528061598052615c40529209930993840980615ca05280615d6052820380615960526160a05292830983" + "038360c051820980615d4052616080528061594052615c80529209930993840980615ce05280615d20528203806159" + "20526160e05292830985038560c051820980615d00526160c0528061590052615cc052920992095b91849083098061" + "532052806156e0528403806152e0526157205291839083098303838160c05109806156c05261570052806152c05261" + "530052920993099384098061536052806156a0528203806152a0526157605292830983038360c05182098061568052" + "6157405280615280526153405292099309938409806153a0528061566052820380615260526157a052928309830383" + "60c051820980615640526157805280615240526153805292099309938409806153e052806156205282038061522052" + "6157e05292830983038360c051820980615600526157c05280615200526153c0529209930993840980615420528061" + "55e0528203806151e0526158205292830983038360c0518209806155c05261580052806151c0526154005292099309" + "9384098061546052806155a0528203806151a0526158605292830983038360c0518209806155805261584052806151" + "80526154405292099309938409806154a0528061556052820380615160526158a05292830983038360c05182098061" + "5540526158805280615140526154805292099309938409806154e0528061552052820380615120526158e052928309" + "85038560c051820980615500526158c05280615100526154c052920992095b918490830980614b205280614ee05284" + "0380614ae052614f205291839083098303838160c0510980614ec052614f005280614ac052614b0052920993099384" + "0980614b605280614ea052820380614aa052614f605292830983038360c051820980614e8052614f405280614a8052" + "614b40529209930993840980614ba05280614e6052820380614a6052614fa05292830983038360c051820980614e40" + "52614f805280614a4052614b80529209930993840980614be05280614e2052820380614a2052614fe0529283098303" + "8360c051820980614e0052614fc05280614a0052614bc0529209930993840980614c205280614de0528203806149e0" + "526150205292830983038360c051820980614dc05261500052806149c052614c00529209930993840980614c605280" + "614da0528203806149a0526150605292830983038360c051820980614d8052615040528061498052614c4052920993" + "0993840980614ca05280614d6052820380614960526150a05292830983038360c051820980614d4052615080528061" + "494052614c80529209930993840980614ce05280614d2052820380614920526150e05292830985038560c051820980" + "614d00526150c0528061490052614cc052920992095b91849083098061432052806146e0528403806142e052614720" + "5291839083098303838160c05109806146c05261470052806142c05261430052920993099384098061436052806146" + "a0528203806142a0526147605292830983038360c05182098061468052614740528061428052614340529209930993" + "8409806143a0528061466052820380614260526147a05292830983038360c051820980614640526147805280614240" + "526143805292099309938409806143e0528061462052820380614220526147e05292830983038360c0518209806146" + "00526147c05280614200526143c052920993099384098061442052806145e0528203806141e0526148205292830983" + "038360c0518209806145c05261480052806141c05261440052920993099384098061446052806145a0528203806141" + "a0526148605292830983038360c051820980614580526148405280614180526144405292099309938409806144a052" + "8061456052820380614160526148a05292830983038360c05182098061454052614880528061414052614480529209" + "9309938409806144e0528061452052820380614120526148e05292830985038560c051820980614500526148c05280" + "614100526144c052920992095b918490830980613b205280613ee052840380613ae052613f20529183908309830383" + "8160c0510980613ec052613f005280613ac052613b00529209930993840980613b605280613ea052820380613aa052" + "613f605292830983038360c051820980613e8052613f405280613a8052613b40529209930993840980613ba0528061" + "3e6052820380613a6052613fa05292830983038360c051820980613e4052613f805280613a4052613b805292099309" + "93840980613be05280613e2052820380613a2052613fe05292830983038360c051820980613e0052613fc05280613a" + "0052613bc0529209930993840980613c205280613de0528203806139e0526140205292830983038360c05182098061" + "3dc05261400052806139c052613c00529209930993840980613c605280613da0528203806139a05261406052928309" + "83038360c051820980613d8052614040528061398052613c40529209930993840980613ca05280613d605282038061" + "3960526140a05292830983038360c051820980613d4052614080528061394052613c80529209930993840980613ce0" + "5280613d2052820380613920526140e05292830985038560c051820980613d00526140c0528061390052613cc05292" + "0992095b91849083098061332052806136e0528403806132e0526137205291839083098303838160c05109806136c0" + "5261370052806132c05261330052920993099384098061336052806136a0528203806132a052613760529283098303" + "8360c051820980613680526137405280613280526133405292099309938409806133a0528061366052820380613260" + "526137a05292830983038360c051820980613640526137805280613240526133805292099309938409806133e05280" + "61362052820380613220526137e05292830983038360c051820980613600526137c05280613200526133c052920993" + "099384098061342052806135e0528203806131e0526138205292830983038360c0518209806135c052613800528061" + "31c05261340052920993099384098061346052806135a0528203806131a0526138605292830983038360c051820980" + "613580526138405280613180526134405292099309938409806134a0528061356052820380613160526138a0529283" + "0983038360c051820980613540526138805280613140526134805292099309938409806134e0528061352052820380" + "613120526138e05292830985038560c051820980613500526138c05280613100526134c052920992095b9184908309" + "80612b205280612ee052840380612ae052612f205291839083098303838160c0510980612ec052612f005280612ac0" + "52612b00529209930993840980612b605280612ea052820380612aa052612f605292830983038360c051820980612e" + "8052612f405280612a8052612b40529209930993840980612ba05280612e6052820380612a6052612fa05292830983" + "038360c051820980612e4052612f805280612a4052612b80529209930993840980612be05280612e2052820380612a" + "2052612fe05292830983038360c051820980612e0052612fc05280612a0052612bc0529209930993840980612c2052" + "80612de0528203806129e0526130205292830983038360c051820980612dc05261300052806129c052612c00529209" + "930993840980612c605280612da0528203806129a0526130605292830983038360c051820980612d80526130405280" + "61298052612c40529209930993840980612ca05280612d6052820380612960526130a05292830983038360c0518209" + "80612d4052613080528061294052612c80529209930993840980612ce05280612d2052820380612920526130e05292" + "830985038560c051820980612d00526130c0528061290052612cc052920992095b91849083098061232052806126e0" + "528403806122e0526127205291839083098303838160c05109806126c05261270052806122c0526123005292099309" + "9384098061236052806126a0528203806122a0526127605292830983038360c0518209806126805261274052806122" + "80526123405292099309938409806123a0528061266052820380612260526127a05292830983038360c05182098061" + "2640526127805280612240526123805292099309938409806123e0528061262052820380612220526127e052928309" + "83038360c051820980612600526127c05280612200526123c052920993099384098061242052806125e05282038061" + "21e0526128205292830983038360c0518209806125c05261280052806121c052612400529209930993840980612460" + "52806125a0528203806121a0526128605292830983038360c051820980612580526128405280612180526124405292" + "099309938409806124a0528061256052820380612160526128a05292830983038360c0518209806125405261288052" + "80612140526124805292099309938409806124e0528061252052820380612120526128e05292830985038560c05182" + "0980612500526128c05280612100526124c052920992095b918490830980611b205280611ee052840380611ae05261" + "1f205291839083098303838160c0510980611ec052611f005280611ac052611b00529209930993840980611b605280" + "611ea052820380611aa052611f605292830983038360c051820980611e8052611f405280611a8052611b4052920993" + "0993840980611ba05280611e6052820380611a6052611fa05292830983038360c051820980611e4052611f80528061" + "1a4052611b80529209930993840980611be05280611e2052820380611a2052611fe05292830983038360c051820980" + "611e0052611fc05280611a0052611bc0529209930993840980611c205280611de0528203806119e052612020529283" + "0983038360c051820980611dc05261200052806119c052611c00529209930993840980611c605280611da052820380" + "6119a0526120605292830983038360c051820980611d8052612040528061198052611c40529209930993840980611c" + "a05280611d6052820380611960526120a05292830983038360c051820980611d4052612080528061194052611c8052" + "9209930993840980611ce05280611d2052820380611920526120e05292830985038560c051820980611d00526120c0" + "528061190052611cc052920992095b91849083098061132052806116e0528403806112e05261172052918390830983" + "03838160c05109806116c05261170052806112c05261130052920993099384098061136052806116a0528203806112" + "a0526117605292830983038360c051820980611680526117405280611280526113405292099309938409806113a052" + "8061166052820380611260526117a05292830983038360c05182098061164052611780528061124052611380529209" + "9309938409806113e0528061162052820380611220526117e05292830983038360c051820980611600526117c05280" + "611200526113c052920993099384098061142052806115e0528203806111e0526118205292830983038360c0518209" + "806115c05261180052806111c05261140052920993099384098061146052806115a0528203806111a0526118605292" + "830983038360c051820980611580526118405280611180526114405292099309938409806114a05280611560528203" + "80611160526118a05292830983038360c0518209806115405261188052806111405261148052920993099384098061" + "14e0528061152052820380611120526118e05292830985038560c051820980611500526118c05280611100526114c0" + "52920992095b918490830980610b205280610ee052840380610ae052610f205291839083098303838160c051098061" + "0ec052610f005280610ac052610b00529209930993840980610b605280610ea052820380610aa052610f6052928309" + "83038360c051820980610e8052610f405280610a8052610b40529209930993840980610ba05280610e605282038061" + "0a6052610fa05292830983038360c051820980610e4052610f805280610a4052610b80529209930993840980610be0" + "5280610e2052820380610a2052610fe05292830983038360c051820980610e0052610fc05280610a0052610bc05292" + "09930993840980610c205280610de0528203806109e0526110205292830983038360c051820980610dc05261100052" + "806109c052610c00529209930993840980610c605280610da0528203806109a0526110605292830983038360c05182" + "0980610d8052611040528061098052610c40529209930993840980610ca05280610d6052820380610960526110a052" + "92830983038360c051820980610d4052611080528061094052610c80529209930993840980610ce05280610d205282" + "0380610920526110e05292830985038560c051820980610d00526110c0528061090052610cc052920992095b918490" + "83098061032052806106e0528403806102e0526107205291839083098303838160c05109806106c052610700528061" + "02c05261030052920993099384098061036052806106a0528203806102a0526107605292830983038360c051820980" + "610680526107405280610280526103405292099309938409806103a0528061066052820380610260526107a0529283" + "0983038360c051820980610640526107805280610240526103805292099309938409806103e0528061062052820380" + "610220526107e05292830983038360c051820980610600526107c05280610200526103c05292099309938409806104" + "2052806105e0528203806101e0526108205292830983038360c0518209806105c05261080052806101c05261040052" + "920993099384098061046052806105a0528203806101a0526108605292830983038360c05182098061058052610840" + "5280610180526104405292099309938409806104a0528061056052820380610160526108a05292830983038360c051" + "820980610540526108805280610140526104805298090981038160c051820980610500526108c05280610100526104" + "c052930909806104e0528061052052810380610120526108e0523d518460071b606060003603046108000261020001" + "035b850180511561225657607c6138c6601e3980518103601e870301516202ffe01680518403906020015184036001" + "60606000360304610800026102000151603e01606060003603046108000261020001526002848a019451035161ffff" + "16565b858082800981605a8703516202ffe01680602001518286850983910986019282915109860181808083800981" + "84820999098103968189818780098a800101089809940993850109018603905b85808280098160588703516202ffe0" + "168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101" + "089809940993850109018603905b85808280098160568703516202ffe0168060200151828685098391098601928291" + "510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280" + "098160548703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103" + "968189818780098a800101089809940993850109018603905b85808280098160528703516202ffe016806020015182" + "8685098391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385" + "0109018603905b85808280098160508703516202ffe016806020015182868509839109860192829151098601818080" + "8380098184820999098103968189818780098a800101089809940993850109018603905b858082800981604e870351" + "6202ffe016806020015182868509839109860192829151098601818080838009818482099909810396818981878009" + "8a800101089809940993850109018603905b858082800981604c8703516202ffe01680602001518286850983910986" + "01928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b" + "858082800981604a8703516202ffe01680602001518286850983910986019282915109860181808083800981848209" + "99098103968189818780098a800101089809940993850109018603905b85808280098160488703516202ffe0168060" + "200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101089809" + "940993850109018603905b85808280098160468703516202ffe0168060200151828685098391098601928291510986" + "018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280098160" + "448703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189" + "818780098a800101089809940993850109018603905b85808280098160428703516202ffe016806020015182868509" + "8391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385010901" + "8603905b85808280098160408703516202ffe016806020015182868509839109860192829151098601818080838009" + "8184820999098103968189818780098a800101089809940993850109018603905b858082800981603e8703516202ff" + "e0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a8001" + "01089809940993850109018603905b858082800981603c8703516202ffe01680602001518286850983910986019282" + "91510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b858082" + "800981603a8703516202ffe01680602001518286850983910986019282915109860181808083800981848209990981" + "03968189818780098a800101089809940993850109018603905b85808280098160388703516202ffe0168060200151" + "828685098391098601928291510986018180808380098184820999098103968189818780098a800101089809940993" + "850109018603905b85808280098160368703516202ffe0168060200151828685098391098601928291510986018180" + "808380098184820999098103968189818780098a800101089809940993850109018603905b85808280098160348703" + "516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189818780" + "098a800101089809940993850109018603905b85808280098160328703516202ffe016806020015182868509839109" + "8601928291510986018180808380098184820999098103968189818780098a80010108980994099385010901860390" + "5b85808280098160308703516202ffe016806020015182868509839109860192829151098601818080838009818482" + "0999098103968189818780098a800101089809940993850109018603905b858082800981602e8703516202ffe01680" + "60200151828685098391098601928291510986018180808380098184820999098103968189818780098a8001010898" + "09940993850109018603905b858082800981602c8703516202ffe01680602001518286850983910986019282915109" + "86018180808380098184820999098103968189818780098a800101089809940993850109018603905b858082800981" + "602a8703516202ffe01680602001518286850983910986019282915109860181808083800981848209990981039681" + "89818780098a800101089809940993850109018603905b85808280098160288703516202ffe0168060200151828685" + "098391098601928291510986018180808380098184820999098103968189818780098a800101089809940993850109" + "018603905b85808280098160268703516202ffe0168060200151828685098391098601928291510986018180808380" + "098184820999098103968189818780098a800101089809940993850109018603905b85808280098160248703516202" + "ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a80" + "0101089809940993850109018603905b85808280098160228703516202ffe016806020015182868509839109860192" + "8291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b8580" + "8280098160208703516202ffe016806020015182868509839109860192829151098601818080838009818482099909" + "8103968189818780098a800101089809940993850109018603905b8582800192830986818001818080838909810397" + "800960030281818009888001019788010992090191869109850388840193515161ffff16565b858082800981605a87" + "03516202ffe01680602001518286850983910986019282915109860181808083800981848209990981039681898187" + "80098a800101089809940993850109018603905b85808280098160588703516202ffe0168060200151828685098391" + "098601928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603" + "905b85808280098160568703516202ffe0168060200151828685098391098601928291510986018180808380098184" + "820999098103968189818780098a800101089809940993850109018603905b85808280098160548703516202ffe016" + "8060200151828685098391098601928291510986018180808380098184820999098103968189818780098a80010108" + "9809940993850109018603905b85808280098160528703516202ffe016806020015182868509839109860192829151" + "0986018180808380098184820999098103968189818780098a800101089809940993850109018603905b8580828009" + "8160508703516202ffe016806020015182868509839109860192829151098601818080838009818482099909810396" + "8189818780098a800101089809940993850109018603905b858082800981604e8703516202ffe01680602001518286" + "85098391098601928291510986018180808380098184820999098103968189818780098a8001010898099409938501" + "09018603905b858082800981604c8703516202ffe01680602001518286850983910986019282915109860181808083" + "80098184820999098103968189818780098a800101089809940993850109018603905b858082800981604a87035162" + "02ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a" + "800101089809940993850109018603905b85808280098160488703516202ffe0168060200151828685098391098601" + "928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b85" + "808280098160468703516202ffe0168060200151828685098391098601928291510986018180808380098184820999" + "098103968189818780098a800101089809940993850109018603905b85808280098160448703516202ffe016806020" + "0151828685098391098601928291510986018180808380098184820999098103968189818780098a80010108980994" + "0993850109018603905b85808280098160428703516202ffe016806020015182868509839109860192829151098601" + "8180808380098184820999098103968189818780098a800101089809940993850109018603905b8580828009816040" + "8703516202ffe016806020015182868509839109860192829151098601818080838009818482099909810396818981" + "8780098a800101089809940993850109018603905b858082800981603e8703516202ffe01680602001518286850983" + "91098601928291510986018180808380098184820999098103968189818780098a8001010898099409938501090186" + "03905b858082800981603c8703516202ffe01680602001518286850983910986019282915109860181808083800981" + "84820999098103968189818780098a800101089809940993850109018603905b858082800981603a8703516202ffe0" + "168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101" + "089809940993850109018603905b85808280098160388703516202ffe0168060200151828685098391098601928291" + "510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280" + "098160368703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103" + "968189818780098a800101089809940993850109018603905b85808280098160348703516202ffe016806020015182" + "8685098391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385" + "0109018603905b85808280098160328703516202ffe016806020015182868509839109860192829151098601818080" + "8380098184820999098103968189818780098a800101089809940993850109018603905b8580828009816030870351" + "6202ffe016806020015182868509839109860192829151098601818080838009818482099909810396818981878009" + "8a800101089809940993850109018603905b858082800981602e8703516202ffe01680602001518286850983910986" + "01928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b" + "858082800981602c8703516202ffe01680602001518286850983910986019282915109860181808083800981848209" + "99098103968189818780098a800101089809940993850109018603905b858082800981602a8703516202ffe0168060" + "200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101089809" + "940993850109018603905b85808280098160288703516202ffe0168060200151828685098391098601928291510986" + "018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280098160" + "268703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189" + "818780098a800101089809940993850109018603905b85808280098160248703516202ffe016806020015182868509" + "8391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385010901" + "8603905b85808280098160228703516202ffe016806020015182868509839109860192829151098601818080838009" + "8184820999098103968189818780098a800101089809940993850109018603905b85808280098160208703516202ff" + "e0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a8001" + "01089809940993850109018603905b806136a757505050508460071b606060003603046108000261020001035b8501" + "8051156134dd57603e6060600036030461080002610200015103606060003603046108000261020001528051810360" + "1e870301516202ffe0168051840390602001518403600160028451038452835161353757613627565b858082800981" + "86516002810388528703601e8d0301516202ffe0168060200151828685098391098601928291510986018180808380" + "09806135ff57876135a8575050505086516002810388528703601e8d0301516202ffe0168060200151820395505190" + "0394505050506001613620565b818680096135ea575050505050505085828001928309868180018180808389098103" + "978009600302818180098880010197880109920901918691098503613620565b505050505050505050506000600160" + "00613620565b8184820999098103968189818780098a800101089809940993850109018603905b8351613537575b83" + "6060600036030461080002610200011461367a57858280019283098681800181808083890981039780096003028181" + "800988800101978801099209019186910985039288019283511561362757613537565b806136a75780158260011484" + "1516166136935760006000fd5b60405260205260005250505050505060603df35b8486910960405284900684036020" + "528390063d5250505050505060603df300000000000000000000000000000000000000000000000000000000000002" + "c700000000000000000000000000000000000000000000000000000000000002a20000000000000000000000000000" + "00000000000000000000000000000000027a0000000000000000000000000000000000000000000000000000000000" + "0002a20000000000000000000000000000000000000000000000000000000000000252000000000000000000000000" + "00000000000000000000000000000000000002a2000000000000000000000000000000000000000000000000000000" + "000000027a00000000000000000000000000000000000000000000000000000000000002a200000000000000000000" + "0000000000000000000000000000000000000000022a00000000000000000000000000000000000000000000000000" + "000000000002a2000000000000000000000000000000000000000000000000000000000000027a0000000000000000" + "0000000000000000000000000000000000000000000002a20000000000000000000000000000000000000000000000" + "00000000000000025200000000000000000000000000000000000000000000000000000000000002a2000000000000" + "000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000" + "00000000000000000002a22b9d2b512b052ab92a6d2a2129d52989293d28f128a52859280d27c12775272926dd2691" + "264525f925ad2561251524c9247d243123e52399234d230122b534bf3473342733db338f334332f732ab325f321331" + "c7317b312f30e33097304b2fff2fb32f672f1b2ecf2e832e372deb2d9f2d532d072cbb2c6f2c232bd7" + "608060405234801561001057600080fd5b5060043610610047577c0100000000000000000000000000000000000000" + "00000000000000000060003504631605782b811461004c575b600080fd5b6100f26004803603602081101561006257" + "600080fd5b81019060208101813564010000000081111561007d57600080fd5b82018360208201111561008f576000" + "80fd5b803590602001918460018302840111640100000000831117156100b157600080fd5b91908080601f01602080" + "9104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610127" + "945050505050565b604080517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009092" + "168252519081900360200190f35b60006040518251602084019350604067ffffffffffffffc0600183011601600982" + "820310600181146101585761015f565b6040820191505b50776745230100efcdab890098badcfe001032547600c3d2" + "e1f06101d0565b6000838310156101c9575080820151928290039260208410156101c9577fffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffffff60208590036101000a0119165b9392505050565b60005b8281" + "1015610686576101e684828961017e565b85526101f684602083018961017e565b6020860152604081850310600181" + "1461020e57610217565b60808286038701535b506040830381146001811461022b57610239565b6020860180516008" + "87021790525b5060405b6080811015610339578581017fffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffc08101517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8820151" + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08301517fffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffff48401516002911891909218189081027ffffffffefffffffeff" + "fffffefffffffefffffffefffffffefffffffefffffffe1663800000009091047c0100000001000000010000000100" + "00000100000001000000010000000116179052600c0161023d565b5060805b61014081101561043a578581017fffff" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808101517fffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffff908201517fffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffc08301517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8840151" + "6004911891909218189081027ffffffffcfffffffcfffffffcfffffffcfffffffcfffffffcfffffffcfffffffc1663" + "400000009091047c03000000030000000300000003000000030000000300000003000000031617905260180161033d" + "565b508160008060005b605081101561065c5760148104801561047257600181146104ae57600281146104e8576003" + "81146105275761055d565b6501000000000085046a0100000000000000000000860481186f01000000000000000000" + "000000000000870416189350635a827999925061055d565b6501000000000085046f01000000000000000000000000" + "00000086046a0100000000000000000000870418189350636ed9eba1925061055d565b6a0100000000000000000000" + "85046f010000000000000000000000000000008604818117650100000000008804169116179350638f1bbcdc925061" + "055d565b6501000000000085046f0100000000000000000000000000000086046a0100000000000000000000870418" + "18935063ca62c1d692505b50601f770800000000000000000000000000000000000000000000008504168063ffffff" + "e073080000000000000000000000000000000000000087041617905080840190508063ffffffff8616019050808301" + "9050807c0100000000000000000000000000000000000000000000000000000000600484028c015104019050740100" + "0000000000000000000000000000000000000081026501000000000086041794506a0100000000000000000000633f" + "ffffff6a040000000000000000000087041663c00000006604000000000000880416170277ffffffff00ffffffff00" + "0000000000ffffffff00ffffffff861617945050600181019050610442565b5050509190910177ffffffff00ffffff" + "ff00ffffffff00ffffffff00ffffffff16906040016101d3565b506c0100000000000000000000000063ffffffff82" + "1667ffffffff000000006101008404166bffffffff0000000000000000620100008504166fffffffff000000000000" + "000000000000630100000086041673ffffffff00000000000000000000000000000000640100000000870416171717" + "170294505050505091905056fea165627a7a7230582083396642a98f6018c81ca24dc0c2af8e842bd33a6b8d7f0863" + "2dc1bc372e466a0029"); using BuilderFn = decltype(&evmone::build_jumpdest_map); From 09d6c6105084dc83ec8200696835644dcae6d838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Apr 2021 16:48:31 +0200 Subject: [PATCH 40/74] mask2 impl --- test/experimental/jumpdest_analysis.cpp | 81 ++++++++++++----------- test/unittests/jumpdest_analysis_test.cpp | 9 ++- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index d161e4f01d..309576c4b9 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -16,6 +16,36 @@ inline constexpr size_t get_push_data_size(uint8_t op) noexcept return op - size_t{OP_PUSH1 - 1}; } +struct pushdata_info +{ + uint32_t mask; + size_t offset; +}; +pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask) +{ + size_t pos = 0; + uint32_t pushdata_mask = 0; + + while (push_mask) + { + const auto a = static_cast(__builtin_ctz(push_mask)); + pos += a; + const auto op = code[pos]; + const auto len = get_push_data_size(op); + const auto len_mask = ~uint32_t{0} >> (32 - len); + const auto part_mask = (pos < 31) ? len_mask << (pos + 1) : 0; + pushdata_mask |= part_mask; + const auto step = a + 1 + len; + pos += 1 + len; + if (pos >= 32) + return {pushdata_mask, pos}; + + push_mask >>= step; + } + + return {pushdata_mask, 32}; +} + std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) { std::vector m(code_size); @@ -223,51 +253,24 @@ std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); auto push_mask = (unsigned)_mm256_movemask_epi8(is_push); auto jumpdest_mask = (unsigned)_mm256_movemask_epi8(is_jumpdest); - auto mask = push_mask | jumpdest_mask; - if (!mask) - { - i += 32; - continue; - } + const auto [pushdata_mask, offset] = build_pushdata_mask(&code[i], push_mask); - // if (!push_mask && jumpdest_mask) - // { - // unsigned pos = 0; - // const auto mask_left = jumpdest_mask >> pos; - // while (mask_left) - // { - // pos = (unsigned)__builtin_ctz(mask_left); - // m[i + pos] = true; - // } - // } + jumpdest_mask &= ~pushdata_mask; - const auto end = i + 32; - while (true) + size_t pos = 0; + while (jumpdest_mask) { - auto progress = (unsigned)__builtin_ctz(mask); - const auto op = code[i + progress]; - if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) - { - progress += unsigned(get_push_data_size(op) + 1); - } - else - { - m[i + progress] = true; - progress += 1; - } - - i += progress; - if (i >= end) + const auto x = static_cast(__builtin_ctz(jumpdest_mask)); + pos += x; + m[i + pos] = true; + if (x >= 31) break; - - mask >>= progress; - if (!mask) - { - i = end; - break; - } + jumpdest_mask >>= x + 1; + pos += 1; } + + i += offset; } for (; i < code_size; ++i) diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 085518fb9a..91d3fa400a 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -39,7 +39,14 @@ const bytecode bytecode_test_cases[]{ push(0x60) + OP_JUMPDEST, "5b000000000000000000000000000000", "005b0000000000000000000000000000", + "605b00605b000000000000000000000000000000000000000000000000000000", + "5b14000000000000005badadad0000000000000000000000606060606060ff5b", "5b00000000000000000000000000000000000000000000000000000000000060", + "605b000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000007f5b", + "00605b000000000000000000000000000000000000000000000000000000605b", + "005b5b5b00000000000000000000000000000000000000000000000000000000", + "5b5b000000000000000000000000000000000000000000000000000000000000", }; } // namespace @@ -56,7 +63,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); const auto v4 = build_jumpdest_map_str_avx2(t.data(), t.size()); const auto v5 = build_jumpdest_map_str_avx2_mask(t.data(), t.size()); - const auto v5 = build_jumpdest_map_str_avx2_mask2(t.data(), t.size()); + const auto v6 = build_jumpdest_map_str_avx2_mask2(t.data(), t.size()); const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); const auto a4 = build_internal_code_v1(t.data(), t.size()); const auto a5 = build_internal_code_v2(t.data(), t.size()); From f5b11663622edac4b35ab015f89d3b907bcf157d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Apr 2021 21:34:45 +0200 Subject: [PATCH 41/74] opt build_pushdata_mask --- test/experimental/jumpdest_analysis.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 309576c4b9..8443d4d060 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -33,17 +33,17 @@ pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask) const auto op = code[pos]; const auto len = get_push_data_size(op); const auto len_mask = ~uint32_t{0} >> (32 - len); - const auto part_mask = (pos < 31) ? len_mask << (pos + 1) : 0; + const auto part_mask = len_mask << pos; pushdata_mask |= part_mask; const auto step = a + 1 + len; pos += 1 + len; if (pos >= 32) - return {pushdata_mask, pos}; + return {pushdata_mask << 1, pos}; push_mask >>= step; } - return {pushdata_mask, 32}; + return {pushdata_mask << 1, 32}; } std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) From cc190097ecd0bfc1815c752c836128bc8fbd169d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Apr 2021 21:46:19 +0200 Subject: [PATCH 42/74] opt build_pushdata_mask --- test/experimental/jumpdest_analysis.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 8443d4d060..f43f645c14 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -28,22 +28,20 @@ pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask) while (push_mask) { - const auto a = static_cast(__builtin_ctz(push_mask)); - pos += a; + pos = static_cast(__builtin_ctz(push_mask)); const auto op = code[pos]; const auto len = get_push_data_size(op); - const auto len_mask = ~uint32_t{0} >> (32 - len); + const auto len_mask = len <= 31 ? ~uint32_t{0} >> (31 - len) : ~uint32_t{0}; const auto part_mask = len_mask << pos; pushdata_mask |= part_mask; - const auto step = a + 1 + len; pos += 1 + len; if (pos >= 32) - return {pushdata_mask << 1, pos}; + return {pushdata_mask, pos}; - push_mask >>= step; + push_mask &= ~part_mask; } - return {pushdata_mask << 1, 32}; + return {pushdata_mask, 32}; } std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) From bd26d545816d0961a51454681dbc8597d1ef8e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Feb 2024 14:53:00 +0100 Subject: [PATCH 43/74] cmake: remove files --- test/unittests/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 75d60c5a90..3362ad4bd5 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -83,9 +83,7 @@ target_sources( statetest_withdrawals_test.cpp tracing_test.cpp jumpdest_analysis_test.cpp - op_table_test.cpp opcode_manip_test.cpp - utils_test.cpp ) target_link_libraries(evmone-unittests PRIVATE evmone evmone::evmmax evmone::state evmone::experimental evmone::statetestutils testutils evmc::instructions GTest::gtest GTest::gtest_main) target_include_directories(evmone-unittests PRIVATE ${evmone_private_include_dir}) From f78852b8a4dfd0170f73b31f483a4e53092548f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Feb 2024 15:16:23 +0100 Subject: [PATCH 44/74] fix build --- test/experimental/jumpdest_analysis.cpp | 3 ++- test/experimental/jumpdest_analysis.hpp | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index f43f645c14..797d3a044e 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace evmone::experimental { @@ -291,7 +292,7 @@ JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size) { const auto op = code[i]; if (__builtin_expect(op == OP_JUMPDEST, false)) - m.set(i); + m[i] = true; else if (is_push(op)) i += get_push_data_size(op); } diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index b0a81606bf..005ffea820 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -9,6 +9,8 @@ namespace evmone::experimental { +using JumpdestMap = std::vector; + inline bool is_jumpdest(const std::vector& jumpdest_map, size_t index) noexcept { return (index < jumpdest_map.size() && jumpdest_map[index]); @@ -34,7 +36,7 @@ class bitset32 std::size_t size() const noexcept { return size_; } - bool operator[](std::size_t index) const noexcept + bool operator[](std::size_t index) const noexcept { const auto w = index / bpw; const auto x = index % bpw; @@ -61,7 +63,7 @@ std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); -bitset build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); +JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t code_size); From 28e75647583e9dbd887629be27643c1229bed8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Feb 2024 15:16:30 +0100 Subject: [PATCH 45/74] add missing evmc --- test/internal_benchmarks/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/internal_benchmarks/CMakeLists.txt b/test/internal_benchmarks/CMakeLists.txt index 6f7bafa617..6369059ca9 100644 --- a/test/internal_benchmarks/CMakeLists.txt +++ b/test/internal_benchmarks/CMakeLists.txt @@ -10,4 +10,4 @@ add_executable( memory_allocation.cpp ) -target_link_libraries(evmone-bench-internal PRIVATE evmone::evmmax evmone::experimental benchmark::benchmark) +target_link_libraries(evmone-bench-internal PRIVATE evmone::evmmax evmone::experimental evmc::evmc_cpp benchmark::benchmark) From 1a54eda854abb9c9b86515475f3fe04b4870118a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Feb 2024 15:16:37 +0100 Subject: [PATCH 46/74] move code --- test/experimental/jumpdest_analysis.cpp | 23 ++++++++++++++++++++- test/experimental/jumpdest_analysis.hpp | 1 + test/internal_benchmarks/analysis_bench.cpp | 19 +++++++++-------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 797d3a044e..2fd7bed640 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -6,12 +6,33 @@ #include "opcode_manip.hpp" #include #include - #include #include +#include namespace evmone::experimental { +JumpdestMap official_analyze_jumpdests(const uint8_t* code, size_t code_size) +{ + // To find if op is any PUSH opcode (OP_PUSH1 <= op <= OP_PUSH32) + // it can be noticed that OP_PUSH32 is INT8_MAX (0x7f) therefore + // static_cast(op) <= OP_PUSH32 is always true and can be skipped. + static_assert(OP_PUSH32 == std::numeric_limits::max()); + + evmone::experimental::JumpdestMap map(code_size); // Allocate and init bitmap with zeros. + for (size_t i = 0; i < code_size; ++i) + { + const auto op = code[i]; + if (static_cast(op) >= OP_PUSH1) // If any PUSH opcode (see explanation above). + i += op - size_t{OP_PUSH1 - 1}; // Skip PUSH data. + else if (__builtin_expect(op == OP_JUMPDEST, false)) + map[i] = true; + } + + return map; +} + + inline constexpr size_t get_push_data_size(uint8_t op) noexcept { return op - size_t{OP_PUSH1 - 1}; diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 005ffea820..dac3449293 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -53,6 +53,7 @@ class bitset32 } }; +JumpdestMap official_analyze_jumpdests(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 70d3e9388a..a71749b082 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -8,13 +8,15 @@ #include #include +#include +#include #include namespace { // blake2_shifts + weierstrudel + sha1_div. -const auto test_bytecode = from_hex( +const auto test_bytecode = *evmc::from_hex( "608060405234801561001057600080fd5b50600436106100365760003560e01c80631e0924231461003b578063d299" "dac0146102bb575b600080fd5b610282600480360360a081101561005157600080fd5b810190602081018135640100" "00000081111561006c57600080fd5b82018360208201111561007e57600080fd5b8035906020019184600183028401" @@ -490,8 +492,6 @@ const auto test_bytecode = from_hex( "170294505050505091905056fea165627a7a7230582083396642a98f6018c81ca24dc0c2af8e842bd33a6b8d7f0863" "2dc1bc372e466a0029"); -using BuilderFn = decltype(&evmone::build_jumpdest_map); - enum : uint8_t { OP_JUMPDEST = 0x5b, @@ -501,12 +501,12 @@ enum : uint8_t [[gnu::noinline]] auto build_bitset2(const uint8_t* code, size_t code_size) { - evmone::bitset m(code_size); + evmone::experimental::JumpdestMap m(code_size); for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; if (op == OP_JUMPDEST) - m.set(i); + m[i] = true; if ((op >> 5) == 0b11) i += static_cast((op & 0b11111) + 1); @@ -772,10 +772,11 @@ void build_jumpdest(benchmark::State& state) } } // namespace -BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, evmone::build_jumpdest_map); -BENCHMARK_TEMPLATE( - build_jumpdest, evmone::bitset, evmone::experimental::build_jumpdest_map_bitset1); -BENCHMARK_TEMPLATE(build_jumpdest, evmone::bitset, build_bitset2); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, + evmone::experimental::official_analyze_jumpdests); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, + evmone::experimental::build_jumpdest_map_bitset1); +BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); From a776a615488d82c6c241ed53f4953aac32bc5fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Feb 2024 15:42:13 +0100 Subject: [PATCH 47/74] build fixes --- lib/evmone/instructions_opcodes.hpp | 2 +- test/experimental/jumpdest_analysis.hpp | 2 +- test/experimental/opcode_manip.hpp | 3 ++- test/unittests/jumpdest_analysis_test.cpp | 16 +--------------- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index 6629732698..0eb4741658 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -11,7 +11,7 @@ namespace evmone /// /// This is not enum class because we want implicit conversion to integers, /// e.g. for usage as an array index. -enum Opcode : uint8_t +enum Opcode : unsigned char { OP_STOP = 0x00, OP_ADD = 0x01, diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index dac3449293..077a3155cb 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -11,7 +11,7 @@ namespace evmone::experimental { using JumpdestMap = std::vector; -inline bool is_jumpdest(const std::vector& jumpdest_map, size_t index) noexcept +inline bool is_jumpdest(const JumpdestMap& jumpdest_map, size_t index) noexcept { return (index < jumpdest_map.size() && jumpdest_map[index]); } diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp index e7e8f51450..56ec873ed2 100644 --- a/test/experimental/opcode_manip.hpp +++ b/test/experimental/opcode_manip.hpp @@ -2,7 +2,8 @@ // Copyright 2020 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 -#include +#include +#include namespace evmone::experimental { diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 91d3fa400a..bf8b5fb015 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -4,8 +4,6 @@ #include "test/experimental/jumpdest_analysis.hpp" #include "test/utils/bytecode.hpp" -#include -#include #include using namespace evmone; @@ -15,21 +13,11 @@ namespace { constexpr auto tail_code_padding = 100; -inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept -{ - return (index < a.size() && a[index]); -} - inline bool is_jumpdest(const bitset32& a, size_t index) noexcept { return (index < a.size() && a[index]); } -inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept -{ - return find_jumpdest(a, static_cast(index)) >= 0; -} - const bytecode bytecode_test_cases[]{ push(0x5b), {}, @@ -55,8 +43,7 @@ TEST(jumpdest_analysis, compare_implementations) for (const auto& t : bytecode_test_cases) { SCOPED_TRACE(hex(t)); - const auto a0 = build_jumpdest_map(t.data(), t.size()); - const auto a1 = analyze(EVMC_FRONTIER, t.data(), t.size()); + const auto a0 = official_analyze_jumpdests(t.data(), t.size()); const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); const auto v2 = build_jumpdest_map_vec2(t.data(), t.size()); const auto x3 = build_jumpdest_map_vec3(t.data(), t.size()); @@ -78,7 +65,6 @@ TEST(jumpdest_analysis, compare_implementations) { SCOPED_TRACE(i); const bool expected = is_jumpdest(a0, i); - EXPECT_EQ(is_jumpdest(a1, i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); EXPECT_EQ(is_jumpdest(x3, i), expected); From e643354c5d4671edea08addb211d288d9ec7a1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Feb 2024 16:14:58 +0100 Subject: [PATCH 48/74] bench: add bytes rate --- test/internal_benchmarks/analysis_bench.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index a71749b082..379f2969df 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -769,6 +769,11 @@ void build_jumpdest(benchmark::State& state) auto r = Fn(test_bytecode.data(), test_bytecode.size()); benchmark::DoNotOptimize(r); } + + using namespace benchmark; + state.counters["bytes"] = { + static_cast(static_cast(test_bytecode.size()) * state.iterations()), + Counter::kIsRate}; } } // namespace From 24e2e4686f8571ad7eed395aaac79875d95d5f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 00:51:45 +0100 Subject: [PATCH 49/74] simd4 --- test/experimental/jumpdest_analysis.cpp | 64 +++++++++++++++++++++++++ test/experimental/jumpdest_analysis.hpp | 1 + 2 files changed, 65 insertions(+) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 2fd7bed640..1a9ba44799 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -520,6 +520,70 @@ bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size) return jumpdest_map; } +bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) +{ + static constexpr auto v_size = 32; + + bitset32 jumpdest_map(code_size); + + const auto v_code_size = code_size / v_size; + const auto v_tail_size = code_size % v_size; + + const auto v_jumpdes_op = _mm256_set1_epi8(OP_JUMPDEST); + const auto v_push0_op = _mm256_set1_epi8(OP_PUSH0); + uint32_t clear_next = 0; + + for (size_t v = 0; v < v_code_size; ++v) + { + const auto v_begin = v * v_size; + const auto* ptr = &code[v_begin]; + + const auto v_fragment = _mm256_loadu_si256((const __m256i*)ptr); + const auto v_is_push = _mm256_cmpgt_epi8(v_fragment, v_push0_op); + auto m_is_push = (unsigned)_mm256_movemask_epi8(v_is_push); + + m_is_push &= ~clear_next; + uint64_t datamask = clear_next; + +#pragma unroll 1 + while (m_is_push != 0) + { + const auto p = __builtin_ctz(m_is_push); + const auto op = code[p]; + const auto dl = op - OP_PUSH0; + const auto dm = ((uint64_t{2} << dl) - 1) << p; + datamask |= dm; + m_is_push &= ~dm; + } + + const auto v_is_jumpdest = _mm256_cmpeq_epi8(v_fragment, v_jumpdes_op); + auto m_is_jumpdest = (unsigned)_mm256_movemask_epi8(v_is_jumpdest); + + m_is_jumpdest &= ~datamask; + jumpdest_map.words_[v] = m_is_jumpdest; + clear_next = static_cast(datamask >> 32); + } + + uint32_t j_mask = 0; + const auto skip = clear_next ? 32 - size_t(__builtin_clz(clear_next)) : 0; + for (size_t j = skip; j < v_tail_size; ++j) + { + const auto base = code_size - v_tail_size; + const auto c = code[base + j]; + if (c == OP_JUMPDEST) + j_mask |= (1u << j); + + if (is_push(c)) + { + const auto p = get_push_data_size(c); + j += p; + } + } + jumpdest_map.words_[v_code_size] = j_mask; + + return jumpdest_map; +} + static constexpr size_t padding = 33; std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size) diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 077a3155cb..c097d95427 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -64,6 +64,7 @@ std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size); +bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size); JumpdestMap build_jumpdest_map_bitset1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v1(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t code_size); From da4ee978e7103ee0358cb7b34e4cd98a218ed3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 00:51:57 +0100 Subject: [PATCH 50/74] test --- test/unittests/jumpdest_analysis_test.cpp | 42 +++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index bf8b5fb015..bc836539e9 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -43,25 +43,29 @@ TEST(jumpdest_analysis, compare_implementations) for (const auto& t : bytecode_test_cases) { SCOPED_TRACE(hex(t)); - const auto a0 = official_analyze_jumpdests(t.data(), t.size()); - const auto a2 = build_jumpdest_map_vec1(t.data(), t.size()); - const auto v2 = build_jumpdest_map_vec2(t.data(), t.size()); - const auto x3 = build_jumpdest_map_vec3(t.data(), t.size()); - const auto v3 = build_jumpdest_map_sttni(t.data(), t.size()); - const auto v4 = build_jumpdest_map_str_avx2(t.data(), t.size()); - const auto v5 = build_jumpdest_map_str_avx2_mask(t.data(), t.size()); - const auto v6 = build_jumpdest_map_str_avx2_mask2(t.data(), t.size()); - const auto a3 = build_jumpdest_map_bitset1(t.data(), t.size()); - const auto a4 = build_internal_code_v1(t.data(), t.size()); - const auto a5 = build_internal_code_v2(t.data(), t.size()); - const auto a6 = build_internal_code_v3(t.data(), t.size()); - const auto ic4 = build_internal_code_v4(t.data(), t.size()); - const auto ic8 = build_internal_code_v8(t.data(), t.size()); - const auto s1 = build_jumpdest_map_simd1(t.data(), t.size()); - const auto s2 = build_jumpdest_map_simd2(t.data(), t.size()); - const auto s3 = build_jumpdest_map_simd3(t.data(), t.size()); + const auto data = t.data(); + const auto data_size = t.size(); - for (size_t i = 0; i < t.size() + tail_code_padding; ++i) + const auto a0 = official_analyze_jumpdests(data, data_size); + const auto a2 = build_jumpdest_map_vec1(data, data_size); + const auto v2 = build_jumpdest_map_vec2(data, data_size); + const auto x3 = build_jumpdest_map_vec3(data, data_size); + const auto v3 = build_jumpdest_map_sttni(data, data_size); + const auto v4 = build_jumpdest_map_str_avx2(data, data_size); + const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); + const auto v6 = build_jumpdest_map_str_avx2_mask2(data, data_size); + const auto a3 = build_jumpdest_map_bitset1(data, data_size); + const auto a4 = build_internal_code_v1(data, data_size); + const auto a5 = build_internal_code_v2(data, data_size); + const auto a6 = build_internal_code_v3(data, data_size); + const auto ic4 = build_internal_code_v4(data, data_size); + const auto ic8 = build_internal_code_v8(data, data_size); + const auto s1 = build_jumpdest_map_simd1(data, data_size); + const auto s2 = build_jumpdest_map_simd2(data, data_size); + const auto s3 = build_jumpdest_map_simd3(data, data_size); + const auto s4 = build_jumpdest_map_simd4(data, data_size); + + for (size_t i = 0; i < data_size + tail_code_padding; ++i) { SCOPED_TRACE(i); const bool expected = is_jumpdest(a0, i); @@ -80,6 +84,8 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(ic8.get(), t.size(), i), expected); EXPECT_EQ(is_jumpdest(s1, i), expected); EXPECT_EQ(is_jumpdest(s2, i), expected); + EXPECT_EQ(is_jumpdest(s3, i), expected); + EXPECT_EQ(is_jumpdest(s4, i), expected); } } } From fac56827efd787bf0571e7da5ff5d605db798513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 00:52:02 +0100 Subject: [PATCH 51/74] fuzz --- test/fuzzer/jumpdest_analysis_fuzz.cpp | 53 ++++++++++---------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 349ccfc5a8..f8fdcb0b9d 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 #include "test/experimental/jumpdest_analysis.hpp" -#include #include @@ -13,7 +12,7 @@ using namespace evmone::experimental; namespace { template -inline void expect_eq(T1 a, T2 b) noexcept +inline void EXPECT_EQ(T1 a, T2 b) noexcept { if (a != b) __builtin_unreachable(); @@ -21,26 +20,15 @@ inline void expect_eq(T1 a, T2 b) noexcept constexpr auto tail_code_padding = 100; -inline bool is_jumpdest(const JumpdestMap& a, size_t index) noexcept -{ - return (index < a.size() && a[index]); -} - inline bool is_jumpdest(const bitset32& a, size_t index) noexcept { return (index < a.size() && a[index]); } - -[[maybe_unused]] inline bool is_jumpdest(const code_analysis& a, size_t index) noexcept -{ - return find_jumpdest(a, static_cast(index)) >= 0; -} } // namespace extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noexcept { - const auto a0 = build_jumpdest_map(data, data_size); - const auto a1 = analyze(EVMC_FRONTIER, data, data_size); + const auto a0 = official_analyze_jumpdests(data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); const auto x3 = build_jumpdest_map_vec3(data, data_size); @@ -57,29 +45,28 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto s1 = build_jumpdest_map_simd1(data, data_size); const auto s2 = build_jumpdest_map_simd2(data, data_size); const auto s3 = build_jumpdest_map_simd3(data, data_size); + const auto s4 = build_jumpdest_map_simd4(data, data_size); for (size_t i = 0; i < data_size + tail_code_padding; ++i) { const bool expected = is_jumpdest(a0, i); - expect_eq(is_jumpdest(a1, i), expected); - expect_eq(is_jumpdest(a2, i), expected); - expect_eq(is_jumpdest(v2, i), expected); - expect_eq(is_jumpdest(x3, i), expected); - expect_eq(is_jumpdest(v3, i), expected); - expect_eq(is_jumpdest(v4, i), expected); - expect_eq(is_jumpdest(v5, i), expected); - expect_eq(is_jumpdest(v6, i), expected); - expect_eq(is_jumpdest(a3, i), expected); - expect_eq(is_jumpdest(a4.get(), data_size, i), expected); - expect_eq(is_jumpdest(a5.get(), data_size, i), expected); - expect_eq(is_jumpdest(a6.get(), data_size, i), expected); - expect_eq(is_jumpdest(ic4.get(), data_size, i), expected); - expect_eq(is_jumpdest(ic8.get(), data_size, i), expected); - expect_eq(is_jumpdest(s1, i), expected); - expect_eq(is_jumpdest(s2, i), expected); - expect_eq(is_jumpdest(s3, i), expected); + EXPECT_EQ(is_jumpdest(a2, i), expected); + EXPECT_EQ(is_jumpdest(v2, i), expected); + EXPECT_EQ(is_jumpdest(x3, i), expected); + EXPECT_EQ(is_jumpdest(v3, i), expected); + EXPECT_EQ(is_jumpdest(v4, i), expected); + EXPECT_EQ(is_jumpdest(v5, i), expected); + EXPECT_EQ(is_jumpdest(v6, i), expected); + EXPECT_EQ(is_jumpdest(a3, i), expected); + EXPECT_EQ(is_jumpdest(a4.get(), data_size, i), expected); + EXPECT_EQ(is_jumpdest(a5.get(), data_size, i), expected); + EXPECT_EQ(is_jumpdest(a6.get(), data_size, i), expected); + EXPECT_EQ(is_jumpdest(ic4.get(), data_size, i), expected); + EXPECT_EQ(is_jumpdest(ic8.get(), data_size, i), expected); + EXPECT_EQ(is_jumpdest(s1, i), expected); + EXPECT_EQ(is_jumpdest(s2, i), expected); + EXPECT_EQ(is_jumpdest(s3, i), expected); + EXPECT_EQ(is_jumpdest(s4, i), expected); } - - return 0; } From 1530adcaab0bf6d9c777df2355e5171c46ea80c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 00:52:06 +0100 Subject: [PATCH 52/74] bench --- test/internal_benchmarks/analysis_bench.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 379f2969df..1f24672850 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -801,6 +801,10 @@ BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); BENCHMARK_TEMPLATE( build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd2); +BENCHMARK_TEMPLATE( + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd3); +BENCHMARK_TEMPLATE( + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); From 239c6d36d9eb6809b11396168ba432287690247c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 10:37:05 +0100 Subject: [PATCH 53/74] fix simd4 --- test/experimental/jumpdest_analysis.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 1a9ba44799..6cdd06356e 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -545,11 +545,11 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) m_is_push &= ~clear_next; uint64_t datamask = clear_next; -#pragma unroll 1 + // #pragma unroll 1 while (m_is_push != 0) { const auto p = __builtin_ctz(m_is_push); - const auto op = code[p]; + const auto op = ptr[p]; const auto dl = op - OP_PUSH0; const auto dm = ((uint64_t{2} << dl) - 1) << p; datamask |= dm; From 75328c2d82d3d7bccce0c373b55964d21cb106e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 10:38:32 +0100 Subject: [PATCH 54/74] avx2_mask_v2 --- test/experimental/jumpdest_analysis.cpp | 69 +++++++++++++++++++-- test/experimental/jumpdest_analysis.hpp | 1 + test/internal_benchmarks/analysis_bench.cpp | 2 + test/unittests/jumpdest_analysis_test.cpp | 4 ++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 6cdd06356e..859911314f 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -257,6 +257,69 @@ std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t c return m; } +std::vector build_jumpdest_map_str_avx2_mask_v2(const uint8_t* code, size_t code_size) +{ + std::vector m(code_size); + + const auto all_jumpdest = _mm256_set1_epi8(OP_JUMPDEST); + const auto all_push1 = _mm256_set1_epi8(OP_PUSH1 - 1); + + size_t v_code_size = code_size >= 32 ? code_size - 31 : 0; + size_t i = 0; + for (; i < v_code_size;) + { + const auto data = _mm256_loadu_si256((const __m256i*)&code[i]); + const auto is_push = _mm256_cmpgt_epi8(data, all_push1); + const auto is_jumpdest = _mm256_cmpeq_epi8(data, all_jumpdest); + const auto is_interesting = _mm256_or_si256(is_push, is_jumpdest); + auto mask = (unsigned)_mm256_movemask_epi8(is_interesting); + + if (!mask) + { + i += 32; + continue; + } + + const auto end = i + 32; + while (true) + { + auto progress = (unsigned)__builtin_ctz(mask); + const auto op = code[i + progress]; + if (__builtin_expect(static_cast(op) >= OP_PUSH1, true)) + { + progress += unsigned(get_push_data_size(op) + 1); + } + else + { + m[i + progress] = true; + progress += 1; + } + + i += progress; + if (i >= end) + break; + + mask >>= progress; + if (!mask) + { + i = end; + break; + } + } + } + + for (; i < code_size; ++i) + { + const auto op = code[i]; + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (__builtin_expect(op == OP_JUMPDEST, false)) + m[i] = true; + } + return m; +} + std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t code_size) { std::vector m(code_size); @@ -462,8 +525,7 @@ bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size) const auto v_tail_size = code_size % v_size; const auto v_jmpd = _mm256_set1_epi8(OP_JUMPDEST); - const auto v_push_mask = _mm256_set1_epi8(static_cast(0xe0)); - const auto v_push_pattern = _mm256_set1_epi8(0x60); + const auto v_push0 = _mm256_set1_epi8(OP_PUSH0); uint32_t clear_next = 0; for (size_t v = 0; v < v_code_size; ++v) { @@ -474,8 +536,7 @@ bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size) const auto v_eq = _mm256_cmpeq_epi8(v_code, v_jmpd); auto j_mask = static_cast(_mm256_movemask_epi8(v_eq)); - const auto v_push_locs = - _mm256_cmpeq_epi8(_mm256_and_si256(v_code, v_push_mask), v_push_pattern); + const auto v_push_locs = _mm256_cmpgt_epi8(v_code, v_push0); auto push_locs = static_cast(_mm256_movemask_epi8(v_push_locs)); push_locs &= ~clear_next; diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index c097d95427..e6a523a2f4 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -60,6 +60,7 @@ std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size) std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); +std::vector build_jumpdest_map_str_avx2_mask_v2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask2(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd1(const uint8_t* code, size_t code_size); bitset32 build_jumpdest_map_simd2(const uint8_t* code, size_t code_size); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 1f24672850..a451cc8f53 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -795,6 +795,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask); +BENCHMARK_TEMPLATE( + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask_v2); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask2); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index bc836539e9..f9d1f81876 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -35,6 +35,8 @@ const bytecode bytecode_test_cases[]{ "00605b000000000000000000000000000000000000000000000000000000605b", "005b5b5b00000000000000000000000000000000000000000000000000000000", "5b5b000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000" // vvv + "7000000000000000005b000000000000005b5b00000000000000000000000000", }; } // namespace @@ -53,6 +55,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); + const auto v5a = build_jumpdest_map_str_avx2_mask_v2(data, data_size); const auto v6 = build_jumpdest_map_str_avx2_mask2(data, data_size); const auto a3 = build_jumpdest_map_bitset1(data, data_size); const auto a4 = build_internal_code_v1(data, data_size); @@ -75,6 +78,7 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(v3, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); + EXPECT_EQ(is_jumpdest(v5a, i), expected); EXPECT_EQ(is_jumpdest(v6, i), expected); EXPECT_EQ(is_jumpdest(a3, i), expected); EXPECT_EQ(is_jumpdest(a4.get(), t.size(), i), expected); From a10f88f9eba55b39c717c962565033a2d87f4813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 11:04:54 +0100 Subject: [PATCH 55/74] fix gcc build --- test/experimental/jumpdest_analysis.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 859911314f..be5cd65adb 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -43,7 +43,7 @@ struct pushdata_info uint32_t mask; size_t offset; }; -pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask) +static pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask) { size_t pos = 0; uint32_t pushdata_mask = 0; @@ -614,13 +614,13 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) const auto dl = op - OP_PUSH0; const auto dm = ((uint64_t{2} << dl) - 1) << p; datamask |= dm; - m_is_push &= ~dm; + m_is_push &= ~static_cast(dm); } const auto v_is_jumpdest = _mm256_cmpeq_epi8(v_fragment, v_jumpdes_op); auto m_is_jumpdest = (unsigned)_mm256_movemask_epi8(v_is_jumpdest); - m_is_jumpdest &= ~datamask; + m_is_jumpdest &= ~static_cast(datamask); jumpdest_map.words_[v] = m_is_jumpdest; clear_next = static_cast(datamask >> 32); } From 66ec0f1ff38863b5ea3a2c89694e83a54cfc0a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 11:15:27 +0100 Subject: [PATCH 56/74] precompute dl with avx --- test/experimental/jumpdest_analysis.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index be5cd65adb..455e0dfe74 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -583,6 +583,8 @@ bitset32 build_jumpdest_map_simd3(const uint8_t* code, size_t code_size) bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) { + alignas(32) uint8_t tmp[32]; + static constexpr auto v_size = 32; bitset32 jumpdest_map(code_size); @@ -603,6 +605,9 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) const auto v_is_push = _mm256_cmpgt_epi8(v_fragment, v_push0_op); auto m_is_push = (unsigned)_mm256_movemask_epi8(v_is_push); + const auto v_dl = _mm256_sub_epi8(v_fragment, v_push0_op); + _mm256_store_si256((__m256i*)tmp, v_dl); + m_is_push &= ~clear_next; uint64_t datamask = clear_next; @@ -610,8 +615,7 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) while (m_is_push != 0) { const auto p = __builtin_ctz(m_is_push); - const auto op = ptr[p]; - const auto dl = op - OP_PUSH0; + const auto dl = tmp[p]; const auto dm = ((uint64_t{2} << dl) - 1) << p; datamask |= dm; m_is_push &= ~static_cast(dm); From a6f7a912a9f0f152fa177fd432339f116edb2f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Feb 2024 11:35:53 +0100 Subject: [PATCH 57/74] precompute more --- test/experimental/jumpdest_analysis.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 455e0dfe74..0a72c866e0 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -594,6 +594,7 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) const auto v_jumpdes_op = _mm256_set1_epi8(OP_JUMPDEST); const auto v_push0_op = _mm256_set1_epi8(OP_PUSH0); + const auto v_pushx_op = _mm256_set1_epi8(OP_PUSH0 - 1); uint32_t clear_next = 0; for (size_t v = 0; v < v_code_size; ++v) @@ -605,7 +606,7 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) const auto v_is_push = _mm256_cmpgt_epi8(v_fragment, v_push0_op); auto m_is_push = (unsigned)_mm256_movemask_epi8(v_is_push); - const auto v_dl = _mm256_sub_epi8(v_fragment, v_push0_op); + const auto v_dl = _mm256_sub_epi8(v_fragment, v_pushx_op); _mm256_store_si256((__m256i*)tmp, v_dl); m_is_push &= ~clear_next; @@ -616,7 +617,7 @@ bitset32 build_jumpdest_map_simd4(const uint8_t* code, size_t code_size) { const auto p = __builtin_ctz(m_is_push); const auto dl = tmp[p]; - const auto dm = ((uint64_t{2} << dl) - 1) << p; + const auto dm = ((uint64_t{1} << dl) - 1) << p; datamask |= dm; m_is_push &= ~static_cast(dm); } From 8ba767db5e50d3ce6d784ecab8190c6d1d28b047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 9 Oct 2024 12:11:49 +0200 Subject: [PATCH 58/74] fix build --- test/unittests/jumpdest_analysis_test.cpp | 1 + test/unittests/opcode_manip_test.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index f9d1f81876..4ea13e5528 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -8,6 +8,7 @@ using namespace evmone; using namespace evmone::experimental; +using namespace evmone::test; namespace { diff --git a/test/unittests/opcode_manip_test.cpp b/test/unittests/opcode_manip_test.cpp index f5e6da28b4..941ce5e36a 100644 --- a/test/unittests/opcode_manip_test.cpp +++ b/test/unittests/opcode_manip_test.cpp @@ -7,6 +7,7 @@ #include using namespace evmone::experimental; +using namespace evmone::test; TEST(opcode_manip, find_first_push) { From b3f9b6a5c8a1d30bb3053acfeab7e0d547516d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 11 Oct 2024 14:35:39 +0200 Subject: [PATCH 59/74] add baseline analysis --- test/unittests/jumpdest_analysis_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 4ea13e5528..ad06fef17e 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -4,6 +4,7 @@ #include "test/experimental/jumpdest_analysis.hpp" #include "test/utils/bytecode.hpp" +#include #include using namespace evmone; @@ -49,6 +50,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto data = t.data(); const auto data_size = t.size(); + const auto xxx = baseline::analyze({data, data_size}, false); const auto a0 = official_analyze_jumpdests(data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); @@ -73,6 +75,7 @@ TEST(jumpdest_analysis, compare_implementations) { SCOPED_TRACE(i); const bool expected = is_jumpdest(a0, i); + EXPECT_EQ(xxx.check_jumpdest(i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); EXPECT_EQ(is_jumpdest(x3, i), expected); From b9065e4d59a83a232413b6929c93c941f9ecd6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 11 Oct 2024 14:53:39 +0200 Subject: [PATCH 60/74] type tests --- test/unittests/jumpdest_analysis_test.cpp | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index ad06fef17e..fe3dbc0874 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -13,6 +13,13 @@ using namespace evmone::test; namespace { +struct JumpdestAnalysisImpl +{ + static constexpr auto name = "baseline"; + static auto analyze(bytes_view code) { return baseline::analyze(code, false); } +}; + + constexpr auto tail_code_padding = 100; inline bool is_jumpdest(const bitset32& a, size_t index) noexcept @@ -42,6 +49,39 @@ const bytecode bytecode_test_cases[]{ }; } // namespace +template +class ja_test : public testing::Test +{}; + +using test_types = testing::Types; + +class NameGenerator +{ +public: + template + static std::string GetName(int) + { + return T::name; + } +}; + +TYPED_TEST_SUITE(ja_test, test_types, NameGenerator); + +TYPED_TEST(ja_test, validate) +{ + for (const auto& code : bytecode_test_cases) + { + const auto a0 = official_analyze_jumpdests(code.data(), code.size()); + const auto analysis = TypeParam::analyze(code); + + for (size_t i = 0; i < code.size() + tail_code_padding; ++i) + { + SCOPED_TRACE(i); + EXPECT_EQ(analysis.check_jumpdest(i), is_jumpdest(a0, i)); + } + } +} + TEST(jumpdest_analysis, compare_implementations) { for (const auto& t : bytecode_test_cases) @@ -50,7 +90,8 @@ TEST(jumpdest_analysis, compare_implementations) const auto data = t.data(); const auto data_size = t.size(); - const auto xxx = baseline::analyze({data, data_size}, false); + const auto xxx = JumpdestAnalysisImpl::analyze(t); + const auto a0 = official_analyze_jumpdests(data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); From 75adf91e5d951903fc28057e1d4ee02a444ebec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 11 Oct 2024 15:08:53 +0200 Subject: [PATCH 61/74] wrap official --- test/experimental/jumpdest_analysis.cpp | 15 +++++---------- test/experimental/jumpdest_analysis.hpp | 12 +++++++++++- test/unittests/jumpdest_analysis_test.cpp | 8 ++++---- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 0a72c866e0..ff27d724a8 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -4,7 +4,6 @@ #include "jumpdest_analysis.hpp" #include "opcode_manip.hpp" -#include #include #include #include @@ -12,19 +11,15 @@ namespace evmone::experimental { -JumpdestMap official_analyze_jumpdests(const uint8_t* code, size_t code_size) +JumpdestBitset official_analyze_jumpdests(bytes_view code) { - // To find if op is any PUSH opcode (OP_PUSH1 <= op <= OP_PUSH32) - // it can be noticed that OP_PUSH32 is INT8_MAX (0x7f) therefore - // static_cast(op) <= OP_PUSH32 is always true and can be skipped. - static_assert(OP_PUSH32 == std::numeric_limits::max()); + JumpdestBitset map(code.size()); - evmone::experimental::JumpdestMap map(code_size); // Allocate and init bitmap with zeros. - for (size_t i = 0; i < code_size; ++i) + for (size_t i = 0; i < code.size(); ++i) { const auto op = code[i]; - if (static_cast(op) >= OP_PUSH1) // If any PUSH opcode (see explanation above). - i += op - size_t{OP_PUSH1 - 1}; // Skip PUSH data. + if (static_cast(op) >= OP_PUSH1) + i += op - (OP_PUSH1 - 1); else if (__builtin_expect(op == OP_JUMPDEST, false)) map[i] = true; } diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index e6a523a2f4..0b38ec3dde 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -9,6 +9,16 @@ namespace evmone::experimental { +class JumpdestBitset : std::vector +{ +public: + using std::vector::operator[]; + + JumpdestBitset(size_t size) : std::vector(size) {} + + bool check_jumpdest(size_t index) const noexcept { return index < size() && (*this)[index]; } +}; + using JumpdestMap = std::vector; inline bool is_jumpdest(const JumpdestMap& jumpdest_map, size_t index) noexcept @@ -53,7 +63,7 @@ class bitset32 } }; -JumpdestMap official_analyze_jumpdests(const uint8_t* code, size_t code_size); +JumpdestBitset official_analyze_jumpdests(bytes_view code); std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index fe3dbc0874..3c0cb1878f 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -71,13 +71,13 @@ TYPED_TEST(ja_test, validate) { for (const auto& code : bytecode_test_cases) { - const auto a0 = official_analyze_jumpdests(code.data(), code.size()); + const auto expected = official_analyze_jumpdests(code); const auto analysis = TypeParam::analyze(code); for (size_t i = 0; i < code.size() + tail_code_padding; ++i) { SCOPED_TRACE(i); - EXPECT_EQ(analysis.check_jumpdest(i), is_jumpdest(a0, i)); + EXPECT_EQ(analysis.check_jumpdest(i), expected.check_jumpdest(i)); } } } @@ -92,7 +92,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto xxx = JumpdestAnalysisImpl::analyze(t); - const auto a0 = official_analyze_jumpdests(data, data_size); + const auto a0 = official_analyze_jumpdests(t); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); const auto x3 = build_jumpdest_map_vec3(data, data_size); @@ -115,7 +115,7 @@ TEST(jumpdest_analysis, compare_implementations) for (size_t i = 0; i < data_size + tail_code_padding; ++i) { SCOPED_TRACE(i); - const bool expected = is_jumpdest(a0, i); + const bool expected = a0.check_jumpdest(i); EXPECT_EQ(xxx.check_jumpdest(i), expected); EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); From 04fab22d33df02c3d9612e59303d61a4cbb5cca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 11 Oct 2024 16:04:22 +0200 Subject: [PATCH 62/74] rework benchmarks --- test/experimental/jumpdest_analysis.cpp | 5 ++- test/experimental/jumpdest_analysis.hpp | 2 +- test/internal_benchmarks/analysis_bench.cpp | 47 +++++++++++++++++++-- test/unittests/jumpdest_analysis_test.cpp | 10 +++-- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index ff27d724a8..d6ed80c4d7 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -104,9 +104,10 @@ std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size) return m; } -std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size) +JumpdestBitset build_jumpdest_map_sttni(bytes_view code) { - std::vector m(code_size); + const auto code_size = code.size(); + JumpdestBitset m(code_size); __m128i match_ranges{}; match_ranges = _mm_insert_epi8(match_ranges, OP_PUSH1, 0); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 0b38ec3dde..1cc9387c04 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -67,7 +67,7 @@ JumpdestBitset official_analyze_jumpdests(bytes_view code); std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size); -std::vector build_jumpdest_map_sttni(const uint8_t* code, size_t code_size); +JumpdestBitset build_jumpdest_map_sttni(bytes_view code); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask_v2(const uint8_t* code, size_t code_size); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index a451cc8f53..16a78d8599 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -775,10 +775,49 @@ void build_jumpdest(benchmark::State& state) static_cast(static_cast(test_bytecode.size()) * state.iterations()), Counter::kIsRate}; } + +template +void ja_bench(benchmark::State& state) +{ + for (auto _ : state) + { + auto r = T::analyze(test_bytecode); + benchmark::DoNotOptimize(r); + } + + using namespace benchmark; + state.counters["bytes"] = { + static_cast(static_cast(test_bytecode.size()) * state.iterations()), + Counter::kIsRate}; +} + +using namespace evmone::experimental; +using namespace evmone; + +struct JumpdestAnalysisImpl +{ + static constexpr auto name = "baseline"; + static auto analyze(bytes_view code) { return baseline::analyze(code, false); } +}; + +template +struct JumpdestAnalysisImpl2 +{ + // static constexpr auto name = "jumpdest_bitset_sttni"; + static auto analyze(bytes_view code) { return Fn(code); } +}; + } // namespace -BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, - evmone::experimental::official_analyze_jumpdests); +namespace +{ +using baseline = JumpdestAnalysisImpl; +BENCHMARK(ja_bench); +} // namespace +BENCHMARK(ja_bench>); + +// BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, +// evmone::experimental::official_analyze_jumpdests); BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, evmone::experimental::build_jumpdest_map_bitset1); BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2); @@ -789,8 +828,8 @@ BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec3); -BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); +// BENCHMARK_TEMPLATE( +// build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 3c0cb1878f..73b19353f1 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -19,6 +19,12 @@ struct JumpdestAnalysisImpl static auto analyze(bytes_view code) { return baseline::analyze(code, false); } }; +struct JumpdestAnalysisImpl2 +{ + static constexpr auto name = "jumpdest_bitset_sttni"; + static auto analyze(bytes_view code) { return build_jumpdest_map_sttni(code); } +}; + constexpr auto tail_code_padding = 100; @@ -53,7 +59,7 @@ template class ja_test : public testing::Test {}; -using test_types = testing::Types; +using test_types = testing::Types; class NameGenerator { @@ -96,7 +102,6 @@ TEST(jumpdest_analysis, compare_implementations) const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); const auto x3 = build_jumpdest_map_vec3(data, data_size); - const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto v5a = build_jumpdest_map_str_avx2_mask_v2(data, data_size); @@ -120,7 +125,6 @@ TEST(jumpdest_analysis, compare_implementations) EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); EXPECT_EQ(is_jumpdest(x3, i), expected); - EXPECT_EQ(is_jumpdest(v3, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); EXPECT_EQ(is_jumpdest(v5a, i), expected); From 8b8dae540e7a1fb2689c24e3f563eb2ed4230b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 11 Oct 2024 17:06:32 +0200 Subject: [PATCH 63/74] remove reduntant impls --- test/experimental/jumpdest_analysis.cpp | 28 --------------------- test/experimental/jumpdest_analysis.hpp | 2 -- test/experimental/opcode_manip.hpp | 3 +-- test/fuzzer/jumpdest_analysis_fuzz.cpp | 1 - test/internal_benchmarks/analysis_bench.cpp | 6 ----- test/unittests/jumpdest_analysis_test.cpp | 23 ++++++++--------- 6 files changed, 12 insertions(+), 51 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index d6ed80c4d7..1e65f6394b 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -61,20 +61,6 @@ static pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask return {pushdata_mask, 32}; } -std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size) -{ - std::vector m(code_size); - for (size_t i = 0; i < code_size; ++i) - { - const auto op = code[i]; - if (is_push(op)) - i += get_push_data_size(op); - else if (__builtin_expect(op == OP_JUMPDEST, false)) - m[i] = true; - } - return m; -} - std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) { std::vector m(code_size); @@ -90,20 +76,6 @@ std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) return m; } -std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size) -{ - std::vector m(code_size); - for (size_t i = 0; i < code_size; ++i) - { - const auto op = code[i]; - if (static_cast(op) >= static_cast(OP_PUSH1)) - i += get_push_data_size(op); - else if (__builtin_expect(op == OP_JUMPDEST, false)) - m[i] = true; - } - return m; -} - JumpdestBitset build_jumpdest_map_sttni(bytes_view code) { const auto code_size = code.size(); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 1cc9387c04..da268990b6 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -64,9 +64,7 @@ class bitset32 }; JumpdestBitset official_analyze_jumpdests(bytes_view code); -std::vector build_jumpdest_map_vec1(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); -std::vector build_jumpdest_map_vec3(const uint8_t* code, size_t code_size); JumpdestBitset build_jumpdest_map_sttni(bytes_view code); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp index 56ec873ed2..d847986b52 100644 --- a/test/experimental/opcode_manip.hpp +++ b/test/experimental/opcode_manip.hpp @@ -9,8 +9,7 @@ namespace evmone::experimental { inline constexpr bool is_push(uint8_t op) noexcept { - return (op & 0xe0) == 0x60; - // TODO: check what is better. return (op >> 5) == 0b11; + return static_cast(op) >= OP_PUSH1; } inline constexpr int find_first_push(const uint8_t* code) noexcept diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index f8fdcb0b9d..2cfe141c61 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -31,7 +31,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe const auto a0 = official_analyze_jumpdests(data, data_size); const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); - const auto x3 = build_jumpdest_map_vec3(data, data_size); const auto v3 = build_jumpdest_map_sttni(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 16a78d8599..35136cb428 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -796,14 +796,12 @@ using namespace evmone; struct JumpdestAnalysisImpl { - static constexpr auto name = "baseline"; static auto analyze(bytes_view code) { return baseline::analyze(code, false); } }; template struct JumpdestAnalysisImpl2 { - // static constexpr auto name = "jumpdest_bitset_sttni"; static auto analyze(bytes_view code) { return Fn(code); } }; @@ -822,12 +820,8 @@ BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, evmone::experimental::build_jumpdest_map_bitset1); BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); -BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec1); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); -BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec3); // BENCHMARK_TEMPLATE( // build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 73b19353f1..3130bacde1 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -13,17 +13,20 @@ using namespace evmone::test; namespace { -struct JumpdestAnalysisImpl +template +struct JAImpl { - static constexpr auto name = "baseline"; - static auto analyze(bytes_view code) { return baseline::analyze(code, false); } + static constexpr auto analyze = Fn; }; -struct JumpdestAnalysisImpl2 + +auto baseline_analyze(bytes_view code) { - static constexpr auto name = "jumpdest_bitset_sttni"; - static auto analyze(bytes_view code) { return build_jumpdest_map_sttni(code); } -}; + return baseline::analyze(code, false); +} + +using JumpdestAnalysisImpl = JAImpl; +using JumpdestAnalysisImpl2 = JAImpl; constexpr auto tail_code_padding = 100; @@ -71,7 +74,7 @@ class NameGenerator } }; -TYPED_TEST_SUITE(ja_test, test_types, NameGenerator); +TYPED_TEST_SUITE(ja_test, test_types); TYPED_TEST(ja_test, validate) { @@ -99,9 +102,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto xxx = JumpdestAnalysisImpl::analyze(t); const auto a0 = official_analyze_jumpdests(t); - const auto a2 = build_jumpdest_map_vec1(data, data_size); const auto v2 = build_jumpdest_map_vec2(data, data_size); - const auto x3 = build_jumpdest_map_vec3(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto v5a = build_jumpdest_map_str_avx2_mask_v2(data, data_size); @@ -122,9 +123,7 @@ TEST(jumpdest_analysis, compare_implementations) SCOPED_TRACE(i); const bool expected = a0.check_jumpdest(i); EXPECT_EQ(xxx.check_jumpdest(i), expected); - EXPECT_EQ(is_jumpdest(a2, i), expected); EXPECT_EQ(is_jumpdest(v2, i), expected); - EXPECT_EQ(is_jumpdest(x3, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); EXPECT_EQ(is_jumpdest(v5a, i), expected); From f68c1be3bfaf49c7d0e5ec9e1687664cab4596bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 09:36:22 +0200 Subject: [PATCH 64/74] rename jda reference --- test/experimental/jumpdest_analysis.cpp | 6 ++---- test/experimental/jumpdest_analysis.hpp | 2 +- test/fuzzer/jumpdest_analysis_fuzz.cpp | 12 +++++------- test/unittests/jumpdest_analysis_test.cpp | 4 ++-- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 1e65f6394b..24021d16ad 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -11,19 +11,17 @@ namespace evmone::experimental { -JumpdestBitset official_analyze_jumpdests(bytes_view code) +JumpdestBitset jda_reference(bytes_view code) { JumpdestBitset map(code.size()); - for (size_t i = 0; i < code.size(); ++i) { const auto op = code[i]; if (static_cast(op) >= OP_PUSH1) i += op - (OP_PUSH1 - 1); - else if (__builtin_expect(op == OP_JUMPDEST, false)) + else if (op == OP_JUMPDEST) [[unlikely]] map[i] = true; } - return map; } diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index da268990b6..cdcb020853 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -63,7 +63,7 @@ class bitset32 } }; -JumpdestBitset official_analyze_jumpdests(bytes_view code); +JumpdestBitset jda_reference(bytes_view code); std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); JumpdestBitset build_jumpdest_map_sttni(bytes_view code); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 2cfe141c61..554f7e60ea 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -28,10 +28,10 @@ inline bool is_jumpdest(const bitset32& a, size_t index) noexcept extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noexcept { - const auto a0 = official_analyze_jumpdests(data, data_size); - const auto a2 = build_jumpdest_map_vec1(data, data_size); + const bytes_view code{data, data_size}; + const auto a0 = jda_reference(code); const auto v2 = build_jumpdest_map_vec2(data, data_size); - const auto v3 = build_jumpdest_map_sttni(data, data_size); + const auto v3 = build_jumpdest_map_sttni(code); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto v6 = build_jumpdest_map_str_avx2_mask2(data, data_size); @@ -48,11 +48,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe for (size_t i = 0; i < data_size + tail_code_padding; ++i) { - const bool expected = is_jumpdest(a0, i); - EXPECT_EQ(is_jumpdest(a2, i), expected); + const bool expected = a0.check_jumpdest(i); EXPECT_EQ(is_jumpdest(v2, i), expected); - EXPECT_EQ(is_jumpdest(x3, i), expected); - EXPECT_EQ(is_jumpdest(v3, i), expected); + EXPECT_EQ(v3.check_jumpdest(i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); EXPECT_EQ(is_jumpdest(v6, i), expected); diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 3130bacde1..f10c5a564d 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -80,7 +80,7 @@ TYPED_TEST(ja_test, validate) { for (const auto& code : bytecode_test_cases) { - const auto expected = official_analyze_jumpdests(code); + const auto expected = jda_reference(code); const auto analysis = TypeParam::analyze(code); for (size_t i = 0; i < code.size() + tail_code_padding; ++i) @@ -101,7 +101,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto xxx = JumpdestAnalysisImpl::analyze(t); - const auto a0 = official_analyze_jumpdests(t); + const auto a0 = jda_reference(t); const auto v2 = build_jumpdest_map_vec2(data, data_size); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); From 5391e0b55efebfd07052ad1f59a7bbd8c5a7a53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 09:44:30 +0200 Subject: [PATCH 65/74] clean up tests --- test/unittests/jumpdest_analysis_test.cpp | 49 ++++++++--------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index f10c5a564d..36d1976c3f 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -13,32 +13,21 @@ using namespace evmone::test; namespace { -template -struct JAImpl -{ - static constexpr auto analyze = Fn; -}; - +constexpr auto CODE_PADDING_CHECK_SIZE = 100; auto baseline_analyze(bytes_view code) { return baseline::analyze(code, false); } -using JumpdestAnalysisImpl = JAImpl; -using JumpdestAnalysisImpl2 = JAImpl; - - -constexpr auto tail_code_padding = 100; - -inline bool is_jumpdest(const bitset32& a, size_t index) noexcept +bool is_jumpdest(const bitset32& a, size_t index) noexcept { return (index < a.size() && a[index]); } const bytecode bytecode_test_cases[]{ - push(0x5b), {}, + push(0x5b), OP_JUMPDEST, push(0), push(0x5b) + OP_JUMPDEST, @@ -58,32 +47,28 @@ const bytecode bytecode_test_cases[]{ }; } // namespace -template -class ja_test : public testing::Test -{}; - -using test_types = testing::Types; - -class NameGenerator +/// Wrapper for jumpdest analysis implementations suitable for typed tests. +template +struct I { -public: - template - static std::string GetName(int) - { - return T::name; - } + static constexpr auto analyze = Fn; }; -TYPED_TEST_SUITE(ja_test, test_types); +template +class jumpdest_analysis_test : public testing::Test +{}; +using test_types = testing::Types, + I>; +TYPED_TEST_SUITE(jumpdest_analysis_test, test_types); -TYPED_TEST(ja_test, validate) +TYPED_TEST(jumpdest_analysis_test, validate) { for (const auto& code : bytecode_test_cases) { const auto expected = jda_reference(code); const auto analysis = TypeParam::analyze(code); - for (size_t i = 0; i < code.size() + tail_code_padding; ++i) + for (size_t i = 0; i < code.size() + CODE_PADDING_CHECK_SIZE; ++i) { SCOPED_TRACE(i); EXPECT_EQ(analysis.check_jumpdest(i), expected.check_jumpdest(i)); @@ -99,7 +84,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto data = t.data(); const auto data_size = t.size(); - const auto xxx = JumpdestAnalysisImpl::analyze(t); + const auto xxx = I::analyze(t); const auto a0 = jda_reference(t); const auto v2 = build_jumpdest_map_vec2(data, data_size); @@ -118,7 +103,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto s3 = build_jumpdest_map_simd3(data, data_size); const auto s4 = build_jumpdest_map_simd4(data, data_size); - for (size_t i = 0; i < data_size + tail_code_padding; ++i) + for (size_t i = 0; i < data_size + CODE_PADDING_CHECK_SIZE; ++i) { SCOPED_TRACE(i); const bool expected = a0.check_jumpdest(i); From 0d8165db485c4e97a1ec824ed3aca26addcaedc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 09:57:26 +0200 Subject: [PATCH 66/74] speculate jda --- test/experimental/jumpdest_analysis.cpp | 8 ++++---- test/experimental/jumpdest_analysis.hpp | 2 +- test/fuzzer/jumpdest_analysis_fuzz.cpp | 4 ++-- test/internal_benchmarks/analysis_bench.cpp | 2 +- test/unittests/jumpdest_analysis_test.cpp | 8 ++------ 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 24021d16ad..8ef33ef6d7 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -59,16 +59,16 @@ static pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask return {pushdata_mask, 32}; } -std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size) +JumpdestBitset jda_speculate_push_data_size(bytes_view code) { - std::vector m(code_size); - for (size_t i = 0; i < code_size; ++i) + JumpdestBitset m(code.size()); + for (size_t i = 0; i < code.size(); ++i) { const auto op = code[i]; const auto potential_push_data_len = get_push_data_size(op); if (potential_push_data_len <= 32) i += potential_push_data_len; - else if (__builtin_expect(op == OP_JUMPDEST, false)) + else if (op == OP_JUMPDEST) [[unlikely]] m[i] = true; } return m; diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index cdcb020853..1af19f2466 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -64,7 +64,7 @@ class bitset32 }; JumpdestBitset jda_reference(bytes_view code); -std::vector build_jumpdest_map_vec2(const uint8_t* code, size_t code_size); +JumpdestBitset jda_speculate_push_data_size(bytes_view code); JumpdestBitset build_jumpdest_map_sttni(bytes_view code); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index 554f7e60ea..d539175155 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -30,7 +30,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe { const bytes_view code{data, data_size}; const auto a0 = jda_reference(code); - const auto v2 = build_jumpdest_map_vec2(data, data_size); + const auto v2 = jda_speculate_push_data_size(data); const auto v3 = build_jumpdest_map_sttni(code); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); @@ -49,7 +49,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noe for (size_t i = 0; i < data_size + tail_code_padding; ++i) { const bool expected = a0.check_jumpdest(i); - EXPECT_EQ(is_jumpdest(v2, i), expected); + EXPECT_EQ(v2.check_jumpdest(i), expected); EXPECT_EQ(v3.check_jumpdest(i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 35136cb428..60c3f98fac 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -821,7 +821,7 @@ BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_vec2); + build_jumpdest, std::vector, evmone::experimental::jda_speculate_push_data_size); // BENCHMARK_TEMPLATE( // build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 36d1976c3f..2890bae977 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -58,7 +58,7 @@ template class jumpdest_analysis_test : public testing::Test {}; using test_types = testing::Types, - I>; + I, I>; TYPED_TEST_SUITE(jumpdest_analysis_test, test_types); TYPED_TEST(jumpdest_analysis_test, validate) @@ -84,10 +84,8 @@ TEST(jumpdest_analysis, compare_implementations) const auto data = t.data(); const auto data_size = t.size(); - const auto xxx = I::analyze(t); - const auto a0 = jda_reference(t); - const auto v2 = build_jumpdest_map_vec2(data, data_size); + const auto v2 = jda_speculate_push_data_size(data); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto v5a = build_jumpdest_map_str_avx2_mask_v2(data, data_size); @@ -107,8 +105,6 @@ TEST(jumpdest_analysis, compare_implementations) { SCOPED_TRACE(i); const bool expected = a0.check_jumpdest(i); - EXPECT_EQ(xxx.check_jumpdest(i), expected); - EXPECT_EQ(is_jumpdest(v2, i), expected); EXPECT_EQ(is_jumpdest(v4, i), expected); EXPECT_EQ(is_jumpdest(v5, i), expected); EXPECT_EQ(is_jumpdest(v5a, i), expected); From ca77b358ba04e6023ebdc226a510af79ca3d73c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 10:11:01 +0200 Subject: [PATCH 67/74] bench --- test/internal_benchmarks/analysis_bench.cpp | 42 ++++++--------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 60c3f98fac..e55749f9d3 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -776,54 +776,34 @@ void build_jumpdest(benchmark::State& state) Counter::kIsRate}; } -template -void ja_bench(benchmark::State& state) +using namespace evmone; +using namespace evmone::experimental; +using namespace benchmark; + +template +void jumpdest_analysis(State& state) { for (auto _ : state) { - auto r = T::analyze(test_bytecode); - benchmark::DoNotOptimize(r); + auto r = AnalyzeFn(test_bytecode); + DoNotOptimize(r); } - using namespace benchmark; state.counters["bytes"] = { static_cast(static_cast(test_bytecode.size()) * state.iterations()), Counter::kIsRate}; } -using namespace evmone::experimental; -using namespace evmone; - -struct JumpdestAnalysisImpl -{ - static auto analyze(bytes_view code) { return baseline::analyze(code, false); } -}; - -template -struct JumpdestAnalysisImpl2 -{ - static auto analyze(bytes_view code) { return Fn(code); } -}; - } // namespace -namespace -{ -using baseline = JumpdestAnalysisImpl; -BENCHMARK(ja_bench); -} // namespace -BENCHMARK(ja_bench>); +BENCHMARK(jumpdest_analysis); +BENCHMARK(jumpdest_analysis); +BENCHMARK(jumpdest_analysis); -// BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, -// evmone::experimental::official_analyze_jumpdests); BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, evmone::experimental::build_jumpdest_map_bitset1); BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2); BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); -BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::jda_speculate_push_data_size); -// BENCHMARK_TEMPLATE( -// build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_sttni); BENCHMARK_TEMPLATE( build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); BENCHMARK_TEMPLATE( From 8528a4ac2cc2d9b2ce8cd5e2d75c297a143fbfef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 20:45:53 +0200 Subject: [PATCH 68/74] add more bench cases --- test/internal_benchmarks/analysis_bench.cpp | 199 ++++++++++++-------- 1 file changed, 118 insertions(+), 81 deletions(-) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index e55749f9d3..51d9d47127 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -12,11 +12,34 @@ #include #include +using namespace evmone::test; + namespace { -// blake2_shifts + weierstrudel + sha1_div. -const auto test_bytecode = *evmc::from_hex( +const std::array test_bytecodes = { + // WETH: + "0x6060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014757806318160ddd146101a157806323b872dd146101ca5780632e1a7d4d14610243578063313ce5671461026657806370a082311461029557806395d89b41146102e2578063a9059cbb14610370578063d0e30db0146103ca578063dd62ed3e146103d4575b6100b7610440565b005b34156100c457600080fd5b6100cc6104dd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010c5780820151818401526020810190506100f1565b50505050905090810190601f1680156101395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015257600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061057b565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461066d565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b610229600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061068c565b604051808215151515815260200191505060405180910390f35b341561024e57600080fd5b61026460048080359060200190919050506109d9565b005b341561027157600080fd5b610279610b05565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a057600080fd5b6102cc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b18565b6040518082815260200191505060405180910390f35b34156102ed57600080fd5b6102f5610b30565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561033557808201518184015260208101905061031a565b50505050905090810190601f1680156103625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561037b57600080fd5b6103b0600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610bce565b604051808215151515815260200191505060405180910390f35b6103d2610440565b005b34156103df57600080fd5b61042a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610be3565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105735780601f1061054857610100808354040283529160200191610573565b820191906000526020600020905b81548152906001019060200180831161055657829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156106dc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156107b457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156108cf5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084457600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a2757600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515610ab457600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bc65780601f10610b9b57610100808354040283529160200191610bc6565b820191906000526020600020905b815481529060010190602001808311610ba957829003601f168201915b505050505081565b6000610bdb33848461068c565b905092915050565b60046020528160005260406000206020528060005260406000206000915091505054815600a165627a7a72305820deb4c2ccab3c2fdca32ab3f46728389c2fe2c165d5fafa07661e4e004f6c344a0029"_hex, + + // Uniswap V2: https://etherscan.io/address/0x00004ee988665cdda9a1080d5792cecd16dc1220 + "0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032"_hex, + + // Uniswap: Universal Router: 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD + "0x60a0604081815260049081361015610022575b505050361561002057600080fd5b005b600092833560e01c90816301ffc9a71461093d57508063150b7a02146108af57806324856bc3146107e85780633593564c146106b1578063709a1cc21461044f578063bc197c811461038a578063f23a6e61146102f95763fa461e330361001257346102f55760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f557813590602435926044359067ffffffffffffffff918281116102f1576100db9036908301610a97565b919092878613908115806102e7575b6102bf5783850186868203126102bb5785359182116102bb5761010e9186016136d0565b5060208401359373ffffffffffffffffffffffffffffffffffffffff938486168096036102bb5761013e9161415a565b959097602b89106102935786359260178460601c98019561016d62ffffff883560601c9660481c16868b614365565b3391160361026b571561026157508186105b15610197575050505061019493503391613ac2565b80f35b9395945091929091906042871061021b5750505083601711610217577f8000000000000000000000000000000000000000000000000000000000000000821015610217577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe961021194019161020c33916141b5565b6141e2565b50505080f35b8480fd5b91969550929391508454841161023957506101949394503391613ac2565b8590517f739dbe52000000000000000000000000000000000000000000000000000000008152fd5b965085821061017f565b8483517f32b13d91000000000000000000000000000000000000000000000000000000008152fd5b8382517f3b99b53d000000000000000000000000000000000000000000000000000000008152fd5b8980fd5b8286517f316cf0eb000000000000000000000000000000000000000000000000000000008152fd5b50888813156100ea565b8680fd5b8280fd5b5082346103875760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038757610332610a2b565b5061033b610a53565b506084359067ffffffffffffffff8211610387575060209261035f91369101610a97565b5050517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b80fd5b5082346103875760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610387576103c3610a2b565b506103cc610a53565b5067ffffffffffffffff9060443582811161044b576103ee9036908601610ac5565b505060643582811161044b576104079036908601610ac5565b5050608435918211610387575060209261042391369101610a97565b5050517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b5080fd5b50346102f557602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106ad5783833567ffffffffffffffff811161044b576104a1829136908701610a97565b90818551928392833781018381520390827f0000000000000000000000000554f068365ed43dcc98dcd7fd7a8208a5638c725af16104dd613675565b50156106855780517f70a082310000000000000000000000000000000000000000000000000000000081523084820152907f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e73ffffffffffffffffffffffffffffffffffffffff168383602481845afa92831561067b578693610646575b5081517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ea37093ce161f090e443f304e1bf3a8f14d7bb40169581019586526020860184905294849186918290899082906040015b03925af193841561063c577f1e8f03f716bc104bf7d728131967a0c771e85ab54d09c1e2d6ed9e0bc4e2a16c9461060f575b5051908152a180f35b61062e90843d8611610635575b61062681836135fa565b81019061388d565b5038610606565b503d61061c565b81513d87823e3d90fd5b9092508381813d8311610674575b61065e81836135fa565b810103126106705751916105d461055b565b8580fd5b503d610654565b82513d88823e3d90fd5b9050517f7d529919000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f55767ffffffffffffffff8235818111610217576106fb9036908501610a97565b91602435908111610670576107139036908601610ac5565b92909160443542116107c0573330146107b1576001958654958773ffffffffffffffffffffffffffffffffffffffff88160361078b5750509185949391610782937fffffffffffffffffffffffff00000000000000000000000000000000000000009586339116178755610b54565b81541617905580f35b517f6f5ffb7e000000000000000000000000000000000000000000000000000000008152fd5b90919293506101949450610b54565b8585517f5bf6f916000000000000000000000000000000000000000000000000000000008152fd5b50807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f55767ffffffffffffffff8235818111610217576108319036908501610a97565b91602435908111610670576108499036908601610ac5565b9290913330146107b1576001958654958773ffffffffffffffffffffffffffffffffffffffff88160361078b5750509185949391610782937fffffffffffffffffffffffff00000000000000000000000000000000000000009586339116178755610b54565b5082346103875760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610387576108e8610a2b565b506108f1610a53565b506064359067ffffffffffffffff8211610387575060209261091591369101610a97565b5050517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b849084346102f55760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f557357fffffffff0000000000000000000000000000000000000000000000000000000081168091036102f557602092507f4e2312e0000000000000000000000000000000000000000000000000000000008114908115610a01575b81156109d7575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836109d0565b7f150b7a0200000000000000000000000000000000000000000000000000000000811491506109c9565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b9181601f84011215610a4e5782359167ffffffffffffffff8311610a4e5760208381860195010111610a4e57565b9181601f84011215610a4e5782359167ffffffffffffffff8311610a4e576020808501948460051b010111610a4e57565b919082519283825260005b848110610b405750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201610b01565b9192909260805282810361350d5791906000905b828210610b755750505050565b8382959394951015611b4c5760059282841b60805101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe19182608051360301821215610a4e578160805101359767ffffffffffffffff8911610a4e576020836080510101988036038a13610a4e57606097603f90818989013560f81c166001976020821060001461317157506010808210156127b4575060088082101561187e57508061109157505050610c2a908a614198565b92909860a08560805101013560001461108757610c6173ffffffffffffffffffffffffffffffffffffffff600154169b5b35613854565b9960408660805101013585829d927f80000000000000000000000000000000000000000000000000000000000000008314610fcf575b50959c95505b7f8000000000000000000000000000000000000000000000000000000000000000811015610a4e5760428610610fc85730915b86602b11610a4e578d91601783013560601c9083359462ffffff8660601c96610d1573ffffffffffffffffffffffffffffffffffffffff92839260481c16868a614365565b169084881015610fac57806401000276a4965b602b60405199604060208c01528160608c015260808b0137600060ab8a015216604088015260a0875260c087019587871067ffffffffffffffff881117610f7d576040948288958688527f128acb080000000000000000000000000000000000000000000000000000000087521660c48a0152868a1060e48a01526101048901521661012487015260a06101448701528160007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4088610deb610164820182610af6565b0301925af1928315610f71576000928394610f2f575b5050610e159310600014610f2857506141b5565b9a60428510610e5657309085601711610a4e5760177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe991019501949b610c9d565b50985098606091969597949392509160805101013511610efe575b1580610ed1575b610e8a57506001019291929092610b68565b90610ecd60409283519384937f2c4029e9000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190610af6565b0390fd5b507f8000000000000000000000000000000000000000000000000000000000000000828501351615610e78565b60046040517f39d35496000000000000000000000000000000000000000000000000000000008152fd5b90506141b5565b91929093506040843d604011610f69575b81610f4d604093866135fa565b8101031261038757505160e092909201519190610e1538610e01565b3d9150610f40565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8073fffd8963efd1fc6a506488495d951d5263988d2596610d28565b8b91610cd0565b60149192501061105d576020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301523560601c5afa908115610f715760009161102b575b503880610c97565b906020823d602011611055575b81611045602093836135fa565b8101031261038757505138611023565b3d9150611038565b60046040517f3b99b53d000000000000000000000000000000000000000000000000000000008152fd5b610c61309b610c5b565b6001819d969d9b989794959a999b146000146111b7575050506040926110bf84836080510101359382614198565b608051840160a00135156111ab5760606110f273ffffffffffffffffffffffffffffffffffffffff600154169435613854565b946080510101356000557f8000000000000000000000000000000000000000000000000000000000000000851015610a4e576111319361020c866141b5565b9091901561119c5750611143906141b5565b0361117357507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000555b610e71565b600490517fd4e0248e000000000000000000000000000000000000000000000000000000008152fd5b6111a691506141b5565b611143565b60606110f23094610c5b565b9194929391600281036112065750505061116e925073ffffffffffffffffffffffffffffffffffffffff600154166111ff604060608560805101013594608051010135613854565b91356139d0565b9193916003810361157857505060805181018084019390604090850312610a4e57823567ffffffffffffffff8111610a4e5782608051010192606084860312610a4e57604051946060860186811067ffffffffffffffff821117610f7d57604052602085013567ffffffffffffffff8111610a4e57850160208201809882011215610a4e5760208101359061129a826136a5565b926112a860405194856135fa565b8284526040602085019360071b830101918a8311610a4e57604001925b828410611513575050505085526112de60408501610a76565b956020860196875260606040870195013585526040846080510101359067ffffffffffffffff8211610a4e57602061131f92611325966080510101016136d0565b5061417b565b909173ffffffffffffffffffffffffffffffffffffffff600154169473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3163b15610a4e5794929391906040519586947f2a2d80d100000000000000000000000000000000000000000000000000000000865260048601526060602486015260c48501935193606060648701528451809152602060e487019501906000905b80821061149a575050509461143e9285949273ffffffffffffffffffffffffffffffffffffffff600098511660848701525160a48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc858403016044860152613537565b03818373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3165af18015610f715761148b575b50610e71565b61149490613576565b38611485565b9197965091929394602060806001928a5173ffffffffffffffffffffffffffffffffffffffff815116825273ffffffffffffffffffffffffffffffffffffffff848201511684830152606065ffffffffffff918260408201511660408501520151166060820152019801920188969795949392916113d8565b608060208584030112610a4e5760206080916040516115318161358a565b61153a87610a76565b8152611547838801610a76565b83820152611557604088016136bd565b6040820152611568606088016136bd565b60608201528152019301926112c5565b600495509193508482036116e757505090916040606061159e8286608051010135613854565b608051909501013573ffffffffffffffffffffffffffffffffffffffff908116933516806116145750479283106115ee575050806115de575b5050610e71565b6115e7916144d1565b38806115d7565b517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b9391908051937f70a082310000000000000000000000000000000000000000000000000000000085523083860152602085602481895afa9485156116dc576000956116a8575b50841061168257505081611671575b505050610e71565b61167a9261453f565b388080611669565b517f675cae38000000000000000000000000000000000000000000000000000000008152fd5b90946020823d6020116116d4575b816116c3602093836135fa565b81010312610387575051933861165a565b3d91506116b6565b82513d6000823e3d90fd5b8103611714575061116e925061170d604060608460805101013593608051010135613854565b90356138a5565b9091906006810361184e57506080510160608101359060409061173990820135613854565b9282158015611843575b61181b573573ffffffffffffffffffffffffffffffffffffffff16938461177f57505061116e92506117786127109147613984565b04906144d1565b8151907f70a082310000000000000000000000000000000000000000000000000000000082523090820152602081602481885afa91821561181157506000916117dd575b506117d661116e94939261271092613984565b049161453f565b906020823d602011611809575b816117f7602093836135fa565b810103126103875750516117d66117c3565b3d91506117ea565b513d6000823e3d90fd5b8482517fdeaa01e6000000000000000000000000000000000000000000000000000000008152fd5b506127108311611743565b83602491604051917fd76a1e9e000000000000000000000000000000000000000000000000000000008352820152fd5b819d969d9b989794959a999b93929314600014611b85575050506040916118ad83836080510101359185614198565b92909460a082608051010135600014611b7b576118e373ffffffffffffffffffffffffffffffffffffffff600154169135613854565b908615611b4c576118f385613a94565b8760011015611b4c5761191561195d9161190f60208901613a94565b90613c34565b907f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b938481611b32575b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff860193868511611b03576119b9946119be73ffffffffffffffffffffffffffffffffffffffff9687928a85613a84565b613a94565b16948651947f70a082310000000000000000000000000000000000000000000000000000000091828752841693600499858b89015260249460208987818d5afa988915611af857600099611ac3575b509160209695949391611a1f93613cad565b8751968793849283528a8301525afa928315611ab857600093611a83575b50906060611a519260805101013592613ab5565b10611a5d575050610e71565b517f849eaf98000000000000000000000000000000000000000000000000000000008152fd5b90926020823d602011611ab0575b81611a9e602093836135fa565b81010312610387575051916060611a3d565b3d9150611a91565b84513d6000823e3d90fd5b90986020823d602011611af0575b81611ade602093836135fa565b81010312610387575051976020611a0d565b3d9150611ad1565b8b513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611b4492611b3f88613a94565b613ac2565b388084611965565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6118e33091610c5b565b919492939160098103611f66575050611b9e9082614198565b608051840160a0013515611f5c57611bcf73ffffffffffffffffffffffffffffffffffffffff600154169335613854565b92611bd9836136a5565b95611be760405197886135fa565b83875283901b820160208701368211610a4e5783905b828210611f44575050506000946002875110611f1a576040816080510101359680517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111611b035790815b611ca757505060805101606001358611611c7d578215611b4c5761116e9585611c7892611b3f85613a94565b613cad565b60046040517f8ab0bc16000000000000000000000000000000000000000000000000000000008152fd5b90977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89019750888811611b035773ffffffffffffffffffffffffffffffffffffffff611cf7611d6d9984613a70565b5116611d2373ffffffffffffffffffffffffffffffffffffffff611d1b8c86613a70565b511682613c34565b819a917f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b90604051907f0902f1ac00000000000000000000000000000000000000000000000000000000825260608260048173ffffffffffffffffffffffffffffffffffffffff87165afa9a8b15610f7157600092839c611ed1575b5073ffffffffffffffffffffffffffffffffffffffff1603611eb7576dffffffffffffffffffffffffffff8091169916905b9880158015611eaf575b611e855782611e0f91613984565b916103e892838102938185041490151715611b0357611e2d91613ab5565b6103e590818102918183041490151715611b0357611e4a91613997565b60018101809111611b0357978015611b03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019081611c4c565b60046040517f7b9c8916000000000000000000000000000000000000000000000000000000008152fd5b508115611e01565b6dffffffffffffffffffffffffffff998a16991690611df7565b611f0a919c5073ffffffffffffffffffffffffffffffffffffffff935060603d8111611f13575b611f0281836135fa565b810190613c77565b509b9092611dc5565b503d611ef8565b60046040517f20db8267000000000000000000000000000000000000000000000000000000008152fd5b60208091611f5184610a76565b815201910190611bfd565b611bcf3093610c5b565b92945091600a81036120cc5750608051830160e08101358101946020808701359450909291611f9991908703018461414d565b1161105d5773ffffffffffffffffffffffffffffffffffffffff93847f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31692856001541691843b15610a4e5760409587875198899687967f2b67b570000000000000000000000000000000000000000000000000000000008852600488015261202190610a76565b166024860152808883608051010161203890610a76565b16604486015265ffffffffffff808360805101606001612057906136bd565b166064870152826080510160800161206e906136bd565b166084860152816080510160a00161208590610a76565b1660a48501526080510160c0013560c484015261010060e48401526120b1916101048401918701613537565b03815a6000948591f1908115611811575061148b5750610e71565b600b8103612296575050506120eb604080926080510101359235613854565b91807f80000000000000000000000000000000000000000000000000000000000000008103612266575050475b8061212557505050610e71565b73ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610a4e578351927fd0e30db0000000000000000000000000000000000000000000000000000000008452600493600081868187875af1801561225b5761224c575b5030908616036121b4575b5050611669565b6122139460006020948651978895869485937fa9059cbb00000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1908115611811575061222d575b808080806121ad565b6122459060203d6020116106355761062681836135fa565b5038612224565b61225590613576565b386121a2565b86513d6000823e3d90fd5b47101561211857600482517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b600c810361242657505050906122ac9035613854565b9073ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660408051937f70a08231000000000000000000000000000000000000000000000000000000008552600430818701526024916020878481885afa968715611ab8576000976123f2575b506080510183013586106123cb578561234e575b50505050505050610e71565b833b15610a4e57600091869183855196879485937f2e1a7d4d0000000000000000000000000000000000000000000000000000000085528401525af190811561181157506123bc575b5030908316036123ac575b8080808080612342565b6123b5916144d1565b38806123a2565b6123c590613576565b38612397565b82517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b90966020823d60201161241e575b8161240d602093836135fa565b81010312610387575051958361232e565b3d9150612400565b600d8103612681575082608051010191602083019360208260805101850312610a4e573567ffffffffffffffff8111610a4e57849160805101019182011215610a4e57602081013590612478826136a5565b93604093612488855196876135fa565b838652602086019285849560071b820101928311610a4e578501925b82841061261f575050505073ffffffffffffffffffffffffffffffffffffffff90816001541684519060005b8281106125b357505050817f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31691823b15610a4e5783517f0d58b1db000000000000000000000000000000000000000000000000000000008152602060048201529451602486018190528592604484019290916000915b81831061256f57505050509181600081819503925af1908115611811575061148b5750610e71565b91938395506080602091846060600195975182815116845282868201511686850152828d820151168d85015201511660608201520195019301909187949392612547565b81856125bf838a613a70565b515116036125f6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611b03576001016124d0565b600486517fe7002877000000000000000000000000000000000000000000000000000000008152fd5b608060208584030112610a4e576020608091875161263c8161358a565b61264587610a76565b8152612652838801610a76565b83820152612661898801610a76565b8982015261267160608801610a76565b60608201528152019301926124a4565b9294505050600e810361278357506040918251907f70a0823100000000000000000000000000000000000000000000000000000000825260208260248173ffffffffffffffffffffffffffffffffffffffff806004983516888301528886608051010135165afa918215611ab85760009261274e575b5060805101606001351180159290612710575050610e71565b517fa3281672000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b9038806115d7565b90916020823d60201161277b575b81612769602093836135fa565b810103126103875750519060606126f7565b3d915061275c565b602490604051907fd76a1e9e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9150915060189b95939897999692949b808310600014612d435750810361282a5750505060009250906127e883928261417b565b81604051928392833781018481520391357f00000000000000000000000000000000000000adc04c56bf30ac9d3c0aaf14dc5af1612824613675565b90610e71565b6011810361288157505050600092509061284583928261417b565b81604051928392833781018481520391357f0000000000000000000000000000000000e655fae4d56241588680f86e3b23775af1612824613675565b601281036128d857505050600092509061289c83928261417b565b81604051928392833781018481520391357f000000000000000000000000941a6d105802cccaa06de58a13a6f49ebdcd481c5af1612824613675565b919392509060138103612a3e575050909150357f000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb916040600080825160208101907f8264fe9800000000000000000000000000000000000000000000000000000000825260248781830152815261294e816135de565b5190606086608051010135885af192612965613675565b948415612a04578273ffffffffffffffffffffffffffffffffffffffff612993921694608051010135613854565b90833b15610a4e5782517f8b72a2ec00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301526024820152916000908390604490829084905af1908115611811575061148b5750610e71565b505091925050517fae9bdf0000000000000000000000000000000000000000000000000000000000602082015260048152612824816135c2565b60158103612b4f57505090604091828051917f6352211e0000000000000000000000000000000000000000000000000000000083526020836024816004976060816080510101358983015273ffffffffffffffffffffffffffffffffffffffff968791608051010135165afa928315612b4457600093612b05575b5081903516911614918215612acf575050610e71565b517f7dbe7e89000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b6020939193813d602011612b3c575b81612b21602093836135fa565b8101031261044b575190828216820361038757509181612ab9565b3d9150612b14565b85513d6000823e3d90fd5b60168103612c765750506040918251907efdd58e00000000000000000000000000000000000000000000000000000000825260208280612bc160049660608660805101013590358884016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b038173ffffffffffffffffffffffffffffffffffffffff8886608051010135165afa918215611ab857600092612c41575b5060809081510101351191821592612c0b575050610e71565b517f483a6929000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b90916020823d602011612c6e575b81612c5c602093836135fa565b81010312610387575051906080612bf2565b3d9150612c4f565b909290601714612c87575050610e71565b60409073ffffffffffffffffffffffffffffffffffffffff612caf8383608051010135613854565b93351692833b15610a4e5782517f42842e0e00000000000000000000000000000000000000000000000000000000815260805130600483015273ffffffffffffffffffffffffffffffffffffffff909216602482015291016060013560448201529160009083908183816064810103925af19081156118115750612d34575b806115d7565b612d3d90613576565b38612d2e565b9396938214159050612d7e5750505061282492507f00000000000000000000000074312363e45dcaba76c59ec49a7aa8a65a67eed391613717565b60198103612dd5575050506000925090612d9983928261417b565b81604051928392833781018481520391357f0000000000000000000000002b2e8cda09bba9660dca5cb6233787738ad683295af1612824613675565b601a8103612e2c575050506000925090612df083928261417b565b81604051928392833781018481520391357f000000000000000000000000a42f6cada809bcf417deefbdd69c5c5a909249c05af1612824613675565b601b8103612f53575050506000612e4481928461417b565b9390604094818651928392833781018481520391357f00000000000000000000000074312363e45dcaba76c59ec49a7aa8a65a67eed35af1918291612e87613675565b92612e95575b505090610e71565b73ffffffffffffffffffffffffffffffffffffffff608083815101013516612ec4606084608051010135613854565b90825190612ed1826135a6565b60008252803b15610a4e57612f2d94600080948651978895869485937ff242432a00000000000000000000000000000000000000000000000000000000855260a060c0836080510101359260805101013590306004870161380f565b03925af19081156118115750612f44575b80612e8d565b612f4d90613576565b38612f3e565b91949091601c8103612f8e5750505061282492507f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f91613717565b9193929091601d81036131175750506060816080510101359060409173ffffffffffffffffffffffffffffffffffffffff612fcf8484608051010135613854565b9435168351947efdd58e0000000000000000000000000000000000000000000000000000000086526004936020878061302e87308a84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b0381865afa96871561225b576000976130e2575b50608090815101013586106130ba57845161305c816135a6565b60008152823b15610a4e576000946130a486928851998a97889687957ff242432a0000000000000000000000000000000000000000000000000000000087523090870161380f565b03925af1908115611811575061148b5750610e71565b8385517f675cae38000000000000000000000000000000000000000000000000000000008152fd5b90966020823d60201161310f575b816130fd602093836135fa565b81010312610387575051956080613042565b3d91506130f0565b929450925050601e810361278357508161313560009392849361417b565b81604051928392833781018481520391357f00000000000000000000000020f780a973856b93f63670377900c1d2a50a77c45af1612824613675565b9499989a92506020819d9792969d989498146000146131da575050505050508061319e600093849361417b565b81604051928392833781018481520391357f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd65af1612824613675565b602190808203613351575050505090916131ff6131f7868661415a565b96909561417b565b929061324160409788519760208901997f24856bc3000000000000000000000000000000000000000000000000000000008b5260248a01526064890191613537565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc878203016044880152818152602082818301951b82010195856000915b8483106132d357505050505050505091816132c5600094938594037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b519082305af1612824613675565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085820301885288358284360301811215610a4e578301906020823592019167ffffffffffffffff8111610a4e578036038313610a4e5761334160209283928b95613537565b9a0198019695949301919061327f565b929750929593509350602281146000146127835750604080936080510101359060009060028310156134e1575050808491156000146134895750506000907f0000000000000000000000001e0049783f008a0085193e00003d00cd54003c71925b6020838251937f095ea7b3000000000000000000000000000000000000000000000000000000008552600496878601526024947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff868201526044968792355af13d15601f3d1187600051141617161561342e5750505050610e71565b91600e7f415050524f56455f4641494c45440000000000000000000000000000000000009260206064969551957f08c379a0000000000000000000000000000000000000000000000000000000008752860152840152820152fd5b036134b8576000907f0000000000000000000000002b2e8cda09bba9660dca5cb6233787738ad68329926133b2565b600482517f5461585f000000000000000000000000000000000000000000000000000000008152fd5b602492507f4e487b71000000000000000000000000000000000000000000000000000000008252600452fd5b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b67ffffffffffffffff8111610f7d57604052565b6080810190811067ffffffffffffffff821117610f7d57604052565b6020810190811067ffffffffffffffff821117610f7d57604052565b6040810190811067ffffffffffffffff821117610f7d57604052565b6060810190811067ffffffffffffffff821117610f7d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610f7d57604052565b67ffffffffffffffff8111610f7d57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156136a0573d906136868261363b565b9161369460405193846135fa565b82523d6000602084013e565b606090565b67ffffffffffffffff8111610f7d5760051b60200190565b359065ffffffffffff82168203610a4e57565b81601f82011215610a4e578035906136e78261363b565b926136f560405194856135fa565b82845260208383010111610a4e57816000926020809301838601378301015290565b919290613724908361417b565b90938460405195869384378201906000958693838580955203918635905af19261374c613675565b9284613756575050565b73ffffffffffffffffffffffffffffffffffffffff60608201351661377e6040830135613854565b91813b156106ad576040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff93909316602484015260800135604483015290919081908390606490829084905af190811561380357506137f85750565b61380190613576565b565b604051903d90823e3d90fd5b919261385195949160a09473ffffffffffffffffffffffffffffffffffffffff8092168552166020840152604083015260608201528160808201520190610af6565b90565b73ffffffffffffffffffffffffffffffffffffffff908082166001810361387e5750506001541690565b90915060020361385157503090565b90816020910312610a4e57518015158103610a4e5790565b9092919073ffffffffffffffffffffffffffffffffffffffff16806138cf575061380191926144d1565b7f80000000000000000000000000000000000000000000000000000000000000008214613902575b92613801929361453f565b9050604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481855afa938415610f7157600094613951575b5092906138f7565b6020813d821161397c575b81613969602093836135fa565b8101031261021757519350613801613949565b3d915061395c565b81810292918115918404141715611b0357565b81156139a1570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b919273ffffffffffffffffffffffffffffffffffffffff91827f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31693843b15610a4e5760009484869281608496816040519b8c9a8b997f36c78516000000000000000000000000000000000000000000000000000000008b521660048a01521660248801521660448601521660648401525af18015610f71576137f85750565b8051821015611b4c5760209160051b010190565b9190811015611b4c5760051b0190565b3573ffffffffffffffffffffffffffffffffffffffff81168103610a4e5790565b91908203918211611b0357565b92919073ffffffffffffffffffffffffffffffffffffffff8082163003613aee575050613801926138a5565b8084959411613b02576138019416926139d0565b60046040517fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff93613c2d916040519060208201927fffffffffffffffffffffffffffffffffffffffff000000000000000000000000809260601b16845260601b16603482015260288152613b8f816135de565b519020613c01604051938492602084019687917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b5190201690565b73ffffffffffffffffffffffffffffffffffffffff8281169082161015613c585791565b9091565b51906dffffffffffffffffffffffffffff82168203610a4e57565b90816060910312610a4e57613c8b81613c5c565b916040613c9a60208401613c5c565b92015163ffffffff81168103610a4e5790565b9260028210614123578115611b4c57613cc584613a94565b9160019481861015611b4c5791613ce360209461190f868601613a94565b50926000935b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84018510613d1c575050505050505050565b613d2a6119b9868685613a84565b92613d3b6119b98a88018786613a84565b936040908151957f0902f1ac00000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff80941694606092600493808a86818b5afa998a1561225b57908d9594939291600091829c6140fd575b50508780916dffffffffffffffffffffffffffff8091169c16921692168214998a6000146140f7575b8651958680947f70a082310000000000000000000000000000000000000000000000000000000082528b8883015260249889915afa9283156140ec578e6000946140bb575b5050808303918115938480156140b3575b61408b57826103e5808602958604149114171561405e57613e439083613984565b926103e880830292830414171561403157613e689291613e629161414d565b90613997565b971561402957600097905b898b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe820181101561401d579161190f6119b9613eb9936002613f039c9601908d613a84565b8198917f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b965b988551918d83019367ffffffffffffffff9484811086821117613ff057885260008452813b15610a4e5760008a93613f8382968b519c8d97889687957f022c0d9f0000000000000000000000000000000000000000000000000000000087528d8701528d860152166044840152608060648401526084830190610af6565b03925af18015611ab857908d969594939291613fa8575b505050505094019391613ce9565b909192938095965011613fc45750505287903880808080613f9a565b6041907f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b876041887f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b5050508b956000613f05565b600090613e73565b856011867f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b866011877f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b8689517f7b9c8916000000000000000000000000000000000000000000000000000000008152fd5b508115613e22565b8181959293953d83116140e5575b6140d381836135fa565b8101031261038757505191388e613e11565b503d6140c9565b87513d6000823e3d90fd5b90613dcc565b899c50899250908161411a92903d10611f1357611f0281836135fa565b509b9091613da3565b60046040517fae52ad0c000000000000000000000000000000000000000000000000000000008152fd5b91908201809211611b0357565b91823583019161417460208435958186019503018561414d565b1161105d57565b91602083013583019161417460208435958186019503018561414d565b91606083013583019161417460208435958186019503018561414d565b7f80000000000000000000000000000000000000000000000000000000000000008114611b035760000390565b939193602b841061105d578462ffffff6000614267946142ee6142999935988960601c9a8b9a61423b601789013560601c9d8e109c73ffffffffffffffffffffffffffffffffffffffff9e8f998a9460481c1691614365565b16968b861461434a576401000276a49a5b60409d8e9b8c93845196879560208701526060860191613537565b91168b830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b848851998a98899788967f128acb080000000000000000000000000000000000000000000000000000000088521660048701528c6024870152604486015216606484015260a0608484015260a4830190610af6565b03925af190811561433f576000938492614309575b50509192565b9080949250813d8311614338575b61432181836135fa565b810103126103875750602082519201513880614303565b503d614317565b83513d6000823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d259a61424c565b73ffffffffffffffffffffffffffffffffffffffff92838316848316116144c9575b62ffffff90846040519481602087019516855216604085015216606083015260608252608082019082821067ffffffffffffffff831117610f7d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80613c2d9183604052845190209361449c60a08201957fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54907f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98488917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608101845201826135fa565b909190614387565b600080809381935af1156144e157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152fd5b60009182604492602095604051937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af13d15601f3d116001600051141617161561459257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fdfea2646970667358221220b2d6a39827110492aaa15cba3556e23894a51f2f635dc99ae66d21764ad4d90b64736f6c63430008110033"_hex, + + // 0x7a250d5630b4cf539739df2c5dacb4c659f2488d + "0x60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8484614608565b90505b92915050565b60008060006113ca7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f34888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b60606113917f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8484613f60565b60008060006131107f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8e7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28b348c8c614ef2565b9094509250600061349c7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f88886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f85856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c63430006060033"_hex, + + // 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + "0x60806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633659cfe6146100775780634f1ef286146100ba5780635c60da1b146101085780638f2839701461015f578063f851a440146101a2575b6100756101f9565b005b34801561008357600080fd5b506100b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610213565b005b610106600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001919091929391929390505050610268565b005b34801561011457600080fd5b5061011d610308565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561016b57600080fd5b506101a0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610360565b005b3480156101ae57600080fd5b506101b761051e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610201610576565b61021161020c610651565b610682565b565b61021b6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025c57610257816106d9565b610265565b6102646101f9565b5b50565b6102706106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fa576102ac836106d9565b3073ffffffffffffffffffffffffffffffffffffffff163483836040518083838082843782019150509250505060006040518083038185875af19250505015156102f557600080fd5b610303565b6103026101f9565b5b505050565b60006103126106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156103545761034d610651565b905061035d565b61035c6101f9565b5b90565b6103686106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561051257600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001807f43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f81526020017f787920746f20746865207a65726f20616464726573730000000000000000000081525060400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61048f6106a8565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161050d81610748565b61051b565b61051a6101f9565b5b50565b60006105286106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561056a576105636106a8565b9050610573565b6105726101f9565b5b90565b61057e6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515610647576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e20667281526020017f6f6d207468652070726f78792061646d696e000000000000000000000000000081525060400191505060405180910390fd5b61064f610777565b565b6000807f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c36001029050805491505090565b3660008037600080366000845af43d6000803e80600081146106a3573d6000f35b3d6000fd5b6000807f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b6001029050805491505090565b6106e281610779565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b60010290508181555050565b565b60006107848261084b565b151561081e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001807f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f81526020017f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000081525060400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c360010290508181555050565b600080823b9050600081119150509190505600a165627a7a72305820a4a547cfc7202c5acaaae74d428e988bc62ad5024eb0165532d3a8f91db4ed240029"_hex, + + // 0xdac17f958d2ee523a2206206994597c13d831ec7 + "0x606060405260043610610196576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde031461019b5780630753c30c14610229578063095ea7b3146102625780630e136b19146102a45780630ecb93c0146102d157806318160ddd1461030a57806323b872dd1461033357806326976e3f1461039457806327e235e3146103e9578063313ce56714610436578063353907141461045f5780633eaaf86b146104885780633f4ba83a146104b157806359bf1abe146104c65780635c658165146105175780635c975abb1461058357806370a08231146105b05780638456cb59146105fd578063893d20e8146106125780638da5cb5b1461066757806395d89b41146106bc578063a9059cbb1461074a578063c0324c771461078c578063cc872b66146107b8578063db006a75146107db578063dd62ed3e146107fe578063dd644f721461086a578063e47d606014610893578063e4997dc5146108e4578063e5b5019a1461091d578063f2fde38b14610946578063f3bdc2281461097f575b600080fd5b34156101a657600080fd5b6101ae6109b8565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ee5780820151818401526020810190506101d3565b50505050905090810190601f16801561021b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561023457600080fd5b610260600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a56565b005b341561026d57600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610b73565b005b34156102af57600080fd5b6102b7610cc1565b604051808215151515815260200191505060405180910390f35b34156102dc57600080fd5b610308600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cd4565b005b341561031557600080fd5b61031d610ded565b6040518082815260200191505060405180910390f35b341561033e57600080fd5b610392600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610ebd565b005b341561039f57600080fd5b6103a761109d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156103f457600080fd5b610420600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506110c3565b6040518082815260200191505060405180910390f35b341561044157600080fd5b6104496110db565b6040518082815260200191505060405180910390f35b341561046a57600080fd5b6104726110e1565b6040518082815260200191505060405180910390f35b341561049357600080fd5b61049b6110e7565b6040518082815260200191505060405180910390f35b34156104bc57600080fd5b6104c46110ed565b005b34156104d157600080fd5b6104fd600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506111ab565b604051808215151515815260200191505060405180910390f35b341561052257600080fd5b61056d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611201565b6040518082815260200191505060405180910390f35b341561058e57600080fd5b610596611226565b604051808215151515815260200191505060405180910390f35b34156105bb57600080fd5b6105e7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611239565b6040518082815260200191505060405180910390f35b341561060857600080fd5b610610611348565b005b341561061d57600080fd5b610625611408565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561067257600080fd5b61067a611431565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156106c757600080fd5b6106cf611456565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561070f5780820151818401526020810190506106f4565b50505050905090810190601f16801561073c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561075557600080fd5b61078a600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506114f4565b005b341561079757600080fd5b6107b6600480803590602001909190803590602001909190505061169e565b005b34156107c357600080fd5b6107d96004808035906020019091905050611783565b005b34156107e657600080fd5b6107fc600480803590602001909190505061197a565b005b341561080957600080fd5b610854600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611b0d565b6040518082815260200191505060405180910390f35b341561087557600080fd5b61087d611c52565b6040518082815260200191505060405180910390f35b341561089e57600080fd5b6108ca600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611c58565b604051808215151515815260200191505060405180910390f35b34156108ef57600080fd5b61091b600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611c78565b005b341561092857600080fd5b610930611d91565b6040518082815260200191505060405180910390f35b341561095157600080fd5b61097d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611db5565b005b341561098a57600080fd5b6109b6600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611e8a565b005b60078054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4e5780601f10610a2357610100808354040283529160200191610a4e565b820191906000526020600020905b815481529060010190602001808311610a3157829003601f168201915b505050505081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610ab157600080fd5b6001600a60146101000a81548160ff02191690831515021790555080600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcc358699805e9a8b7f77b522628c7cb9abd07d9efb86b6fb616af1609036a99e81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b604060048101600036905010151515610b8b57600080fd5b600a60149054906101000a900460ff1615610cb157600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aee92d333385856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b1515610c9857600080fd5b6102c65a03f11515610ca957600080fd5b505050610cbc565b610cbb838361200e565b5b505050565b600a60149054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d2f57600080fd5b6001600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507f42e160154868087d6bfdc0ca23d96a1c1cfa32f1b72ba9ba27b69b98a0d819dc81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b6000600a60149054906101000a900460ff1615610eb457600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6000604051602001526040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1515610e9257600080fd5b6102c65a03f11515610ea357600080fd5b505050604051805190509050610eba565b60015490505b90565b600060149054906101000a900460ff16151515610ed957600080fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151515610f3257600080fd5b600a60149054906101000a900460ff161561108c57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638b477adb338585856040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050600060405180830381600087803b151561107357600080fd5b6102c65a03f1151561108457600080fd5b505050611098565b6110978383836121ab565b5b505050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915090505481565b60095481565b60045481565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561114857600080fd5b600060149054906101000a900460ff16151561116357600080fd5b60008060146101000a81548160ff0219169083151502179055507f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3360405160405180910390a1565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6005602052816000526040600020602052806000526040600020600091509150505481565b600060149054906101000a900460ff1681565b6000600a60149054906101000a900460ff161561133757600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561131557600080fd5b6102c65a03f1151561132657600080fd5b505050604051805190509050611343565b61134082612652565b90505b919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113a357600080fd5b600060149054906101000a900460ff161515156113bf57600080fd5b6001600060146101000a81548160ff0219169083151502179055507f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62560405160405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60088054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156114ec5780601f106114c1576101008083540402835291602001916114ec565b820191906000526020600020905b8154815290600101906020018083116114cf57829003601f168201915b505050505081565b600060149054906101000a900460ff1615151561151057600080fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151561156957600080fd5b600a60149054906101000a900460ff161561168f57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e18980a3384846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b151561167657600080fd5b6102c65a03f1151561168757600080fd5b50505061169a565b611699828261269b565b5b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116f957600080fd5b60148210151561170857600080fd5b60328110151561171757600080fd5b81600381905550611736600954600a0a82612a0390919063ffffffff16565b6004819055507fb044a1e409eac5c48e5af22d4af52670dd1a99059537a78b31b48c6500a6354e600354600454604051808381526020018281526020019250505060405180910390a15050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117de57600080fd5b60015481600154011115156117f257600080fd5b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054011115156118c257600080fd5b80600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550806001600082825401925050819055507fcb8241adb0c3fdb35b70c24ce35c5eb0c17af7431c99f827d44a445ca624176a816040518082815260200191505060405180910390a150565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156119d557600080fd5b80600154101515156119e657600080fd5b80600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515611a5557600080fd5b8060016000828254039250508190555080600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507f702d5967f45f6513a38ffc42d6ba9bf230bd40e8f53b16363c7eb4fd2deb9a44816040518082815260200191505060405180910390a150565b6000600a60149054906101000a900460ff1615611c3f57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1515611c1d57600080fd5b6102c65a03f11515611c2e57600080fd5b505050604051805190509050611c4c565b611c498383612a3e565b90505b92915050565b60035481565b60066020528060005260406000206000915054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611cd357600080fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fd7e9ec6e6ecd65492dce6bf513cd6867560d49544421d0783ddf06e76c24470c81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611e1057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611e8757806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611ee757600080fd5b600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611f3f57600080fd5b611f4882611239565b90506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550806001600082825403925050819055507f61e6e66b0d6339b2980aecc6ccc0039736791f0ccde9ed512e789a7fbdd698c68282604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15050565b60406004810160003690501015151561202657600080fd5b600082141580156120b457506000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b1515156120c057600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3505050565b60008060006060600481016000369050101515156121c857600080fd5b600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054935061227061271061226260035488612a0390919063ffffffff16565b612ac590919063ffffffff16565b92506004548311156122825760045492505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84101561233e576122bd8585612ae090919063ffffffff16565b600560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6123518386612ae090919063ffffffff16565b91506123a585600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ae090919063ffffffff16565b600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061243a82600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060008311156125e4576124f983600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a35b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a350505050505050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000806040600481016000369050101515156126b657600080fd5b6126df6127106126d160035487612a0390919063ffffffff16565b612ac590919063ffffffff16565b92506004548311156126f15760045492505b6127048385612ae090919063ffffffff16565b915061275884600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ae090919063ffffffff16565b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506127ed82600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000831115612997576128ac83600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a35b8473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a35050505050565b6000806000841415612a185760009150612a37565b8284029050828482811515612a2957fe5b04141515612a3357fe5b8091505b5092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000808284811515612ad357fe5b0490508091505092915050565b6000828211151515612aee57fe5b818303905092915050565b6000808284019050838110151515612b0d57fe5b80915050929150505600a165627a7a72305820645ee12d73db47fd78ba77fa1f824c3c8f9184061b3b10386beb4dc9236abb280029"_hex, + + // 0x1111111254eeb25477b68fb85ed929f73a960582 + "0x6080604052600436106102f65760003560e01c80637e54f0921161018f578063bf15fcd8116100e1578063d365c6951161008a578063f2fde38b11610064578063f2fde38b14610859578063f78dc25314610879578063fa461e331461088c57600080fd5b8063d365c69514610813578063e449022e14610833578063e5d7bde61461084657600080fd5b8063c805a666116100bb578063c805a66614610799578063ca4ece22146107b9578063cf6fc6e3146107d957600080fd5b8063bf15fcd814610744578063bfa7514314610764578063c53a02921461078457600080fd5b8063942461bb11610143578063bc80f1a81161011d578063bc80f1a8146106f1578063bd61951d14610704578063bddccd351461072457600080fd5b8063942461bb146106915780639570eeee146106be578063bc1ed74c146106d157600080fd5b806383197ef01161017457806383197ef01461064157806384bd6d29146106565780638da5cb5b1461066957600080fd5b80637e54f092146105f4578063825caba11461062157600080fd5b80635a0998431161024857806370ae92d2116101fc57806372c244a8116101d657806372c244a81461059457806374261145146105b457806378e3214f146105d457600080fd5b806370ae92d21461053257806370ccbd311461055f578063715018a61461057f57600080fd5b806363592c2b1161022d57806363592c2b146104d25780636c838250146104f25780636fe7b0ba1461051257600080fd5b80635a099843146104ac57806362e238bb146104bf57600080fd5b80632d9a56f6116102aa5780633eca9c0a116102845780633eca9c0a1461041b5780634f38e2b81461044957806356f161241461046957600080fd5b80632d9a56f6146103bb57806337e7316f146103db5780633c15fd91146103fb57600080fd5b806312aa3caf116102db57806312aa3caf146103435780632521b9301461036b5780632cc2878d1461038b57600080fd5b80630502b1c51461030a578063093d4fa51461033057600080fd5b36610305576103036108ac565b005b600080fd5b61031d61031836600461483f565b6108b6565b6040519081526020015b60405180910390f35b61031d61033e3660046148a9565b6108d0565b610356610351366004614975565b610d16565b60408051928352602083019190915201610327565b34801561037757600080fd5b5061031d610386366004614a17565b610fd1565b34801561039757600080fd5b506103ab6103a6366004614abf565b611001565b6040519015158152602001610327565b3480156103c757600080fd5b506103566103d6366004614af1565b61104b565b3480156103e757600080fd5b5061031d6103f6366004614af1565b61114a565b34801561040757600080fd5b5061031d610416366004614a17565b611164565b61042e610429366004614c15565b611188565b60408051938452602084019290925290820152606001610327565b34801561045557600080fd5b506103ab610464366004614c72565b6111aa565b34801561047557600080fd5b5061031d610484366004614cbe565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b61042e6104ba366004614cea565b6111d5565b61042e6104cd366004614d60565b61132b565b3480156104de57600080fd5b506103ab6104ed366004614abf565b421090565b3480156104fe57600080fd5b506103ab61050d366004614af1565b611355565b34801561051e57600080fd5b506103ab61052d366004614c72565b611384565b34801561053e57600080fd5b5061031d61054d366004614e0c565b60016020526000908152604090205481565b34801561056b57600080fd5b5061042e61057a366004614e29565b6113aa565b34801561058b57600080fd5b506103036113f1565b3480156105a057600080fd5b506103036105af366004614ecd565b611403565b3480156105c057600080fd5b506103ab6105cf366004614c72565b6114b2565b3480156105e057600080fd5b506103036105ef366004614cbe565b611524565b34801561060057600080fd5b5061031d61060f366004614abf565b60009081526002602052604090205490565b34801561062d57600080fd5b5061030361063c366004614abf565b611544565b34801561064d57600080fd5b50610303611553565b61031d610664366004614ef0565b61155e565b34801561067557600080fd5b506000546040516001600160a01b039091168152602001610327565b34801561069d57600080fd5b506106b16106ac366004614f67565b611571565b6040516103279190615001565b61042e6106cc366004615045565b61162a565b3480156106dd57600080fd5b5061031d6106ec366004614abf565b611767565b61031d6106ff36600461483f565b6117b7565b34801561071057600080fd5b5061030361071f366004615082565b6117c6565b34801561073057600080fd5b5061030361073f3660046150be565b611867565b34801561075057600080fd5b5061031d61075f366004615082565b611872565b34801561077057600080fd5b506103ab61077f366004614c72565b6118bd565b34801561079057600080fd5b50610303611930565b3480156107a557600080fd5b5061031d6107b43660046150e0565b61193a565b3480156107c557600080fd5b506103ab6107d4366004614c72565b611971565b3480156107e557600080fd5b506103ab6107f4366004614cbe565b6001600160a01b03919091166000908152600160205260409020541490565b34801561081f57600080fd5b5061042e61082e3660046151a4565b611998565b61031d610841366004615295565b611a2c565b61042e6108543660046152e8565b611a3b565b34801561086557600080fd5b50610303610874366004614e0c565b6124cb565b61031d6108873660046153ac565b612558565b34801561089857600080fd5b506103036108a7366004615416565b612573565b6108b4612785565b565b60006108c63387878787876127be565b9695505050505050565b60006001600160a01b0388161580156109085786341461090357604051631841b4e160e01b815260040160405180910390fd5b610a24565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316896001600160a01b0316036109f057506001341561096357604051631841b4e160e01b815260040160405180910390fd5b6040516323b872dd60e01b808252336004830152306024830152604482018990527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d60e01b9060008060648382885af16109c6573d6000823e3d81fd5b8181528a60048201526000806024836000885af16109e7573d6000823e3d81fd5b50505050610a24565b3415610a0f57604051631841b4e160e01b815260040160405180910390fd5b610a246001600160a01b038a16338d8a612b30565b8015610ab85760008b905060006327a9b42460e01b90506040518181528a60048201528960248201528860448201528760648201528c60848201528560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149838d875af1610ab0573d6000823e3d81fd5b505050610d07565b6001600160a01b0388161580610aff57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316886001600160a01b0316145b15610c75576040517f4cb6864c00000000000000000000000000000000000000000000000000000000808252600482018b90526024820189905260448201889052606482018790528c918a1560018114610b5e57306084830152610b65565b8d60848301525b508560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149836000875af1610bb8573d6000823e3d81fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031603610c6e57604051630d0e30db60e41b8082527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29163a9059cbb60e01b906000806004838f885af1610c42573d6000823e3d81fd5b8181528f60048201528b60248201526000806044836000885af1610c69573d6000823e3d81fd5b505050505b5050610d07565b60008b90506000632b651a6c60e01b90506040518181528b60048201528a60248201528960448201528860648201528760848201528c60a48201528560ff1c601b0160c48201528660e48201526001600160ff1b03861661010482015261014061012482015264a62929c86960d31b610163820152600080610169836000875af1610d03573d6000823e3d81fd5b5050505b50939998505050505050505050565b6000808660a00135600003610d57576040517f0262dde400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d666020890189614e0c565b90506000610d7a60408a0160208b01614e0c565b90506000610d90836001600160a01b0316612bcd565b905060c08a013560021615610dd55780610dab576000610db1565b89608001355b3411610dd057604051631841b4e160e01b815260040160405180910390fd5b610e06565b80610de1576000610de7565b89608001355b3414610e0657604051631841b4e160e01b815260040160405180910390fd5b80610e4f578715610e2557610e256001600160a01b0384168a8a612c06565b610e4f33610e3960608d0160408e01614e0c565b6001600160a01b038616919060808e0135612b30565b610e608b338c608001358a8a612cbf565b60808a01359350610e7a6001600160a01b03831630612d1f565b945084600003610eb6576040517f28ebf24700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000199094019360c08a013560011615610f4f576000610edf6001600160a01b03851630612d1f565b90506001811115610f0e5760001901610ef88186615473565b9450610f0e6001600160a01b0385163383612dca565b610f1c8560a08d0135615486565b610f2a60808d013588615486565b1015610f495760405163f32bec2f60e01b815260040160405180910390fd5b50610f74565b8960a00135851015610f745760405163f32bec2f60e01b815260040160405180910390fd5b600080610f8760808d0160608e01614e0c565b6001600160a01b031614610faa57610fa560808c0160608d01614e0c565b610fac565b335b9050610fc26001600160a01b0384168288612dca565b50505050965096945050505050565b6000610fe76001600160a01b0389168484612c06565b610ff48988888888612eaa565b9998505050505050505050565b600060d082901c60a083901c65ffffffffffff168361101f83421090565b801561104257506001600160a01b03811660009081526001602052604090205482145b95945050505050565b6000803361105f6080850160608601614e0c565b6001600160a01b03161461109f576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110a88361114a565b6000818152600260205260409020549250905060001982016110f6576040517f41a26a6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518281526020810184905233917fcbfa7d191838ece7ba4783ca3a30afd316619b7f368094b57ee7ffde9a923db1910160405180910390a26000818152600260205260409020600190559092909150565b600061115e611157613131565b8390613258565b92915050565b600061117a6001600160a01b0389168484612c06565b610ff48989898989896127be565b600080600061119a87878787336111d5565b9250925092509450945094915050565b60008060006111b985856132d7565b915091508180156111c957508581115b925050505b9392505050565b60008060006112356111e5613131565b601f198a0180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8516156112a957600160fd1b851615801590611259575060418614155b15611277576040516317c2b1f160e01b815260040160405180910390fd5b6112878860600151828989613466565b6112a4576040516317c2b1f160e01b815260040160405180910390fd5b6112d6565b6112b988606001518289896134bb565b6112d6576040516317c2b1f160e01b815260040160405180910390fd5b6112e1888686613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a1955095509592505050565b60008060006113418b8b8b8b8b8b8b8b33611a3b565b925092509250985098509895505050505050565b600080600061136b61136685613b2e565b6132d7565b9150915081801561137c5750806001145b949350505050565b600080600061139385856132d7565b915091508180156111c95750909414949350505050565b60008060006113d185858c604001516001600160a01b0316612c069092919063ffffffff16565b6113de8a8a8a8a8a6111d5565b9250925092509750975097945050505050565b6113f9613b45565b6108b46000613b9f565b8060ff16600003611440576040517fbd71636d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526001602052604081205461145e9060ff84169061549d565b336000818152600160205260409081902083905551919250907ffc69110dd11eb791755e4abd6b7d281bae236de95736d38a23782814be5e10db906114a69084815260200190565b60405180910390a25050565b60008080805b63ffffffff87821c1692508215611517576000806114db61136686868a8c6154b0565b915091508180156114ec5750806001145b156114ff576001955050505050506111ce565b50839250611510905060208261549d565b90506114b8565b5060009695505050505050565b61152c613b45565b6115406001600160a01b0383163383612dca565b5050565b61155033826000613c07565b50565b61155b613b45565b33ff5b6000610ff489338a8a8a8a8a8a8a6108d0565b60606000825167ffffffffffffffff81111561158f5761158f614b26565b6040519080825280602002602001820160405280156115b8578160200160208202803683370190505b50905060005b835181101561162357600260008583815181106115dd576115dd6154da565b6020026020010151815260200190815260200160002054828281518110611606576116066154da565b60209081029190910101528061161b816154f0565b9150506115be565b5092915050565b600080600061168a61163a613131565b601f19890180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8416156116e657600160fd1b8416156116d6576116b48760600151828888613c9b565b6116d1576040516317c2b1f160e01b815260040160405180910390fd5b611713565b6116b48760600151828888613d05565b6116f68760600151828888613d5a565b611713576040516317c2b1f160e01b815260040160405180910390fd5b61171e878533613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a19450945094915050565b600081815260026020526040812054806117ad576040517fb838de9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000190192915050565b60006108c68686868686612eaa565b600080846001600160a01b031684846040516117e3929190615509565b600060405180830381855af49150503d806000811461181e576040519150601f19603f3d011682016040523d82523d6000602084013e611823565b606091505b509150915081816040517f1934afc800000000000000000000000000000000000000000000000000000000815260040161185e929190615569565b60405180910390fd5b611540338383613c07565b6000806000611882868686613da9565b9150915081611042576040517f1f1b8f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080805b63ffffffff87821c1692508215611923576000806118e661136686868a8c6154b0565b915091508115806118f8575080600114155b1561190b576000955050505050506111ce565b5083925061191c905060208261549d565b90506118c3565b5060019695505050505050565b6108b46001611403565b60006119506001600160a01b038b168484612c06565b6119618c8c8c8c8c8c8c8c8c6108d0565b9c9b505050505050505050505050565b600080600061198085856132d7565b915091508180156111c9575094909410949350505050565b6000808060148410156119d7576040517fd9e1c6dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006119e68888613dd7565b91945092509050611a016001600160a01b0384168383612c06565b505050611a158e8e8e8e8e8e8e8e8e611a3b565b9250925092509b509b509b98505050505050505050565b60006110423386868686612eaa565b600080806001600160a01b038416611a7f576040517fb0c4d05f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a888c61114a565b6000818152600260205260409020548894508793509091508c906000198101611add576040517fecef366400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611aef60c0840160a08501614e0c565b6001600160a01b031614158015611b1e575033611b1260c0840160a08501614e0c565b6001600160a01b031614155b15611b55576040517fd4dfdafe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80611c5857611b75611b6d6080840160608501614e0c565b848f8f6134bb565b611bab576040517f5cd5d23300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060c0810135366000611bbd84613e15565b91509150600160ff1b89166000148015611bd8575060148110155b15611c51576000366000611bec8585613dd7565b91945092509050611c076001600160a01b0384168383612c06565b60008881526002602052604090205415611c4d576040517fc5f2be5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505b5050611c5d565b600019015b6000611c6883613b2e565b90501115611caf57611c7982611355565b611caf576040517fb6629c0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415841503611ce9576040517ee2a52200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611d795780851115611cfd578094505b611d1b611d0983613e23565b8460c00135888660e001358689613e31565b93506001600160ff1b038716611d318682615486565b611d3b8b87615486565b1115611d73576040517ffb8ae12900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611e44565b611d97611d8583613e67565b8460e00135878660c001358689613e75565b945080851115611dec57809450611db0611d0983613e23565b935087841115611dec576040517f939c420400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160ff1b038716611e008582615486565b611e0a8a88615486565b1015611e42576040517f481ea39200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b841580611e4f575083155b15611e86576040517ffba5a27600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84810390508060010160026000858152602001908152602001600020819055508d6060016020810190611eb99190614e0c565b6001600160a01b03167fb9ed0243fdf00f0545c63a0af8850c090d86bb46682baec4bf3c496814fe4f028483604051611efc929190918252602082015260400190565b60405180910390a26014611f0f83613e89565b905010611fb2576000366000611f2c611f2786613e89565b613dd7565b919450925090506001600160a01b0383166396a10e3387611f536080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b8152600401611f7c9897969594939291906155ad565b600060405180830381600087803b158015611f9657600080fd5b505af1158015611faa573d6000803e3d6000fd5b505050505050505b611fe5611fc56040840160208501614e0c565b611fd56080850160608601614e0c565b8888611fe087613e97565b613ea5565b61201b576040517f70a03f4800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148a106120f35760003660006120328e8e613dd7565b9250925092506000836001600160a01b031663ccee33d7338b8b87876040518663ffffffff1660e01b815260040161206e959493929190615600565b6020604051808303816000875af115801561208d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b1919061562f565b905087811180156120d057506120ce6120c987613e67565b613f00565b155b80156120e557506120e36120c987613e23565b155b156120ee578097505b505050505b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21661212d6060840160408501614e0c565b6001600160a01b03161480156121435750600034115b15612359578334101561216957604051631841b4e160e01b815260040160405180910390fd5b833411156121df57604051600090339034879003908381818185875af1925050503d80600081146121b6576040519150601f19603f3d011682016040523d82523d6000602084013e6121bb565b606091505b50509050806121dd5760405163b12d13eb60e01b815260040160405180910390fd5b505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216925063a9059cbb91506000905061229760a0860160808701614e0c565b6001600160a01b0316146122ba576122b560a0850160808601614e0c565b6122ca565b6122ca6080850160608601614e0c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018790526044016020604051808303816000875af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123539190615648565b50612411565b341561237857604051631841b4e160e01b815260040160405180910390fd5b6123db61238b6060840160408501614e0c565b33600061239e60a0870160808801614e0c565b6001600160a01b0316146123c1576123bc60a0860160808701614e0c565b6123d1565b6123d16080860160608701614e0c565b87611fe087613f75565b612411576040517f478a520500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601461241c83613f83565b9050106124ba576000366000612434611f2786613f83565b919450925090506001600160a01b038316633504ed628761245b6080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b81526004016124849897969594939291906155ad565b600060405180830381600087803b15801561249e57600080fd5b505af11580156124b2573d6000803e3d6000fd5b505050505050505b505099509950999650505050505050565b6124d3613b45565b6001600160a01b03811661254f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161185e565b61155081613b9f565b60006125688787878787876127be565b979650505050505050565b6125cc565b3d6000803e3d6000fd5b8061258f5761258f612578565b600160005114601f3d11163d151780611540577ff27f64e40000000000000000000000000000000000000000000000000000000060005260046000fd5b604051601581017f0dfe1681d21220a7ddca3f43a9059cbb23b872dd0000000000000000000000008252602081600484335afa61260b5761260b612578565b60208082016004808501335afa61262457612624612578565b602060408201600460088501335afa61263f5761263f612578565b600080600088136001811461265d5760208401519250879150612665565b835192508891505b507fff1f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000084526060832083527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460208401526001600160a01b0360558520169250338318156126f6577fb2c027220000000000000000000000000000000000000000000000000000000060005260046000fd5b60843592507f0dfe1681d21220a7ddca3f43a9059cbb23b872dd00000000000000000000000084523083146001811461275757836014860152336034860152816054860152612752602060006064601089016000885af1612582565b61277a565b33601086015281603086015261277a602060006044600c89016000885af1612582565b505050505050505050565b3233036108b4576040517f1b10b0f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128b9565b7f0902f1ac0000000000000000000000000000000000000000000000000000000081526000604082600484875afa6127ff576127ff612578565b60603d14612831577f85cd58dc0000000000000000000000000000000000000000000000000000000060005260046000fd5b81516020830151861561284057905b8785029250633b9aca008202830181840204925050507f022c0d9f000000000000000000000000000000000000000000000000000000008252841594508415810260048301528481026024830152866044830152608060648301526000608483015260008060a4846000885af16108c6576108c6612578565b6dffffffffffffffffffffffffffff8511156128f9577fcf0b4d3a0000000000000000000000000000000000000000000000000000000060005260046000fd5b60405160c081016040528260051b84018435886000811461296957341561292b57631841b4e160e01b60005260046000fd5b6323b872dd60e01b84523360048501526001600160a01b03821660248501528860448501526129646020600060648760008f5af1612582565b6129ff565b34891461298157631841b4e160e01b60005260046000fd5b630d0e30db60e41b84526000806004868c73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129b5576129b5612578565b63a9059cbb60e01b84526001600160a01b0382166004850152886024850152600080604486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129ff576129ff612578565b50879350602086015b82811015612a50578035612a446001600160a01b03821663ffffffff60a01b851660a01c600160ff1b86166001600160a01b0387168a8a6127c5565b95509150602001612a08565b50600160fe1b81168015612adf57612a873063ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b9450632e1a7d4d60e01b8452846004850152600080602486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1612ac457612ac4612578565b600080600080888f5af1612ada57612ada612578565b612b0b565b612b088b63ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b94505b50505050838110156108c65760405163f32bec2f60e01b815260040160405180910390fd5b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af19150508015612b8e573d8015612b8457600160005114601f3d11169150612b8c565b6000873b1191505b505b80612bc5576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b60006001600160a01b038216158061115e57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600060e0829003612c4457612c3d847fd505accf000000000000000000000000000000000000000000000000000000008585613f91565b9050612cac565b610100829003612c7a57612c3d847f8fcbaf0c000000000000000000000000000000000000000000000000000000008585613f91565b6040517f6827585700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80612cb957612cb9613fe3565b50505050565b6040517f4b64e4920000000000000000000000000000000000000000000000000000000080825260048201869052908284602483013784836024830101526000808460440183348b5af1612d16573d6000823e3d81fd5b50505050505050565b6000612d2a83612bcd565b15612d4057506001600160a01b0381163161115e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015612d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc3919061562f565b905061115e565b8015612ea557612dd983612bcd565b15612e915780471015612e18576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b03168261138890604051600060405180830381858888f193505050503d8060008114612e6a576040519150601f19603f3d011682016040523d82523d6000602084013e612e6f565b606091505b5050905080612cb95760405163b12d13eb60e01b815260040160405180910390fd5b612ea56001600160a01b0384168383613fef565b505050565b600081808203612ee6576040517f67e7c0f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8591506000198101341515600080600160fd1b888886818110612f0b57612f0b6154da565b90506020020135161190508115612fb157883414612f3c57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08a6040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f9757600080fd5b505af1158015612fab573d6000803e3d6000fd5b50505050505b600184111561305157612feb3083612fc95733612fcb565b305b89896000818110612fde57612fde6154da565b9050602002013588614038565b945060015b838110156130265761301c30308a8a8581811061300f5761300f6154da565b9050602002013589614038565b9550600101612ff0565b5061304a81613035578a613037565b305b30898987818110612fde57612fde6154da565b945061306f565b61306c8161305f578a613061565b305b83612fc95733612fcb565b94505b878510156130905760405163f32bec2f60e01b815260040160405180910390fd5b801561312457604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156130f857600080fd5b505af115801561310c573d6000803e3d6000fd5b50613124925050506001600160a01b038b16866141d4565b5050505095945050505050565b6000306001600160a01b037f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605821614801561318a57507f000000000000000000000000000000000000000000000000000000000000000146145b156131b457507f1c0eb4c27d5b523ca136c0b3b83a4dcac8b70225b38be8507ba1a3f2af03cfca90565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f5c6cbfb2848b981a8f93044b3530be1fac304ecd5042396ca8729cb8fdd718f3828401527fceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c160608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000368161326a61012086018661566a565b60405191935091507f0a244ca8a150ac294c14fcff9277051ced9a5b23e966a0ff0522e989da23116c9082848237828120610140820152610120876020830137818152610160902060405161190160f01b81526002810187905260228101829052604290209094506108c6565b60008060006132e685856142ed565b60e01c905060006132f986866004614317565b9050632cc2878c19820161333057600161331282611001565b61331d576000613320565b60015b90945060ff16925061345f915050565b63bf15fcd88210156133be57636fe7b0ba82101561338257634f38e2b71982016133665760016133128261046489896064614348565b6363592c2a19820161337d57600161331282421090565b61344d565b636fe7b0b91982016133a05760016133128261052d89896064614348565b637426114419820161337d576001613312826105cf89896064614348565b63ca4ece228210156134115763bf15fcd71982016133f35760016133e88261075f89896064614348565b93509350505061345f565b63bfa7514219820161337d5760016133128261077f89896064614348565b63ca4ece2119820161342f576001613312826107d489896064614348565b63cf6fc6e219820161344d576001613312826107f489896024614317565b613458308787613da9565b9350935050505b9250929050565b600080631626ba7e60e01b905060405181815285600482015260406024820152836044820152838560648301376020600085606401838a5afa156134b15760203d1460005183141692505b5050949350505050565b60006001600160a01b0385166134d35750600061137c565b60408214806134e25750604182145b80156135095750846001600160a01b03166134fe858585614378565b6001600160a01b0316145b156135165750600161137c565b61104285858585613466565b6000806001600160a01b038316613565576040517f692e45e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606085015160808601516001600160a01b031615801590613593575060808601516001600160a01b03163314155b156135ca576040517fe8c6632100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff604082901c1680158015906135e957508042115b15613620576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61362c83836000613c07565b505060a086015160c08701517f0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716600081900361366f57829550819450613715565b600160ff1b8816156136ca57828111156136b5576040517faa34b69600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8095506136c383838861442d565b9450613715565b81811115613704576040517f7f902a9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80945061371283838761445b565b95505b5050508260001480613725575081155b1561375c576040517f07b6e79f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686602001516001600160a01b03161480156137c257507f1000000000000000000000000000000000000000000000000000000000000000851615155b1561395a576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018590527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906323b872dd906064016020604051808303816000875af115801561383c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138609190615648565b50604051632e1a7d4d60e01b8152600481018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156138c357600080fd5b505af11580156138d7573d6000803e3d6000fd5b505050506000846001600160a01b03168461138890604051600060405180830381858888f193505050503d806000811461392d576040519150601f19603f3d011682016040523d82523d6000602084013e613932565b606091505b50509050806139545760405163b12d13eb60e01b815260040160405180910390fd5b50613974565b6020860151613974906001600160a01b0316828686612b30565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686604001516001600160a01b03161480156139b95750600034115b15613aec578134146139de57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a3957600080fd5b505af1158015613a4d573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018790527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063a9059cbb925060440190506020604051808303816000875af1158015613ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae69190615648565b50613b25565b3415613b0b57604051631841b4e160e01b815260040160405180910390fd5b6040860151613b25906001600160a01b0316338385612b30565b50935093915050565b366000613b3c836004614468565b91509150915091565b6000546001600160a01b031633146108b45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161185e565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038316600090815260036020908152604080832066ffffffffffffff600887901c16808552928190529220549091600160ff86161b841791808316839003613c82576040517ff71fbda200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000938452602091909152604090922091179055505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604160448201528460648201526001600160ff1b03841660848201528360ff1c601b0160a48201536020600060a5838a5afa156134b15750600051143d6020141695945050505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604060448201528460648201528360848201526020600060a4838a5afa156134b15750600051143d6020141695945050505050565b60006001600160a01b038516613d725750600061137c565b846001600160a01b0316613d878585856144c3565b6001600160a01b031603613d9d5750600161137c565b61104285858585613d05565b60008060405183858237602060008583895afa3d602014169250508115613dcf57506000515b935093915050565b600036816014841015613dfd5760405163779ab6bd60e11b815260040160405180910390fd5b505050813560601c9260149092019160131990910190565b366000613b3c836005614468565b366000613b3c836003614468565b6000868103613e4c57613e4586858761442d565b9050612568565b613e5b88888888888888614532565b98975050505050505050565b366000613b3c836002614468565b6000868103613e4c57613e4584878761445b565b366000613b3c836006614468565b366000613b3c836000614468565b6040516323b872dd60e01b8082526004820187905260248201869052604482018590526000918385606483013760206000856064018360008d5af19050600160005114601f3d11163d15178116925050509695505050505050565b60006001821480156111ce575082826000818110613f2057613f206154da565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f7800000000000000000000000000000000000000000000000000000000000000149392505050565b366000613b3c836001614468565b366000613b3c836007614468565b6000816004016040518581528385600483013760206000838360008b5af192505050801561137c573d8015613fd257600160005114601f3d11169150613fda565b6000863b1191505b50949350505050565b6040513d6000823e3d81fd5b6140028363a9059cbb60e01b84846146be565b612ea5576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600160ff1b831615801561410e576000846001600160a01b031663128acb08888461406488614700565b604080516001600160a01b038d1660208201526401000276a491016040516020818303038152906040526040518663ffffffff1660e01b81526004016140ae9594939291906156b1565b60408051808303816000875af11580156140cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f091906156eb565b915050614105816141009061570f565b614783565b9250505061137c565b6000846001600160a01b031663128acb08888461412a88614700565b604080516001600160a01b038d16602082015273fffd8963efd1fc6a506488495d951d5263988d2591016040516020818303038152906040526040518663ffffffff1660e01b81526004016141839594939291906156b1565b60408051808303816000875af11580156141a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c591906156eb565b5090506141056141008261570f565b804710156142245760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161185e565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614271576040519150601f19603f3d011682016040523d82523d6000602084013e614276565b606091505b5050905080612ea55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161185e565b600060048210156143115760405163779ab6bd60e11b815260040160405180910390fd5b50503590565b60006020820183101561433d5760405163779ab6bd60e11b815260040160405180910390fd5b509190910135919050565b3660008284101561436c5760405163779ab6bd60e11b815260040160405180910390fd5b50509182019291900390565b6000604051826041811461439757604081146143b157600091506143d9565b604085013560001a602083015260408560408401376143d9565b60208501358060ff1c601b01602084015260208660408501376001600160ff1b031660608301525b508015614425577f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16060820151101561442557848152600080526020600060808360015afa5060005191505b509392505050565b60008360018161443d8686615486565b614447919061549d565b6144519190615473565b61137c919061572b565b6000826144518584615486565b3660008060058460078111156144805761448061574d565b901b905061449261012086018661566a565b6144b79161010088013580851c63ffffffff9081169360209290921b861c16916154b0565b92509250509250929050565b60006001600160ff1b0382167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1811015614425576040518581528360ff1c601b016020820152846040820152816060820152600080526020600060808360015afa505060005195945050505050565b600060018790036145be576145478888613f00565b1561458c57858514614585576040517f49986e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5082612568565b6040517fbec74c8500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006145cd8b8b613dd7565b925092509250600080846001600160a01b031684848c8b8b6040516020016145f9959493929190615763565b60408051601f198184030181529082905261461391615782565b600060405180830381855afa9150503d806000811461464e576040519150601f19603f3d011682016040523d82523d6000602084013e614653565b606091505b509150915081158061466757508051602014155b1561469e576040517f110b8e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808060200190518101906146b2919061562f565b95505050505050612568565b60006040518481528360048201528260248201526020600060448360008a5af1915050801561137c573d8015613fd257600160005114601f3d11169150613fda565b60006001600160ff1b0382111561477f5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e74323536000000000000000000000000000000000000000000000000606482015260840161185e565b5090565b60008082121561477f5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161185e565b6001600160a01b038116811461155057600080fd5b80356147f5816147d5565b919050565b60008083601f84011261480c57600080fd5b50813567ffffffffffffffff81111561482457600080fd5b6020830191508360208260051b850101111561345f57600080fd5b60008060008060006080868803121561485757600080fd5b8535614862816147d5565b94506020860135935060408601359250606086013567ffffffffffffffff81111561488c57600080fd5b614898888289016147fa565b969995985093965092949392505050565b60008060008060008060008060006101208a8c0312156148c857600080fd5b89356148d3816147d5565b985060208a01356148e3816147d5565b975060408a01356148f3816147d5565b965060608a0135614903816147d5565b989b979a50959860808101359760a0820135975060c0820135965060e08201359550610100909101359350915050565b60008083601f84011261494557600080fd5b50813567ffffffffffffffff81111561495d57600080fd5b60208301915083602082850101111561345f57600080fd5b60008060008060008086880361014081121561499057600080fd5b873561499b816147d5565b965060e0601f19820112156149af57600080fd5b5060208701945061010087013567ffffffffffffffff808211156149d257600080fd5b6149de8a838b01614933565b90965094506101208901359150808211156149f857600080fd5b50614a0589828a01614933565b979a9699509497509295939492505050565b60008060008060008060008060c0898b031215614a3357600080fd5b8835614a3e816147d5565b97506020890135614a4e816147d5565b96506040890135955060608901359450608089013567ffffffffffffffff80821115614a7957600080fd5b614a858c838d016147fa565b909650945060a08b0135915080821115614a9e57600080fd5b50614aab8b828c01614933565b999c989b5096995094979396929594505050565b600060208284031215614ad157600080fd5b5035919050565b60006101408284031215614aeb57600080fd5b50919050565b600060208284031215614b0357600080fd5b813567ffffffffffffffff811115614b1a57600080fd5b61137c84828501614ad8565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b6557614b65614b26565b604052919050565b600060e08284031215614b7f57600080fd5b60405160e0810181811067ffffffffffffffff82111715614ba257614ba2614b26565b604052823581529050806020830135614bba816147d5565b60208201526040830135614bcd816147d5565b60408201526060830135614be0816147d5565b60608201526080830135614bf3816147d5565b8060808301525060a083013560a082015260c083013560c08201525092915050565b6000806000806101208587031215614c2c57600080fd5b614c368686614b6d565b935060e085013567ffffffffffffffff811115614c5257600080fd5b614c5e87828801614933565b959890975094956101000135949350505050565b600080600060408486031215614c8757600080fd5b83359250602084013567ffffffffffffffff811115614ca557600080fd5b614cb186828701614933565b9497909650939450505050565b60008060408385031215614cd157600080fd5b8235614cdc816147d5565b946020939093013593505050565b60008060008060006101408688031215614d0357600080fd5b614d0d8787614b6d565b945060e086013567ffffffffffffffff811115614d2957600080fd5b614d3588828901614933565b9095509350506101008601359150610120860135614d52816147d5565b809150509295509295909350565b60008060008060008060008060c0898b031215614d7c57600080fd5b883567ffffffffffffffff80821115614d9457600080fd5b614da08c838d01614ad8565b995060208b0135915080821115614db657600080fd5b614dc28c838d01614933565b909950975060408b0135915080821115614ddb57600080fd5b50614de88b828c01614933565b999c989b5096999698976060880135976080810135975060a0013595509350505050565b600060208284031215614e1e57600080fd5b81356111ce816147d5565b6000806000806000806000610160888a031215614e4557600080fd5b614e4f8989614b6d565b965060e088013567ffffffffffffffff80821115614e6c57600080fd5b614e788b838c01614933565b90985096506101008a013595506101208a01359150614e96826147d5565b9093506101408901359080821115614ead57600080fd5b50614eba8a828b01614933565b989b979a50959850939692959293505050565b600060208284031215614edf57600080fd5b813560ff811681146111ce57600080fd5b600080600080600080600080610100898b031215614f0d57600080fd5b8835614f18816147d5565b97506020890135614f28816147d5565b96506040890135614f38816147d5565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b60006020808385031215614f7a57600080fd5b823567ffffffffffffffff80821115614f9257600080fd5b818501915085601f830112614fa657600080fd5b813581811115614fb857614fb8614b26565b8060051b9150614fc9848301614b3c565b8181529183018401918481019088841115614fe357600080fd5b938501935b83851015613e5b57843582529385019390850190614fe8565b6020808252825182820181905260009190848201906040850190845b818110156150395783518352928401929184019160010161501d565b50909695505050505050565b600080600080610140858703121561505c57600080fd5b6150668686614b6d565b9660e08601359650610100860135956101200135945092505050565b60008060006040848603121561509757600080fd5b83356150a2816147d5565b9250602084013567ffffffffffffffff811115614ca557600080fd5b600080604083850312156150d157600080fd5b50508035926020909101359150565b60008060008060008060008060008060006101408c8e03121561510257600080fd5b8b3561510d816147d5565b9a5060208c013561511d816147d5565b995060408c013561512d816147d5565b985060608c013561513d816147d5565b975060808c0135965060a08c0135955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561517e57600080fd5b61518a8e828f01614933565b915080935050809150509295989b509295989b9093969950565b60008060008060008060008060008060006101008c8e0312156151c657600080fd5b67ffffffffffffffff808d3511156151dd57600080fd5b6151ea8e8e358f01614ad8565b9b508060208e013511156151fd57600080fd5b61520d8e60208f01358f01614933565b909b50995060408d013581101561522357600080fd5b6152338e60408f01358f01614933565b909950975060608d0135965060808d0135955060a08d0135945061525960c08e016147ea565b93508060e08e0135111561526c57600080fd5b5061527d8d60e08e01358e01614933565b81935080925050509295989b509295989b9093969950565b600080600080606085870312156152ab57600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156152d057600080fd5b6152dc878288016147fa565b95989497509550505050565b600080600080600080600080600060e08a8c03121561530657600080fd5b893567ffffffffffffffff8082111561531e57600080fd5b61532a8d838e01614ad8565b9a5060208c013591508082111561534057600080fd5b61534c8d838e01614933565b909a50985060408c013591508082111561536557600080fd5b506153728c828d01614933565b90975095505060608a0135935060808a0135925060a08a0135915060c08a013561539b816147d5565b809150509295985092959850929598565b60008060008060008060a087890312156153c557600080fd5b86356153d0816147d5565b955060208701356153e0816147d5565b94506040870135935060608701359250608087013567ffffffffffffffff81111561540a57600080fd5b614a0589828a016147fa565b6000806000806060858703121561542c57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561545157600080fd5b6152dc87828801614933565b634e487b7160e01b600052601160045260246000fd5b8181038181111561115e5761115e61545d565b808202811582820484141761115e5761115e61545d565b8082018082111561115e5761115e61545d565b600080858511156154c057600080fd5b838611156154cd57600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b6000600182016155025761550261545d565b5060010190565b8183823760009101908152919050565b60005b8381101561553457818101518382015260200161551c565b50506000910152565b60008151808452615555816020860160208601615519565b601f01601f19169290920160200192915050565b821515815260406020820152600061137c604083018461553d565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b88815260006001600160a01b03808a1660208401528089166040840152508660608301528560808301528460a083015260e060c08301526155f260e083018486615584565b9a9950505050505050505050565b6001600160a01b0386168152846020820152836040820152608060608201526000612568608083018486615584565b60006020828403121561564157600080fd5b5051919050565b60006020828403121561565a57600080fd5b815180151581146111ce57600080fd5b6000808335601e1984360301811261568157600080fd5b83018035915067ffffffffffffffff82111561569c57600080fd5b60200191503681900382131561345f57600080fd5b60006001600160a01b038088168352861515602084015285604084015280851660608401525060a0608083015261256860a083018461553d565b600080604083850312156156fe57600080fd5b505080516020909101519092909150565b6000600160ff1b82036157245761572461545d565b5060000390565b60008261574857634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fd5b8486823790930191825260208201526040810191909152606001919050565b60008251615794818460208701615519565b919091019291505056fea264697066735822122040321861ce858a2c911db7a2e1f42f4368d23b5251b80dd661a6f2abf19c358d64736f6c63430008110033"_hex, + + // blake2_shifts + weierstrudel + sha1_div. "608060405234801561001057600080fd5b50600436106100365760003560e01c80631e0924231461003b578063d299" "dac0146102bb575b600080fd5b610282600480360360a081101561005157600080fd5b810190602081018135640100" "00000081111561006c57600080fd5b82018360208201111561007e57600080fd5b8035906020019184600183028401" @@ -490,7 +513,8 @@ const auto test_bytecode = *evmc::from_hex( "1667ffffffff000000006101008404166bffffffff0000000000000000620100008504166fffffffff000000000000" "000000000000630100000086041673ffffffff00000000000000000000000000000000640100000000870416171717" "170294505050505091905056fea165627a7a7230582083396642a98f6018c81ca24dc0c2af8e842bd33a6b8d7f0863" - "2dc1bc372e466a0029"); + "2dc1bc372e466a0029"_hex, +}; enum : uint8_t { @@ -535,49 +559,44 @@ inline bool is_push(uint8_t op) return (op & uint8_t{0b11100000}) == 0b01100000; } -[[maybe_unused]] bool x = []() noexcept { - size_t last_push = size_t(-1); - std::vector dists; - for (size_t i = 0; i < test_bytecode.size();) - { - const auto op = test_bytecode[i]; - - if (is_push(op)) - { - if (last_push != size_t(-1)) - dists.push_back(static_cast(i - last_push)); - last_push = i; - } - - i += is_push(op) ? static_cast(op - OP_PUSH1 + 2) : 1; - } - - auto sum = std::accumulate(dists.begin(), dists.end(), 0); - std::sort(dists.begin(), dists.end()); - - std::cerr << "AVG: " << double(sum) / double(dists.size()) << "\n"; - std::cerr << "MED: " << dists[dists.size() / 2] << "\n"; - - int last = 0; - int count = 0; - for (auto d : dists) - { - if (d == last) - ++count; - else - { - std::cerr << last << " x" << count << "\n"; - count = 1; - last = d; - } - } - return true; -}(); - -// uint8_t get_push_size(uint8_t x) -//{ -// return (x & 0b11111); -//} +// [[maybe_unused]] bool x = []() noexcept { +// size_t last_push = size_t(-1); +// std::vector dists; +// for (size_t i = 0; i < test_bytecode.size();) +// { +// const auto op = test_bytecode[i]; +// +// if (is_push(op)) +// { +// if (last_push != size_t(-1)) +// dists.push_back(static_cast(i - last_push)); +// last_push = i; +// } +// +// i += is_push(op) ? static_cast(op - OP_PUSH1 + 2) : 1; +// } +// +// auto sum = std::accumulate(dists.begin(), dists.end(), 0); +// std::sort(dists.begin(), dists.end()); +// +// std::cerr << "AVG: " << double(sum) / double(dists.size()) << "\n"; +// std::cerr << "MED: " << dists[dists.size() / 2] << "\n"; +// +// int last = 0; +// int count = 0; +// for (auto d : dists) +// { +// if (d == last) +// ++count; +// else +// { +// std::cerr << last << " x" << count << "\n"; +// count = 1; +// last = d; +// } +// } +// return true; +// }(); [[gnu::noinline]] auto build_vec3(const uint8_t* code, size_t code_size) { @@ -764,15 +783,16 @@ inline bool is_push(uint8_t op) template void build_jumpdest(benchmark::State& state) { + const bytes_view code = test_bytecodes[static_cast(state.range(0))]; for (auto _ : state) { - auto r = Fn(test_bytecode.data(), test_bytecode.size()); + auto r = Fn(code.data(), code.size()); benchmark::DoNotOptimize(r); } using namespace benchmark; state.counters["bytes"] = { - static_cast(static_cast(test_bytecode.size()) * state.iterations()), + static_cast(static_cast(code.size()) * state.iterations()), Counter::kIsRate}; } @@ -783,62 +803,79 @@ using namespace benchmark; template void jumpdest_analysis(State& state) { + const bytes_view code = test_bytecodes[static_cast(state.range(0))]; for (auto _ : state) { - auto r = AnalyzeFn(test_bytecode); + auto r = AnalyzeFn(code); DoNotOptimize(r); } state.counters["bytes"] = { - static_cast(static_cast(test_bytecode.size()) * state.iterations()), + static_cast(static_cast(code.size()) * state.iterations()), Counter::kIsRate}; } } // namespace -BENCHMARK(jumpdest_analysis); -BENCHMARK(jumpdest_analysis); -BENCHMARK(jumpdest_analysis); +#define ARGS ->DenseRange(0, test_bytecodes.size() - 1) + +BENCHMARK(jumpdest_analysis) ARGS; +BENCHMARK(jumpdest_analysis) ARGS; +BENCHMARK(jumpdest_analysis) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, - evmone::experimental::build_jumpdest_map_bitset1); -BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec); + evmone::experimental::build_jumpdest_map_bitset1) +ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2); + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask); + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask_v2); + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask_v2) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask2); + build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask2) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1); + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd2); + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd2) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd3); + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd3) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd4); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec6); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec7); -BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_bytes); + build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd4) +ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec5) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec6) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec7) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_bytes) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v1); + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v1) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v2); + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v2) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v3); + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v3) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v4); + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v4) +ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v8); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3p); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code4); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1p); -BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, memcpy); + build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v8) +ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3p) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code4) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, copy_by1p) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, memcpy) ARGS; From bfa0669394b462d45f3463fca91db533e000c1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 22:02:56 +0200 Subject: [PATCH 69/74] add test bytecodes --- test/internal_benchmarks/CMakeLists.txt | 2 ++ test/internal_benchmarks/test_bytecodes.cpp | 35 +++++++++++++++++++++ test/internal_benchmarks/test_bytecodes.hpp | 13 ++++++++ 3 files changed, 50 insertions(+) create mode 100644 test/internal_benchmarks/test_bytecodes.cpp create mode 100644 test/internal_benchmarks/test_bytecodes.hpp diff --git a/test/internal_benchmarks/CMakeLists.txt b/test/internal_benchmarks/CMakeLists.txt index 6369059ca9..54a29eb8aa 100644 --- a/test/internal_benchmarks/CMakeLists.txt +++ b/test/internal_benchmarks/CMakeLists.txt @@ -8,6 +8,8 @@ add_executable( evmmax_bench.cpp find_jumpdest_bench.cpp memory_allocation.cpp + test_bytecodes.hpp + test_bytecodes.cpp ) target_link_libraries(evmone-bench-internal PRIVATE evmone::evmmax evmone::experimental evmc::evmc_cpp benchmark::benchmark) diff --git a/test/internal_benchmarks/test_bytecodes.cpp b/test/internal_benchmarks/test_bytecodes.cpp new file mode 100644 index 0000000000..3315b7956f --- /dev/null +++ b/test/internal_benchmarks/test_bytecodes.cpp @@ -0,0 +1,35 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2024 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "test_bytecodes.hpp" + +namespace evmone::test +{ +// https://dune.com/queries/3700178 +const std::array test_bytecodes{ + + // WETH: + "0x6060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014757806318160ddd146101a157806323b872dd146101ca5780632e1a7d4d14610243578063313ce5671461026657806370a082311461029557806395d89b41146102e2578063a9059cbb14610370578063d0e30db0146103ca578063dd62ed3e146103d4575b6100b7610440565b005b34156100c457600080fd5b6100cc6104dd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010c5780820151818401526020810190506100f1565b50505050905090810190601f1680156101395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015257600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061057b565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461066d565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b610229600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061068c565b604051808215151515815260200191505060405180910390f35b341561024e57600080fd5b61026460048080359060200190919050506109d9565b005b341561027157600080fd5b610279610b05565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a057600080fd5b6102cc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b18565b6040518082815260200191505060405180910390f35b34156102ed57600080fd5b6102f5610b30565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561033557808201518184015260208101905061031a565b50505050905090810190601f1680156103625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561037b57600080fd5b6103b0600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610bce565b604051808215151515815260200191505060405180910390f35b6103d2610440565b005b34156103df57600080fd5b61042a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610be3565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105735780601f1061054857610100808354040283529160200191610573565b820191906000526020600020905b81548152906001019060200180831161055657829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156106dc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156107b457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156108cf5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084457600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a2757600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515610ab457600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bc65780601f10610b9b57610100808354040283529160200191610bc6565b820191906000526020600020905b815481529060010190602001808311610ba957829003601f168201915b505050505081565b6000610bdb33848461068c565b905092915050565b60046020528160005260406000206020528060005260406000206000915091505054815600a165627a7a72305820deb4c2ccab3c2fdca32ab3f46728389c2fe2c165d5fafa07661e4e004f6c344a0029"_hex, + + // Uniswap V2: https://etherscan.io/address/0x00004ee988665cdda9a1080d5792cecd16dc1220 + "0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032"_hex, + + // Uniswap: Universal Router: 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD + "0x60a0604081815260049081361015610022575b505050361561002057600080fd5b005b600092833560e01c90816301ffc9a71461093d57508063150b7a02146108af57806324856bc3146107e85780633593564c146106b1578063709a1cc21461044f578063bc197c811461038a578063f23a6e61146102f95763fa461e330361001257346102f55760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f557813590602435926044359067ffffffffffffffff918281116102f1576100db9036908301610a97565b919092878613908115806102e7575b6102bf5783850186868203126102bb5785359182116102bb5761010e9186016136d0565b5060208401359373ffffffffffffffffffffffffffffffffffffffff938486168096036102bb5761013e9161415a565b959097602b89106102935786359260178460601c98019561016d62ffffff883560601c9660481c16868b614365565b3391160361026b571561026157508186105b15610197575050505061019493503391613ac2565b80f35b9395945091929091906042871061021b5750505083601711610217577f8000000000000000000000000000000000000000000000000000000000000000821015610217577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe961021194019161020c33916141b5565b6141e2565b50505080f35b8480fd5b91969550929391508454841161023957506101949394503391613ac2565b8590517f739dbe52000000000000000000000000000000000000000000000000000000008152fd5b965085821061017f565b8483517f32b13d91000000000000000000000000000000000000000000000000000000008152fd5b8382517f3b99b53d000000000000000000000000000000000000000000000000000000008152fd5b8980fd5b8286517f316cf0eb000000000000000000000000000000000000000000000000000000008152fd5b50888813156100ea565b8680fd5b8280fd5b5082346103875760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038757610332610a2b565b5061033b610a53565b506084359067ffffffffffffffff8211610387575060209261035f91369101610a97565b5050517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b80fd5b5082346103875760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610387576103c3610a2b565b506103cc610a53565b5067ffffffffffffffff9060443582811161044b576103ee9036908601610ac5565b505060643582811161044b576104079036908601610ac5565b5050608435918211610387575060209261042391369101610a97565b5050517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b5080fd5b50346102f557602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106ad5783833567ffffffffffffffff811161044b576104a1829136908701610a97565b90818551928392833781018381520390827f0000000000000000000000000554f068365ed43dcc98dcd7fd7a8208a5638c725af16104dd613675565b50156106855780517f70a082310000000000000000000000000000000000000000000000000000000081523084820152907f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e73ffffffffffffffffffffffffffffffffffffffff168383602481845afa92831561067b578693610646575b5081517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ea37093ce161f090e443f304e1bf3a8f14d7bb40169581019586526020860184905294849186918290899082906040015b03925af193841561063c577f1e8f03f716bc104bf7d728131967a0c771e85ab54d09c1e2d6ed9e0bc4e2a16c9461060f575b5051908152a180f35b61062e90843d8611610635575b61062681836135fa565b81019061388d565b5038610606565b503d61061c565b81513d87823e3d90fd5b9092508381813d8311610674575b61065e81836135fa565b810103126106705751916105d461055b565b8580fd5b503d610654565b82513d88823e3d90fd5b9050517f7d529919000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f55767ffffffffffffffff8235818111610217576106fb9036908501610a97565b91602435908111610670576107139036908601610ac5565b92909160443542116107c0573330146107b1576001958654958773ffffffffffffffffffffffffffffffffffffffff88160361078b5750509185949391610782937fffffffffffffffffffffffff00000000000000000000000000000000000000009586339116178755610b54565b81541617905580f35b517f6f5ffb7e000000000000000000000000000000000000000000000000000000008152fd5b90919293506101949450610b54565b8585517f5bf6f916000000000000000000000000000000000000000000000000000000008152fd5b50807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f55767ffffffffffffffff8235818111610217576108319036908501610a97565b91602435908111610670576108499036908601610ac5565b9290913330146107b1576001958654958773ffffffffffffffffffffffffffffffffffffffff88160361078b5750509185949391610782937fffffffffffffffffffffffff00000000000000000000000000000000000000009586339116178755610b54565b5082346103875760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610387576108e8610a2b565b506108f1610a53565b506064359067ffffffffffffffff8211610387575060209261091591369101610a97565b5050517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b849084346102f55760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f557357fffffffff0000000000000000000000000000000000000000000000000000000081168091036102f557602092507f4e2312e0000000000000000000000000000000000000000000000000000000008114908115610a01575b81156109d7575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836109d0565b7f150b7a0200000000000000000000000000000000000000000000000000000000811491506109c9565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b9181601f84011215610a4e5782359167ffffffffffffffff8311610a4e5760208381860195010111610a4e57565b9181601f84011215610a4e5782359167ffffffffffffffff8311610a4e576020808501948460051b010111610a4e57565b919082519283825260005b848110610b405750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201610b01565b9192909260805282810361350d5791906000905b828210610b755750505050565b8382959394951015611b4c5760059282841b60805101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe19182608051360301821215610a4e578160805101359767ffffffffffffffff8911610a4e576020836080510101988036038a13610a4e57606097603f90818989013560f81c166001976020821060001461317157506010808210156127b4575060088082101561187e57508061109157505050610c2a908a614198565b92909860a08560805101013560001461108757610c6173ffffffffffffffffffffffffffffffffffffffff600154169b5b35613854565b9960408660805101013585829d927f80000000000000000000000000000000000000000000000000000000000000008314610fcf575b50959c95505b7f8000000000000000000000000000000000000000000000000000000000000000811015610a4e5760428610610fc85730915b86602b11610a4e578d91601783013560601c9083359462ffffff8660601c96610d1573ffffffffffffffffffffffffffffffffffffffff92839260481c16868a614365565b169084881015610fac57806401000276a4965b602b60405199604060208c01528160608c015260808b0137600060ab8a015216604088015260a0875260c087019587871067ffffffffffffffff881117610f7d576040948288958688527f128acb080000000000000000000000000000000000000000000000000000000087521660c48a0152868a1060e48a01526101048901521661012487015260a06101448701528160007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4088610deb610164820182610af6565b0301925af1928315610f71576000928394610f2f575b5050610e159310600014610f2857506141b5565b9a60428510610e5657309085601711610a4e5760177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe991019501949b610c9d565b50985098606091969597949392509160805101013511610efe575b1580610ed1575b610e8a57506001019291929092610b68565b90610ecd60409283519384937f2c4029e9000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190610af6565b0390fd5b507f8000000000000000000000000000000000000000000000000000000000000000828501351615610e78565b60046040517f39d35496000000000000000000000000000000000000000000000000000000008152fd5b90506141b5565b91929093506040843d604011610f69575b81610f4d604093866135fa565b8101031261038757505160e092909201519190610e1538610e01565b3d9150610f40565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8073fffd8963efd1fc6a506488495d951d5263988d2596610d28565b8b91610cd0565b60149192501061105d576020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301523560601c5afa908115610f715760009161102b575b503880610c97565b906020823d602011611055575b81611045602093836135fa565b8101031261038757505138611023565b3d9150611038565b60046040517f3b99b53d000000000000000000000000000000000000000000000000000000008152fd5b610c61309b610c5b565b6001819d969d9b989794959a999b146000146111b7575050506040926110bf84836080510101359382614198565b608051840160a00135156111ab5760606110f273ffffffffffffffffffffffffffffffffffffffff600154169435613854565b946080510101356000557f8000000000000000000000000000000000000000000000000000000000000000851015610a4e576111319361020c866141b5565b9091901561119c5750611143906141b5565b0361117357507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000555b610e71565b600490517fd4e0248e000000000000000000000000000000000000000000000000000000008152fd5b6111a691506141b5565b611143565b60606110f23094610c5b565b9194929391600281036112065750505061116e925073ffffffffffffffffffffffffffffffffffffffff600154166111ff604060608560805101013594608051010135613854565b91356139d0565b9193916003810361157857505060805181018084019390604090850312610a4e57823567ffffffffffffffff8111610a4e5782608051010192606084860312610a4e57604051946060860186811067ffffffffffffffff821117610f7d57604052602085013567ffffffffffffffff8111610a4e57850160208201809882011215610a4e5760208101359061129a826136a5565b926112a860405194856135fa565b8284526040602085019360071b830101918a8311610a4e57604001925b828410611513575050505085526112de60408501610a76565b956020860196875260606040870195013585526040846080510101359067ffffffffffffffff8211610a4e57602061131f92611325966080510101016136d0565b5061417b565b909173ffffffffffffffffffffffffffffffffffffffff600154169473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3163b15610a4e5794929391906040519586947f2a2d80d100000000000000000000000000000000000000000000000000000000865260048601526060602486015260c48501935193606060648701528451809152602060e487019501906000905b80821061149a575050509461143e9285949273ffffffffffffffffffffffffffffffffffffffff600098511660848701525160a48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc858403016044860152613537565b03818373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3165af18015610f715761148b575b50610e71565b61149490613576565b38611485565b9197965091929394602060806001928a5173ffffffffffffffffffffffffffffffffffffffff815116825273ffffffffffffffffffffffffffffffffffffffff848201511684830152606065ffffffffffff918260408201511660408501520151166060820152019801920188969795949392916113d8565b608060208584030112610a4e5760206080916040516115318161358a565b61153a87610a76565b8152611547838801610a76565b83820152611557604088016136bd565b6040820152611568606088016136bd565b60608201528152019301926112c5565b600495509193508482036116e757505090916040606061159e8286608051010135613854565b608051909501013573ffffffffffffffffffffffffffffffffffffffff908116933516806116145750479283106115ee575050806115de575b5050610e71565b6115e7916144d1565b38806115d7565b517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b9391908051937f70a082310000000000000000000000000000000000000000000000000000000085523083860152602085602481895afa9485156116dc576000956116a8575b50841061168257505081611671575b505050610e71565b61167a9261453f565b388080611669565b517f675cae38000000000000000000000000000000000000000000000000000000008152fd5b90946020823d6020116116d4575b816116c3602093836135fa565b81010312610387575051933861165a565b3d91506116b6565b82513d6000823e3d90fd5b8103611714575061116e925061170d604060608460805101013593608051010135613854565b90356138a5565b9091906006810361184e57506080510160608101359060409061173990820135613854565b9282158015611843575b61181b573573ffffffffffffffffffffffffffffffffffffffff16938461177f57505061116e92506117786127109147613984565b04906144d1565b8151907f70a082310000000000000000000000000000000000000000000000000000000082523090820152602081602481885afa91821561181157506000916117dd575b506117d661116e94939261271092613984565b049161453f565b906020823d602011611809575b816117f7602093836135fa565b810103126103875750516117d66117c3565b3d91506117ea565b513d6000823e3d90fd5b8482517fdeaa01e6000000000000000000000000000000000000000000000000000000008152fd5b506127108311611743565b83602491604051917fd76a1e9e000000000000000000000000000000000000000000000000000000008352820152fd5b819d969d9b989794959a999b93929314600014611b85575050506040916118ad83836080510101359185614198565b92909460a082608051010135600014611b7b576118e373ffffffffffffffffffffffffffffffffffffffff600154169135613854565b908615611b4c576118f385613a94565b8760011015611b4c5761191561195d9161190f60208901613a94565b90613c34565b907f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b938481611b32575b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff860193868511611b03576119b9946119be73ffffffffffffffffffffffffffffffffffffffff9687928a85613a84565b613a94565b16948651947f70a082310000000000000000000000000000000000000000000000000000000091828752841693600499858b89015260249460208987818d5afa988915611af857600099611ac3575b509160209695949391611a1f93613cad565b8751968793849283528a8301525afa928315611ab857600093611a83575b50906060611a519260805101013592613ab5565b10611a5d575050610e71565b517f849eaf98000000000000000000000000000000000000000000000000000000008152fd5b90926020823d602011611ab0575b81611a9e602093836135fa565b81010312610387575051916060611a3d565b3d9150611a91565b84513d6000823e3d90fd5b90986020823d602011611af0575b81611ade602093836135fa565b81010312610387575051976020611a0d565b3d9150611ad1565b8b513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611b4492611b3f88613a94565b613ac2565b388084611965565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6118e33091610c5b565b919492939160098103611f66575050611b9e9082614198565b608051840160a0013515611f5c57611bcf73ffffffffffffffffffffffffffffffffffffffff600154169335613854565b92611bd9836136a5565b95611be760405197886135fa565b83875283901b820160208701368211610a4e5783905b828210611f44575050506000946002875110611f1a576040816080510101359680517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111611b035790815b611ca757505060805101606001358611611c7d578215611b4c5761116e9585611c7892611b3f85613a94565b613cad565b60046040517f8ab0bc16000000000000000000000000000000000000000000000000000000008152fd5b90977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89019750888811611b035773ffffffffffffffffffffffffffffffffffffffff611cf7611d6d9984613a70565b5116611d2373ffffffffffffffffffffffffffffffffffffffff611d1b8c86613a70565b511682613c34565b819a917f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b90604051907f0902f1ac00000000000000000000000000000000000000000000000000000000825260608260048173ffffffffffffffffffffffffffffffffffffffff87165afa9a8b15610f7157600092839c611ed1575b5073ffffffffffffffffffffffffffffffffffffffff1603611eb7576dffffffffffffffffffffffffffff8091169916905b9880158015611eaf575b611e855782611e0f91613984565b916103e892838102938185041490151715611b0357611e2d91613ab5565b6103e590818102918183041490151715611b0357611e4a91613997565b60018101809111611b0357978015611b03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019081611c4c565b60046040517f7b9c8916000000000000000000000000000000000000000000000000000000008152fd5b508115611e01565b6dffffffffffffffffffffffffffff998a16991690611df7565b611f0a919c5073ffffffffffffffffffffffffffffffffffffffff935060603d8111611f13575b611f0281836135fa565b810190613c77565b509b9092611dc5565b503d611ef8565b60046040517f20db8267000000000000000000000000000000000000000000000000000000008152fd5b60208091611f5184610a76565b815201910190611bfd565b611bcf3093610c5b565b92945091600a81036120cc5750608051830160e08101358101946020808701359450909291611f9991908703018461414d565b1161105d5773ffffffffffffffffffffffffffffffffffffffff93847f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31692856001541691843b15610a4e5760409587875198899687967f2b67b570000000000000000000000000000000000000000000000000000000008852600488015261202190610a76565b166024860152808883608051010161203890610a76565b16604486015265ffffffffffff808360805101606001612057906136bd565b166064870152826080510160800161206e906136bd565b166084860152816080510160a00161208590610a76565b1660a48501526080510160c0013560c484015261010060e48401526120b1916101048401918701613537565b03815a6000948591f1908115611811575061148b5750610e71565b600b8103612296575050506120eb604080926080510101359235613854565b91807f80000000000000000000000000000000000000000000000000000000000000008103612266575050475b8061212557505050610e71565b73ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610a4e578351927fd0e30db0000000000000000000000000000000000000000000000000000000008452600493600081868187875af1801561225b5761224c575b5030908616036121b4575b5050611669565b6122139460006020948651978895869485937fa9059cbb00000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1908115611811575061222d575b808080806121ad565b6122459060203d6020116106355761062681836135fa565b5038612224565b61225590613576565b386121a2565b86513d6000823e3d90fd5b47101561211857600482517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b600c810361242657505050906122ac9035613854565b9073ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660408051937f70a08231000000000000000000000000000000000000000000000000000000008552600430818701526024916020878481885afa968715611ab8576000976123f2575b506080510183013586106123cb578561234e575b50505050505050610e71565b833b15610a4e57600091869183855196879485937f2e1a7d4d0000000000000000000000000000000000000000000000000000000085528401525af190811561181157506123bc575b5030908316036123ac575b8080808080612342565b6123b5916144d1565b38806123a2565b6123c590613576565b38612397565b82517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b90966020823d60201161241e575b8161240d602093836135fa565b81010312610387575051958361232e565b3d9150612400565b600d8103612681575082608051010191602083019360208260805101850312610a4e573567ffffffffffffffff8111610a4e57849160805101019182011215610a4e57602081013590612478826136a5565b93604093612488855196876135fa565b838652602086019285849560071b820101928311610a4e578501925b82841061261f575050505073ffffffffffffffffffffffffffffffffffffffff90816001541684519060005b8281106125b357505050817f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31691823b15610a4e5783517f0d58b1db000000000000000000000000000000000000000000000000000000008152602060048201529451602486018190528592604484019290916000915b81831061256f57505050509181600081819503925af1908115611811575061148b5750610e71565b91938395506080602091846060600195975182815116845282868201511686850152828d820151168d85015201511660608201520195019301909187949392612547565b81856125bf838a613a70565b515116036125f6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611b03576001016124d0565b600486517fe7002877000000000000000000000000000000000000000000000000000000008152fd5b608060208584030112610a4e576020608091875161263c8161358a565b61264587610a76565b8152612652838801610a76565b83820152612661898801610a76565b8982015261267160608801610a76565b60608201528152019301926124a4565b9294505050600e810361278357506040918251907f70a0823100000000000000000000000000000000000000000000000000000000825260208260248173ffffffffffffffffffffffffffffffffffffffff806004983516888301528886608051010135165afa918215611ab85760009261274e575b5060805101606001351180159290612710575050610e71565b517fa3281672000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b9038806115d7565b90916020823d60201161277b575b81612769602093836135fa565b810103126103875750519060606126f7565b3d915061275c565b602490604051907fd76a1e9e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9150915060189b95939897999692949b808310600014612d435750810361282a5750505060009250906127e883928261417b565b81604051928392833781018481520391357f00000000000000000000000000000000000000adc04c56bf30ac9d3c0aaf14dc5af1612824613675565b90610e71565b6011810361288157505050600092509061284583928261417b565b81604051928392833781018481520391357f0000000000000000000000000000000000e655fae4d56241588680f86e3b23775af1612824613675565b601281036128d857505050600092509061289c83928261417b565b81604051928392833781018481520391357f000000000000000000000000941a6d105802cccaa06de58a13a6f49ebdcd481c5af1612824613675565b919392509060138103612a3e575050909150357f000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb916040600080825160208101907f8264fe9800000000000000000000000000000000000000000000000000000000825260248781830152815261294e816135de565b5190606086608051010135885af192612965613675565b948415612a04578273ffffffffffffffffffffffffffffffffffffffff612993921694608051010135613854565b90833b15610a4e5782517f8b72a2ec00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301526024820152916000908390604490829084905af1908115611811575061148b5750610e71565b505091925050517fae9bdf0000000000000000000000000000000000000000000000000000000000602082015260048152612824816135c2565b60158103612b4f57505090604091828051917f6352211e0000000000000000000000000000000000000000000000000000000083526020836024816004976060816080510101358983015273ffffffffffffffffffffffffffffffffffffffff968791608051010135165afa928315612b4457600093612b05575b5081903516911614918215612acf575050610e71565b517f7dbe7e89000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b6020939193813d602011612b3c575b81612b21602093836135fa565b8101031261044b575190828216820361038757509181612ab9565b3d9150612b14565b85513d6000823e3d90fd5b60168103612c765750506040918251907efdd58e00000000000000000000000000000000000000000000000000000000825260208280612bc160049660608660805101013590358884016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b038173ffffffffffffffffffffffffffffffffffffffff8886608051010135165afa918215611ab857600092612c41575b5060809081510101351191821592612c0b575050610e71565b517f483a6929000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b90916020823d602011612c6e575b81612c5c602093836135fa565b81010312610387575051906080612bf2565b3d9150612c4f565b909290601714612c87575050610e71565b60409073ffffffffffffffffffffffffffffffffffffffff612caf8383608051010135613854565b93351692833b15610a4e5782517f42842e0e00000000000000000000000000000000000000000000000000000000815260805130600483015273ffffffffffffffffffffffffffffffffffffffff909216602482015291016060013560448201529160009083908183816064810103925af19081156118115750612d34575b806115d7565b612d3d90613576565b38612d2e565b9396938214159050612d7e5750505061282492507f00000000000000000000000074312363e45dcaba76c59ec49a7aa8a65a67eed391613717565b60198103612dd5575050506000925090612d9983928261417b565b81604051928392833781018481520391357f0000000000000000000000002b2e8cda09bba9660dca5cb6233787738ad683295af1612824613675565b601a8103612e2c575050506000925090612df083928261417b565b81604051928392833781018481520391357f000000000000000000000000a42f6cada809bcf417deefbdd69c5c5a909249c05af1612824613675565b601b8103612f53575050506000612e4481928461417b565b9390604094818651928392833781018481520391357f00000000000000000000000074312363e45dcaba76c59ec49a7aa8a65a67eed35af1918291612e87613675565b92612e95575b505090610e71565b73ffffffffffffffffffffffffffffffffffffffff608083815101013516612ec4606084608051010135613854565b90825190612ed1826135a6565b60008252803b15610a4e57612f2d94600080948651978895869485937ff242432a00000000000000000000000000000000000000000000000000000000855260a060c0836080510101359260805101013590306004870161380f565b03925af19081156118115750612f44575b80612e8d565b612f4d90613576565b38612f3e565b91949091601c8103612f8e5750505061282492507f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f91613717565b9193929091601d81036131175750506060816080510101359060409173ffffffffffffffffffffffffffffffffffffffff612fcf8484608051010135613854565b9435168351947efdd58e0000000000000000000000000000000000000000000000000000000086526004936020878061302e87308a84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b0381865afa96871561225b576000976130e2575b50608090815101013586106130ba57845161305c816135a6565b60008152823b15610a4e576000946130a486928851998a97889687957ff242432a0000000000000000000000000000000000000000000000000000000087523090870161380f565b03925af1908115611811575061148b5750610e71565b8385517f675cae38000000000000000000000000000000000000000000000000000000008152fd5b90966020823d60201161310f575b816130fd602093836135fa565b81010312610387575051956080613042565b3d91506130f0565b929450925050601e810361278357508161313560009392849361417b565b81604051928392833781018481520391357f00000000000000000000000020f780a973856b93f63670377900c1d2a50a77c45af1612824613675565b9499989a92506020819d9792969d989498146000146131da575050505050508061319e600093849361417b565b81604051928392833781018481520391357f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd65af1612824613675565b602190808203613351575050505090916131ff6131f7868661415a565b96909561417b565b929061324160409788519760208901997f24856bc3000000000000000000000000000000000000000000000000000000008b5260248a01526064890191613537565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc878203016044880152818152602082818301951b82010195856000915b8483106132d357505050505050505091816132c5600094938594037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b519082305af1612824613675565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085820301885288358284360301811215610a4e578301906020823592019167ffffffffffffffff8111610a4e578036038313610a4e5761334160209283928b95613537565b9a0198019695949301919061327f565b929750929593509350602281146000146127835750604080936080510101359060009060028310156134e1575050808491156000146134895750506000907f0000000000000000000000001e0049783f008a0085193e00003d00cd54003c71925b6020838251937f095ea7b3000000000000000000000000000000000000000000000000000000008552600496878601526024947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff868201526044968792355af13d15601f3d1187600051141617161561342e5750505050610e71565b91600e7f415050524f56455f4641494c45440000000000000000000000000000000000009260206064969551957f08c379a0000000000000000000000000000000000000000000000000000000008752860152840152820152fd5b036134b8576000907f0000000000000000000000002b2e8cda09bba9660dca5cb6233787738ad68329926133b2565b600482517f5461585f000000000000000000000000000000000000000000000000000000008152fd5b602492507f4e487b71000000000000000000000000000000000000000000000000000000008252600452fd5b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b67ffffffffffffffff8111610f7d57604052565b6080810190811067ffffffffffffffff821117610f7d57604052565b6020810190811067ffffffffffffffff821117610f7d57604052565b6040810190811067ffffffffffffffff821117610f7d57604052565b6060810190811067ffffffffffffffff821117610f7d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610f7d57604052565b67ffffffffffffffff8111610f7d57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156136a0573d906136868261363b565b9161369460405193846135fa565b82523d6000602084013e565b606090565b67ffffffffffffffff8111610f7d5760051b60200190565b359065ffffffffffff82168203610a4e57565b81601f82011215610a4e578035906136e78261363b565b926136f560405194856135fa565b82845260208383010111610a4e57816000926020809301838601378301015290565b919290613724908361417b565b90938460405195869384378201906000958693838580955203918635905af19261374c613675565b9284613756575050565b73ffffffffffffffffffffffffffffffffffffffff60608201351661377e6040830135613854565b91813b156106ad576040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff93909316602484015260800135604483015290919081908390606490829084905af190811561380357506137f85750565b61380190613576565b565b604051903d90823e3d90fd5b919261385195949160a09473ffffffffffffffffffffffffffffffffffffffff8092168552166020840152604083015260608201528160808201520190610af6565b90565b73ffffffffffffffffffffffffffffffffffffffff908082166001810361387e5750506001541690565b90915060020361385157503090565b90816020910312610a4e57518015158103610a4e5790565b9092919073ffffffffffffffffffffffffffffffffffffffff16806138cf575061380191926144d1565b7f80000000000000000000000000000000000000000000000000000000000000008214613902575b92613801929361453f565b9050604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481855afa938415610f7157600094613951575b5092906138f7565b6020813d821161397c575b81613969602093836135fa565b8101031261021757519350613801613949565b3d915061395c565b81810292918115918404141715611b0357565b81156139a1570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b919273ffffffffffffffffffffffffffffffffffffffff91827f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31693843b15610a4e5760009484869281608496816040519b8c9a8b997f36c78516000000000000000000000000000000000000000000000000000000008b521660048a01521660248801521660448601521660648401525af18015610f71576137f85750565b8051821015611b4c5760209160051b010190565b9190811015611b4c5760051b0190565b3573ffffffffffffffffffffffffffffffffffffffff81168103610a4e5790565b91908203918211611b0357565b92919073ffffffffffffffffffffffffffffffffffffffff8082163003613aee575050613801926138a5565b8084959411613b02576138019416926139d0565b60046040517fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff93613c2d916040519060208201927fffffffffffffffffffffffffffffffffffffffff000000000000000000000000809260601b16845260601b16603482015260288152613b8f816135de565b519020613c01604051938492602084019687917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b5190201690565b73ffffffffffffffffffffffffffffffffffffffff8281169082161015613c585791565b9091565b51906dffffffffffffffffffffffffffff82168203610a4e57565b90816060910312610a4e57613c8b81613c5c565b916040613c9a60208401613c5c565b92015163ffffffff81168103610a4e5790565b9260028210614123578115611b4c57613cc584613a94565b9160019481861015611b4c5791613ce360209461190f868601613a94565b50926000935b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84018510613d1c575050505050505050565b613d2a6119b9868685613a84565b92613d3b6119b98a88018786613a84565b936040908151957f0902f1ac00000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff80941694606092600493808a86818b5afa998a1561225b57908d9594939291600091829c6140fd575b50508780916dffffffffffffffffffffffffffff8091169c16921692168214998a6000146140f7575b8651958680947f70a082310000000000000000000000000000000000000000000000000000000082528b8883015260249889915afa9283156140ec578e6000946140bb575b5050808303918115938480156140b3575b61408b57826103e5808602958604149114171561405e57613e439083613984565b926103e880830292830414171561403157613e689291613e629161414d565b90613997565b971561402957600097905b898b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe820181101561401d579161190f6119b9613eb9936002613f039c9601908d613a84565b8198917f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b965b988551918d83019367ffffffffffffffff9484811086821117613ff057885260008452813b15610a4e5760008a93613f8382968b519c8d97889687957f022c0d9f0000000000000000000000000000000000000000000000000000000087528d8701528d860152166044840152608060648401526084830190610af6565b03925af18015611ab857908d969594939291613fa8575b505050505094019391613ce9565b909192938095965011613fc45750505287903880808080613f9a565b6041907f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b876041887f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b5050508b956000613f05565b600090613e73565b856011867f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b866011877f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b8689517f7b9c8916000000000000000000000000000000000000000000000000000000008152fd5b508115613e22565b8181959293953d83116140e5575b6140d381836135fa565b8101031261038757505191388e613e11565b503d6140c9565b87513d6000823e3d90fd5b90613dcc565b899c50899250908161411a92903d10611f1357611f0281836135fa565b509b9091613da3565b60046040517fae52ad0c000000000000000000000000000000000000000000000000000000008152fd5b91908201809211611b0357565b91823583019161417460208435958186019503018561414d565b1161105d57565b91602083013583019161417460208435958186019503018561414d565b91606083013583019161417460208435958186019503018561414d565b7f80000000000000000000000000000000000000000000000000000000000000008114611b035760000390565b939193602b841061105d578462ffffff6000614267946142ee6142999935988960601c9a8b9a61423b601789013560601c9d8e109c73ffffffffffffffffffffffffffffffffffffffff9e8f998a9460481c1691614365565b16968b861461434a576401000276a49a5b60409d8e9b8c93845196879560208701526060860191613537565b91168b830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b848851998a98899788967f128acb080000000000000000000000000000000000000000000000000000000088521660048701528c6024870152604486015216606484015260a0608484015260a4830190610af6565b03925af190811561433f576000938492614309575b50509192565b9080949250813d8311614338575b61432181836135fa565b810103126103875750602082519201513880614303565b503d614317565b83513d6000823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d259a61424c565b73ffffffffffffffffffffffffffffffffffffffff92838316848316116144c9575b62ffffff90846040519481602087019516855216604085015216606083015260608252608082019082821067ffffffffffffffff831117610f7d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80613c2d9183604052845190209361449c60a08201957fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54907f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98488917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608101845201826135fa565b909190614387565b600080809381935af1156144e157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152fd5b60009182604492602095604051937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af13d15601f3d116001600051141617161561459257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fdfea2646970667358221220b2d6a39827110492aaa15cba3556e23894a51f2f635dc99ae66d21764ad4d90b64736f6c63430008110033"_hex, + + // 0x7a250d5630b4cf539739df2c5dacb4c659f2488d + "0x60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8484614608565b90505b92915050565b60008060006113ca7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f34888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b60606113917f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8484613f60565b60008060006131107f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8e7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28b348c8c614ef2565b9094509250600061349c7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f88886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f85856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c63430006060033"_hex, + + // 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + "0x60806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633659cfe6146100775780634f1ef286146100ba5780635c60da1b146101085780638f2839701461015f578063f851a440146101a2575b6100756101f9565b005b34801561008357600080fd5b506100b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610213565b005b610106600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001919091929391929390505050610268565b005b34801561011457600080fd5b5061011d610308565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561016b57600080fd5b506101a0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610360565b005b3480156101ae57600080fd5b506101b761051e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610201610576565b61021161020c610651565b610682565b565b61021b6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025c57610257816106d9565b610265565b6102646101f9565b5b50565b6102706106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fa576102ac836106d9565b3073ffffffffffffffffffffffffffffffffffffffff163483836040518083838082843782019150509250505060006040518083038185875af19250505015156102f557600080fd5b610303565b6103026101f9565b5b505050565b60006103126106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156103545761034d610651565b905061035d565b61035c6101f9565b5b90565b6103686106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561051257600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001807f43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f81526020017f787920746f20746865207a65726f20616464726573730000000000000000000081525060400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61048f6106a8565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161050d81610748565b61051b565b61051a6101f9565b5b50565b60006105286106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561056a576105636106a8565b9050610573565b6105726101f9565b5b90565b61057e6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515610647576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e20667281526020017f6f6d207468652070726f78792061646d696e000000000000000000000000000081525060400191505060405180910390fd5b61064f610777565b565b6000807f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c36001029050805491505090565b3660008037600080366000845af43d6000803e80600081146106a3573d6000f35b3d6000fd5b6000807f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b6001029050805491505090565b6106e281610779565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b60010290508181555050565b565b60006107848261084b565b151561081e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001807f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f81526020017f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000081525060400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c360010290508181555050565b600080823b9050600081119150509190505600a165627a7a72305820a4a547cfc7202c5acaaae74d428e988bc62ad5024eb0165532d3a8f91db4ed240029"_hex, + + // 0xdac17f958d2ee523a2206206994597c13d831ec7 + "0x606060405260043610610196576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde031461019b5780630753c30c14610229578063095ea7b3146102625780630e136b19146102a45780630ecb93c0146102d157806318160ddd1461030a57806323b872dd1461033357806326976e3f1461039457806327e235e3146103e9578063313ce56714610436578063353907141461045f5780633eaaf86b146104885780633f4ba83a146104b157806359bf1abe146104c65780635c658165146105175780635c975abb1461058357806370a08231146105b05780638456cb59146105fd578063893d20e8146106125780638da5cb5b1461066757806395d89b41146106bc578063a9059cbb1461074a578063c0324c771461078c578063cc872b66146107b8578063db006a75146107db578063dd62ed3e146107fe578063dd644f721461086a578063e47d606014610893578063e4997dc5146108e4578063e5b5019a1461091d578063f2fde38b14610946578063f3bdc2281461097f575b600080fd5b34156101a657600080fd5b6101ae6109b8565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ee5780820151818401526020810190506101d3565b50505050905090810190601f16801561021b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561023457600080fd5b610260600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a56565b005b341561026d57600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610b73565b005b34156102af57600080fd5b6102b7610cc1565b604051808215151515815260200191505060405180910390f35b34156102dc57600080fd5b610308600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cd4565b005b341561031557600080fd5b61031d610ded565b6040518082815260200191505060405180910390f35b341561033e57600080fd5b610392600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610ebd565b005b341561039f57600080fd5b6103a761109d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156103f457600080fd5b610420600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506110c3565b6040518082815260200191505060405180910390f35b341561044157600080fd5b6104496110db565b6040518082815260200191505060405180910390f35b341561046a57600080fd5b6104726110e1565b6040518082815260200191505060405180910390f35b341561049357600080fd5b61049b6110e7565b6040518082815260200191505060405180910390f35b34156104bc57600080fd5b6104c46110ed565b005b34156104d157600080fd5b6104fd600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506111ab565b604051808215151515815260200191505060405180910390f35b341561052257600080fd5b61056d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611201565b6040518082815260200191505060405180910390f35b341561058e57600080fd5b610596611226565b604051808215151515815260200191505060405180910390f35b34156105bb57600080fd5b6105e7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611239565b6040518082815260200191505060405180910390f35b341561060857600080fd5b610610611348565b005b341561061d57600080fd5b610625611408565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561067257600080fd5b61067a611431565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156106c757600080fd5b6106cf611456565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561070f5780820151818401526020810190506106f4565b50505050905090810190601f16801561073c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561075557600080fd5b61078a600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506114f4565b005b341561079757600080fd5b6107b6600480803590602001909190803590602001909190505061169e565b005b34156107c357600080fd5b6107d96004808035906020019091905050611783565b005b34156107e657600080fd5b6107fc600480803590602001909190505061197a565b005b341561080957600080fd5b610854600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611b0d565b6040518082815260200191505060405180910390f35b341561087557600080fd5b61087d611c52565b6040518082815260200191505060405180910390f35b341561089e57600080fd5b6108ca600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611c58565b604051808215151515815260200191505060405180910390f35b34156108ef57600080fd5b61091b600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611c78565b005b341561092857600080fd5b610930611d91565b6040518082815260200191505060405180910390f35b341561095157600080fd5b61097d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611db5565b005b341561098a57600080fd5b6109b6600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611e8a565b005b60078054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4e5780601f10610a2357610100808354040283529160200191610a4e565b820191906000526020600020905b815481529060010190602001808311610a3157829003601f168201915b505050505081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610ab157600080fd5b6001600a60146101000a81548160ff02191690831515021790555080600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcc358699805e9a8b7f77b522628c7cb9abd07d9efb86b6fb616af1609036a99e81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b604060048101600036905010151515610b8b57600080fd5b600a60149054906101000a900460ff1615610cb157600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aee92d333385856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b1515610c9857600080fd5b6102c65a03f11515610ca957600080fd5b505050610cbc565b610cbb838361200e565b5b505050565b600a60149054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d2f57600080fd5b6001600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507f42e160154868087d6bfdc0ca23d96a1c1cfa32f1b72ba9ba27b69b98a0d819dc81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b6000600a60149054906101000a900460ff1615610eb457600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6000604051602001526040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1515610e9257600080fd5b6102c65a03f11515610ea357600080fd5b505050604051805190509050610eba565b60015490505b90565b600060149054906101000a900460ff16151515610ed957600080fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151515610f3257600080fd5b600a60149054906101000a900460ff161561108c57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638b477adb338585856040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050600060405180830381600087803b151561107357600080fd5b6102c65a03f1151561108457600080fd5b505050611098565b6110978383836121ab565b5b505050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915090505481565b60095481565b60045481565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561114857600080fd5b600060149054906101000a900460ff16151561116357600080fd5b60008060146101000a81548160ff0219169083151502179055507f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3360405160405180910390a1565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6005602052816000526040600020602052806000526040600020600091509150505481565b600060149054906101000a900460ff1681565b6000600a60149054906101000a900460ff161561133757600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561131557600080fd5b6102c65a03f1151561132657600080fd5b505050604051805190509050611343565b61134082612652565b90505b919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113a357600080fd5b600060149054906101000a900460ff161515156113bf57600080fd5b6001600060146101000a81548160ff0219169083151502179055507f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62560405160405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60088054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156114ec5780601f106114c1576101008083540402835291602001916114ec565b820191906000526020600020905b8154815290600101906020018083116114cf57829003601f168201915b505050505081565b600060149054906101000a900460ff1615151561151057600080fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151561156957600080fd5b600a60149054906101000a900460ff161561168f57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e18980a3384846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b151561167657600080fd5b6102c65a03f1151561168757600080fd5b50505061169a565b611699828261269b565b5b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116f957600080fd5b60148210151561170857600080fd5b60328110151561171757600080fd5b81600381905550611736600954600a0a82612a0390919063ffffffff16565b6004819055507fb044a1e409eac5c48e5af22d4af52670dd1a99059537a78b31b48c6500a6354e600354600454604051808381526020018281526020019250505060405180910390a15050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117de57600080fd5b60015481600154011115156117f257600080fd5b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054011115156118c257600080fd5b80600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550806001600082825401925050819055507fcb8241adb0c3fdb35b70c24ce35c5eb0c17af7431c99f827d44a445ca624176a816040518082815260200191505060405180910390a150565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156119d557600080fd5b80600154101515156119e657600080fd5b80600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515611a5557600080fd5b8060016000828254039250508190555080600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507f702d5967f45f6513a38ffc42d6ba9bf230bd40e8f53b16363c7eb4fd2deb9a44816040518082815260200191505060405180910390a150565b6000600a60149054906101000a900460ff1615611c3f57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1515611c1d57600080fd5b6102c65a03f11515611c2e57600080fd5b505050604051805190509050611c4c565b611c498383612a3e565b90505b92915050565b60035481565b60066020528060005260406000206000915054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611cd357600080fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fd7e9ec6e6ecd65492dce6bf513cd6867560d49544421d0783ddf06e76c24470c81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611e1057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611e8757806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611ee757600080fd5b600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611f3f57600080fd5b611f4882611239565b90506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550806001600082825403925050819055507f61e6e66b0d6339b2980aecc6ccc0039736791f0ccde9ed512e789a7fbdd698c68282604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15050565b60406004810160003690501015151561202657600080fd5b600082141580156120b457506000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b1515156120c057600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3505050565b60008060006060600481016000369050101515156121c857600080fd5b600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054935061227061271061226260035488612a0390919063ffffffff16565b612ac590919063ffffffff16565b92506004548311156122825760045492505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84101561233e576122bd8585612ae090919063ffffffff16565b600560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6123518386612ae090919063ffffffff16565b91506123a585600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ae090919063ffffffff16565b600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061243a82600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060008311156125e4576124f983600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a35b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a350505050505050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000806040600481016000369050101515156126b657600080fd5b6126df6127106126d160035487612a0390919063ffffffff16565b612ac590919063ffffffff16565b92506004548311156126f15760045492505b6127048385612ae090919063ffffffff16565b915061275884600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ae090919063ffffffff16565b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506127ed82600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000831115612997576128ac83600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a35b8473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a35050505050565b6000806000841415612a185760009150612a37565b8284029050828482811515612a2957fe5b04141515612a3357fe5b8091505b5092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000808284811515612ad357fe5b0490508091505092915050565b6000828211151515612aee57fe5b818303905092915050565b6000808284019050838110151515612b0d57fe5b80915050929150505600a165627a7a72305820645ee12d73db47fd78ba77fa1f824c3c8f9184061b3b10386beb4dc9236abb280029"_hex, + + // 0x1111111254eeb25477b68fb85ed929f73a960582 + "0x6080604052600436106102f65760003560e01c80637e54f0921161018f578063bf15fcd8116100e1578063d365c6951161008a578063f2fde38b11610064578063f2fde38b14610859578063f78dc25314610879578063fa461e331461088c57600080fd5b8063d365c69514610813578063e449022e14610833578063e5d7bde61461084657600080fd5b8063c805a666116100bb578063c805a66614610799578063ca4ece22146107b9578063cf6fc6e3146107d957600080fd5b8063bf15fcd814610744578063bfa7514314610764578063c53a02921461078457600080fd5b8063942461bb11610143578063bc80f1a81161011d578063bc80f1a8146106f1578063bd61951d14610704578063bddccd351461072457600080fd5b8063942461bb146106915780639570eeee146106be578063bc1ed74c146106d157600080fd5b806383197ef01161017457806383197ef01461064157806384bd6d29146106565780638da5cb5b1461066957600080fd5b80637e54f092146105f4578063825caba11461062157600080fd5b80635a0998431161024857806370ae92d2116101fc57806372c244a8116101d657806372c244a81461059457806374261145146105b457806378e3214f146105d457600080fd5b806370ae92d21461053257806370ccbd311461055f578063715018a61461057f57600080fd5b806363592c2b1161022d57806363592c2b146104d25780636c838250146104f25780636fe7b0ba1461051257600080fd5b80635a099843146104ac57806362e238bb146104bf57600080fd5b80632d9a56f6116102aa5780633eca9c0a116102845780633eca9c0a1461041b5780634f38e2b81461044957806356f161241461046957600080fd5b80632d9a56f6146103bb57806337e7316f146103db5780633c15fd91146103fb57600080fd5b806312aa3caf116102db57806312aa3caf146103435780632521b9301461036b5780632cc2878d1461038b57600080fd5b80630502b1c51461030a578063093d4fa51461033057600080fd5b36610305576103036108ac565b005b600080fd5b61031d61031836600461483f565b6108b6565b6040519081526020015b60405180910390f35b61031d61033e3660046148a9565b6108d0565b610356610351366004614975565b610d16565b60408051928352602083019190915201610327565b34801561037757600080fd5b5061031d610386366004614a17565b610fd1565b34801561039757600080fd5b506103ab6103a6366004614abf565b611001565b6040519015158152602001610327565b3480156103c757600080fd5b506103566103d6366004614af1565b61104b565b3480156103e757600080fd5b5061031d6103f6366004614af1565b61114a565b34801561040757600080fd5b5061031d610416366004614a17565b611164565b61042e610429366004614c15565b611188565b60408051938452602084019290925290820152606001610327565b34801561045557600080fd5b506103ab610464366004614c72565b6111aa565b34801561047557600080fd5b5061031d610484366004614cbe565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b61042e6104ba366004614cea565b6111d5565b61042e6104cd366004614d60565b61132b565b3480156104de57600080fd5b506103ab6104ed366004614abf565b421090565b3480156104fe57600080fd5b506103ab61050d366004614af1565b611355565b34801561051e57600080fd5b506103ab61052d366004614c72565b611384565b34801561053e57600080fd5b5061031d61054d366004614e0c565b60016020526000908152604090205481565b34801561056b57600080fd5b5061042e61057a366004614e29565b6113aa565b34801561058b57600080fd5b506103036113f1565b3480156105a057600080fd5b506103036105af366004614ecd565b611403565b3480156105c057600080fd5b506103ab6105cf366004614c72565b6114b2565b3480156105e057600080fd5b506103036105ef366004614cbe565b611524565b34801561060057600080fd5b5061031d61060f366004614abf565b60009081526002602052604090205490565b34801561062d57600080fd5b5061030361063c366004614abf565b611544565b34801561064d57600080fd5b50610303611553565b61031d610664366004614ef0565b61155e565b34801561067557600080fd5b506000546040516001600160a01b039091168152602001610327565b34801561069d57600080fd5b506106b16106ac366004614f67565b611571565b6040516103279190615001565b61042e6106cc366004615045565b61162a565b3480156106dd57600080fd5b5061031d6106ec366004614abf565b611767565b61031d6106ff36600461483f565b6117b7565b34801561071057600080fd5b5061030361071f366004615082565b6117c6565b34801561073057600080fd5b5061030361073f3660046150be565b611867565b34801561075057600080fd5b5061031d61075f366004615082565b611872565b34801561077057600080fd5b506103ab61077f366004614c72565b6118bd565b34801561079057600080fd5b50610303611930565b3480156107a557600080fd5b5061031d6107b43660046150e0565b61193a565b3480156107c557600080fd5b506103ab6107d4366004614c72565b611971565b3480156107e557600080fd5b506103ab6107f4366004614cbe565b6001600160a01b03919091166000908152600160205260409020541490565b34801561081f57600080fd5b5061042e61082e3660046151a4565b611998565b61031d610841366004615295565b611a2c565b61042e6108543660046152e8565b611a3b565b34801561086557600080fd5b50610303610874366004614e0c565b6124cb565b61031d6108873660046153ac565b612558565b34801561089857600080fd5b506103036108a7366004615416565b612573565b6108b4612785565b565b60006108c63387878787876127be565b9695505050505050565b60006001600160a01b0388161580156109085786341461090357604051631841b4e160e01b815260040160405180910390fd5b610a24565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316896001600160a01b0316036109f057506001341561096357604051631841b4e160e01b815260040160405180910390fd5b6040516323b872dd60e01b808252336004830152306024830152604482018990527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d60e01b9060008060648382885af16109c6573d6000823e3d81fd5b8181528a60048201526000806024836000885af16109e7573d6000823e3d81fd5b50505050610a24565b3415610a0f57604051631841b4e160e01b815260040160405180910390fd5b610a246001600160a01b038a16338d8a612b30565b8015610ab85760008b905060006327a9b42460e01b90506040518181528a60048201528960248201528860448201528760648201528c60848201528560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149838d875af1610ab0573d6000823e3d81fd5b505050610d07565b6001600160a01b0388161580610aff57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316886001600160a01b0316145b15610c75576040517f4cb6864c00000000000000000000000000000000000000000000000000000000808252600482018b90526024820189905260448201889052606482018790528c918a1560018114610b5e57306084830152610b65565b8d60848301525b508560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149836000875af1610bb8573d6000823e3d81fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031603610c6e57604051630d0e30db60e41b8082527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29163a9059cbb60e01b906000806004838f885af1610c42573d6000823e3d81fd5b8181528f60048201528b60248201526000806044836000885af1610c69573d6000823e3d81fd5b505050505b5050610d07565b60008b90506000632b651a6c60e01b90506040518181528b60048201528a60248201528960448201528860648201528760848201528c60a48201528560ff1c601b0160c48201528660e48201526001600160ff1b03861661010482015261014061012482015264a62929c86960d31b610163820152600080610169836000875af1610d03573d6000823e3d81fd5b5050505b50939998505050505050505050565b6000808660a00135600003610d57576040517f0262dde400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d666020890189614e0c565b90506000610d7a60408a0160208b01614e0c565b90506000610d90836001600160a01b0316612bcd565b905060c08a013560021615610dd55780610dab576000610db1565b89608001355b3411610dd057604051631841b4e160e01b815260040160405180910390fd5b610e06565b80610de1576000610de7565b89608001355b3414610e0657604051631841b4e160e01b815260040160405180910390fd5b80610e4f578715610e2557610e256001600160a01b0384168a8a612c06565b610e4f33610e3960608d0160408e01614e0c565b6001600160a01b038616919060808e0135612b30565b610e608b338c608001358a8a612cbf565b60808a01359350610e7a6001600160a01b03831630612d1f565b945084600003610eb6576040517f28ebf24700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000199094019360c08a013560011615610f4f576000610edf6001600160a01b03851630612d1f565b90506001811115610f0e5760001901610ef88186615473565b9450610f0e6001600160a01b0385163383612dca565b610f1c8560a08d0135615486565b610f2a60808d013588615486565b1015610f495760405163f32bec2f60e01b815260040160405180910390fd5b50610f74565b8960a00135851015610f745760405163f32bec2f60e01b815260040160405180910390fd5b600080610f8760808d0160608e01614e0c565b6001600160a01b031614610faa57610fa560808c0160608d01614e0c565b610fac565b335b9050610fc26001600160a01b0384168288612dca565b50505050965096945050505050565b6000610fe76001600160a01b0389168484612c06565b610ff48988888888612eaa565b9998505050505050505050565b600060d082901c60a083901c65ffffffffffff168361101f83421090565b801561104257506001600160a01b03811660009081526001602052604090205482145b95945050505050565b6000803361105f6080850160608601614e0c565b6001600160a01b03161461109f576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110a88361114a565b6000818152600260205260409020549250905060001982016110f6576040517f41a26a6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518281526020810184905233917fcbfa7d191838ece7ba4783ca3a30afd316619b7f368094b57ee7ffde9a923db1910160405180910390a26000818152600260205260409020600190559092909150565b600061115e611157613131565b8390613258565b92915050565b600061117a6001600160a01b0389168484612c06565b610ff48989898989896127be565b600080600061119a87878787336111d5565b9250925092509450945094915050565b60008060006111b985856132d7565b915091508180156111c957508581115b925050505b9392505050565b60008060006112356111e5613131565b601f198a0180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8516156112a957600160fd1b851615801590611259575060418614155b15611277576040516317c2b1f160e01b815260040160405180910390fd5b6112878860600151828989613466565b6112a4576040516317c2b1f160e01b815260040160405180910390fd5b6112d6565b6112b988606001518289896134bb565b6112d6576040516317c2b1f160e01b815260040160405180910390fd5b6112e1888686613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a1955095509592505050565b60008060006113418b8b8b8b8b8b8b8b33611a3b565b925092509250985098509895505050505050565b600080600061136b61136685613b2e565b6132d7565b9150915081801561137c5750806001145b949350505050565b600080600061139385856132d7565b915091508180156111c95750909414949350505050565b60008060006113d185858c604001516001600160a01b0316612c069092919063ffffffff16565b6113de8a8a8a8a8a6111d5565b9250925092509750975097945050505050565b6113f9613b45565b6108b46000613b9f565b8060ff16600003611440576040517fbd71636d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526001602052604081205461145e9060ff84169061549d565b336000818152600160205260409081902083905551919250907ffc69110dd11eb791755e4abd6b7d281bae236de95736d38a23782814be5e10db906114a69084815260200190565b60405180910390a25050565b60008080805b63ffffffff87821c1692508215611517576000806114db61136686868a8c6154b0565b915091508180156114ec5750806001145b156114ff576001955050505050506111ce565b50839250611510905060208261549d565b90506114b8565b5060009695505050505050565b61152c613b45565b6115406001600160a01b0383163383612dca565b5050565b61155033826000613c07565b50565b61155b613b45565b33ff5b6000610ff489338a8a8a8a8a8a8a6108d0565b60606000825167ffffffffffffffff81111561158f5761158f614b26565b6040519080825280602002602001820160405280156115b8578160200160208202803683370190505b50905060005b835181101561162357600260008583815181106115dd576115dd6154da565b6020026020010151815260200190815260200160002054828281518110611606576116066154da565b60209081029190910101528061161b816154f0565b9150506115be565b5092915050565b600080600061168a61163a613131565b601f19890180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8416156116e657600160fd1b8416156116d6576116b48760600151828888613c9b565b6116d1576040516317c2b1f160e01b815260040160405180910390fd5b611713565b6116b48760600151828888613d05565b6116f68760600151828888613d5a565b611713576040516317c2b1f160e01b815260040160405180910390fd5b61171e878533613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a19450945094915050565b600081815260026020526040812054806117ad576040517fb838de9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000190192915050565b60006108c68686868686612eaa565b600080846001600160a01b031684846040516117e3929190615509565b600060405180830381855af49150503d806000811461181e576040519150601f19603f3d011682016040523d82523d6000602084013e611823565b606091505b509150915081816040517f1934afc800000000000000000000000000000000000000000000000000000000815260040161185e929190615569565b60405180910390fd5b611540338383613c07565b6000806000611882868686613da9565b9150915081611042576040517f1f1b8f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080805b63ffffffff87821c1692508215611923576000806118e661136686868a8c6154b0565b915091508115806118f8575080600114155b1561190b576000955050505050506111ce565b5083925061191c905060208261549d565b90506118c3565b5060019695505050505050565b6108b46001611403565b60006119506001600160a01b038b168484612c06565b6119618c8c8c8c8c8c8c8c8c6108d0565b9c9b505050505050505050505050565b600080600061198085856132d7565b915091508180156111c9575094909410949350505050565b6000808060148410156119d7576040517fd9e1c6dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006119e68888613dd7565b91945092509050611a016001600160a01b0384168383612c06565b505050611a158e8e8e8e8e8e8e8e8e611a3b565b9250925092509b509b509b98505050505050505050565b60006110423386868686612eaa565b600080806001600160a01b038416611a7f576040517fb0c4d05f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a888c61114a565b6000818152600260205260409020548894508793509091508c906000198101611add576040517fecef366400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611aef60c0840160a08501614e0c565b6001600160a01b031614158015611b1e575033611b1260c0840160a08501614e0c565b6001600160a01b031614155b15611b55576040517fd4dfdafe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80611c5857611b75611b6d6080840160608501614e0c565b848f8f6134bb565b611bab576040517f5cd5d23300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060c0810135366000611bbd84613e15565b91509150600160ff1b89166000148015611bd8575060148110155b15611c51576000366000611bec8585613dd7565b91945092509050611c076001600160a01b0384168383612c06565b60008881526002602052604090205415611c4d576040517fc5f2be5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505b5050611c5d565b600019015b6000611c6883613b2e565b90501115611caf57611c7982611355565b611caf576040517fb6629c0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415841503611ce9576040517ee2a52200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611d795780851115611cfd578094505b611d1b611d0983613e23565b8460c00135888660e001358689613e31565b93506001600160ff1b038716611d318682615486565b611d3b8b87615486565b1115611d73576040517ffb8ae12900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611e44565b611d97611d8583613e67565b8460e00135878660c001358689613e75565b945080851115611dec57809450611db0611d0983613e23565b935087841115611dec576040517f939c420400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160ff1b038716611e008582615486565b611e0a8a88615486565b1015611e42576040517f481ea39200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b841580611e4f575083155b15611e86576040517ffba5a27600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84810390508060010160026000858152602001908152602001600020819055508d6060016020810190611eb99190614e0c565b6001600160a01b03167fb9ed0243fdf00f0545c63a0af8850c090d86bb46682baec4bf3c496814fe4f028483604051611efc929190918252602082015260400190565b60405180910390a26014611f0f83613e89565b905010611fb2576000366000611f2c611f2786613e89565b613dd7565b919450925090506001600160a01b0383166396a10e3387611f536080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b8152600401611f7c9897969594939291906155ad565b600060405180830381600087803b158015611f9657600080fd5b505af1158015611faa573d6000803e3d6000fd5b505050505050505b611fe5611fc56040840160208501614e0c565b611fd56080850160608601614e0c565b8888611fe087613e97565b613ea5565b61201b576040517f70a03f4800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148a106120f35760003660006120328e8e613dd7565b9250925092506000836001600160a01b031663ccee33d7338b8b87876040518663ffffffff1660e01b815260040161206e959493929190615600565b6020604051808303816000875af115801561208d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b1919061562f565b905087811180156120d057506120ce6120c987613e67565b613f00565b155b80156120e557506120e36120c987613e23565b155b156120ee578097505b505050505b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21661212d6060840160408501614e0c565b6001600160a01b03161480156121435750600034115b15612359578334101561216957604051631841b4e160e01b815260040160405180910390fd5b833411156121df57604051600090339034879003908381818185875af1925050503d80600081146121b6576040519150601f19603f3d011682016040523d82523d6000602084013e6121bb565b606091505b50509050806121dd5760405163b12d13eb60e01b815260040160405180910390fd5b505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216925063a9059cbb91506000905061229760a0860160808701614e0c565b6001600160a01b0316146122ba576122b560a0850160808601614e0c565b6122ca565b6122ca6080850160608601614e0c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018790526044016020604051808303816000875af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123539190615648565b50612411565b341561237857604051631841b4e160e01b815260040160405180910390fd5b6123db61238b6060840160408501614e0c565b33600061239e60a0870160808801614e0c565b6001600160a01b0316146123c1576123bc60a0860160808701614e0c565b6123d1565b6123d16080860160608701614e0c565b87611fe087613f75565b612411576040517f478a520500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601461241c83613f83565b9050106124ba576000366000612434611f2786613f83565b919450925090506001600160a01b038316633504ed628761245b6080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b81526004016124849897969594939291906155ad565b600060405180830381600087803b15801561249e57600080fd5b505af11580156124b2573d6000803e3d6000fd5b505050505050505b505099509950999650505050505050565b6124d3613b45565b6001600160a01b03811661254f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161185e565b61155081613b9f565b60006125688787878787876127be565b979650505050505050565b6125cc565b3d6000803e3d6000fd5b8061258f5761258f612578565b600160005114601f3d11163d151780611540577ff27f64e40000000000000000000000000000000000000000000000000000000060005260046000fd5b604051601581017f0dfe1681d21220a7ddca3f43a9059cbb23b872dd0000000000000000000000008252602081600484335afa61260b5761260b612578565b60208082016004808501335afa61262457612624612578565b602060408201600460088501335afa61263f5761263f612578565b600080600088136001811461265d5760208401519250879150612665565b835192508891505b507fff1f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000084526060832083527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460208401526001600160a01b0360558520169250338318156126f6577fb2c027220000000000000000000000000000000000000000000000000000000060005260046000fd5b60843592507f0dfe1681d21220a7ddca3f43a9059cbb23b872dd00000000000000000000000084523083146001811461275757836014860152336034860152816054860152612752602060006064601089016000885af1612582565b61277a565b33601086015281603086015261277a602060006044600c89016000885af1612582565b505050505050505050565b3233036108b4576040517f1b10b0f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128b9565b7f0902f1ac0000000000000000000000000000000000000000000000000000000081526000604082600484875afa6127ff576127ff612578565b60603d14612831577f85cd58dc0000000000000000000000000000000000000000000000000000000060005260046000fd5b81516020830151861561284057905b8785029250633b9aca008202830181840204925050507f022c0d9f000000000000000000000000000000000000000000000000000000008252841594508415810260048301528481026024830152866044830152608060648301526000608483015260008060a4846000885af16108c6576108c6612578565b6dffffffffffffffffffffffffffff8511156128f9577fcf0b4d3a0000000000000000000000000000000000000000000000000000000060005260046000fd5b60405160c081016040528260051b84018435886000811461296957341561292b57631841b4e160e01b60005260046000fd5b6323b872dd60e01b84523360048501526001600160a01b03821660248501528860448501526129646020600060648760008f5af1612582565b6129ff565b34891461298157631841b4e160e01b60005260046000fd5b630d0e30db60e41b84526000806004868c73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129b5576129b5612578565b63a9059cbb60e01b84526001600160a01b0382166004850152886024850152600080604486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129ff576129ff612578565b50879350602086015b82811015612a50578035612a446001600160a01b03821663ffffffff60a01b851660a01c600160ff1b86166001600160a01b0387168a8a6127c5565b95509150602001612a08565b50600160fe1b81168015612adf57612a873063ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b9450632e1a7d4d60e01b8452846004850152600080602486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1612ac457612ac4612578565b600080600080888f5af1612ada57612ada612578565b612b0b565b612b088b63ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b94505b50505050838110156108c65760405163f32bec2f60e01b815260040160405180910390fd5b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af19150508015612b8e573d8015612b8457600160005114601f3d11169150612b8c565b6000873b1191505b505b80612bc5576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b60006001600160a01b038216158061115e57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600060e0829003612c4457612c3d847fd505accf000000000000000000000000000000000000000000000000000000008585613f91565b9050612cac565b610100829003612c7a57612c3d847f8fcbaf0c000000000000000000000000000000000000000000000000000000008585613f91565b6040517f6827585700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80612cb957612cb9613fe3565b50505050565b6040517f4b64e4920000000000000000000000000000000000000000000000000000000080825260048201869052908284602483013784836024830101526000808460440183348b5af1612d16573d6000823e3d81fd5b50505050505050565b6000612d2a83612bcd565b15612d4057506001600160a01b0381163161115e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015612d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc3919061562f565b905061115e565b8015612ea557612dd983612bcd565b15612e915780471015612e18576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b03168261138890604051600060405180830381858888f193505050503d8060008114612e6a576040519150601f19603f3d011682016040523d82523d6000602084013e612e6f565b606091505b5050905080612cb95760405163b12d13eb60e01b815260040160405180910390fd5b612ea56001600160a01b0384168383613fef565b505050565b600081808203612ee6576040517f67e7c0f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8591506000198101341515600080600160fd1b888886818110612f0b57612f0b6154da565b90506020020135161190508115612fb157883414612f3c57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08a6040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f9757600080fd5b505af1158015612fab573d6000803e3d6000fd5b50505050505b600184111561305157612feb3083612fc95733612fcb565b305b89896000818110612fde57612fde6154da565b9050602002013588614038565b945060015b838110156130265761301c30308a8a8581811061300f5761300f6154da565b9050602002013589614038565b9550600101612ff0565b5061304a81613035578a613037565b305b30898987818110612fde57612fde6154da565b945061306f565b61306c8161305f578a613061565b305b83612fc95733612fcb565b94505b878510156130905760405163f32bec2f60e01b815260040160405180910390fd5b801561312457604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156130f857600080fd5b505af115801561310c573d6000803e3d6000fd5b50613124925050506001600160a01b038b16866141d4565b5050505095945050505050565b6000306001600160a01b037f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605821614801561318a57507f000000000000000000000000000000000000000000000000000000000000000146145b156131b457507f1c0eb4c27d5b523ca136c0b3b83a4dcac8b70225b38be8507ba1a3f2af03cfca90565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f5c6cbfb2848b981a8f93044b3530be1fac304ecd5042396ca8729cb8fdd718f3828401527fceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c160608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000368161326a61012086018661566a565b60405191935091507f0a244ca8a150ac294c14fcff9277051ced9a5b23e966a0ff0522e989da23116c9082848237828120610140820152610120876020830137818152610160902060405161190160f01b81526002810187905260228101829052604290209094506108c6565b60008060006132e685856142ed565b60e01c905060006132f986866004614317565b9050632cc2878c19820161333057600161331282611001565b61331d576000613320565b60015b90945060ff16925061345f915050565b63bf15fcd88210156133be57636fe7b0ba82101561338257634f38e2b71982016133665760016133128261046489896064614348565b6363592c2a19820161337d57600161331282421090565b61344d565b636fe7b0b91982016133a05760016133128261052d89896064614348565b637426114419820161337d576001613312826105cf89896064614348565b63ca4ece228210156134115763bf15fcd71982016133f35760016133e88261075f89896064614348565b93509350505061345f565b63bfa7514219820161337d5760016133128261077f89896064614348565b63ca4ece2119820161342f576001613312826107d489896064614348565b63cf6fc6e219820161344d576001613312826107f489896024614317565b613458308787613da9565b9350935050505b9250929050565b600080631626ba7e60e01b905060405181815285600482015260406024820152836044820152838560648301376020600085606401838a5afa156134b15760203d1460005183141692505b5050949350505050565b60006001600160a01b0385166134d35750600061137c565b60408214806134e25750604182145b80156135095750846001600160a01b03166134fe858585614378565b6001600160a01b0316145b156135165750600161137c565b61104285858585613466565b6000806001600160a01b038316613565576040517f692e45e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606085015160808601516001600160a01b031615801590613593575060808601516001600160a01b03163314155b156135ca576040517fe8c6632100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff604082901c1680158015906135e957508042115b15613620576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61362c83836000613c07565b505060a086015160c08701517f0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716600081900361366f57829550819450613715565b600160ff1b8816156136ca57828111156136b5576040517faa34b69600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8095506136c383838861442d565b9450613715565b81811115613704576040517f7f902a9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80945061371283838761445b565b95505b5050508260001480613725575081155b1561375c576040517f07b6e79f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686602001516001600160a01b03161480156137c257507f1000000000000000000000000000000000000000000000000000000000000000851615155b1561395a576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018590527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906323b872dd906064016020604051808303816000875af115801561383c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138609190615648565b50604051632e1a7d4d60e01b8152600481018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156138c357600080fd5b505af11580156138d7573d6000803e3d6000fd5b505050506000846001600160a01b03168461138890604051600060405180830381858888f193505050503d806000811461392d576040519150601f19603f3d011682016040523d82523d6000602084013e613932565b606091505b50509050806139545760405163b12d13eb60e01b815260040160405180910390fd5b50613974565b6020860151613974906001600160a01b0316828686612b30565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686604001516001600160a01b03161480156139b95750600034115b15613aec578134146139de57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a3957600080fd5b505af1158015613a4d573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018790527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063a9059cbb925060440190506020604051808303816000875af1158015613ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae69190615648565b50613b25565b3415613b0b57604051631841b4e160e01b815260040160405180910390fd5b6040860151613b25906001600160a01b0316338385612b30565b50935093915050565b366000613b3c836004614468565b91509150915091565b6000546001600160a01b031633146108b45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161185e565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038316600090815260036020908152604080832066ffffffffffffff600887901c16808552928190529220549091600160ff86161b841791808316839003613c82576040517ff71fbda200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000938452602091909152604090922091179055505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604160448201528460648201526001600160ff1b03841660848201528360ff1c601b0160a48201536020600060a5838a5afa156134b15750600051143d6020141695945050505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604060448201528460648201528360848201526020600060a4838a5afa156134b15750600051143d6020141695945050505050565b60006001600160a01b038516613d725750600061137c565b846001600160a01b0316613d878585856144c3565b6001600160a01b031603613d9d5750600161137c565b61104285858585613d05565b60008060405183858237602060008583895afa3d602014169250508115613dcf57506000515b935093915050565b600036816014841015613dfd5760405163779ab6bd60e11b815260040160405180910390fd5b505050813560601c9260149092019160131990910190565b366000613b3c836005614468565b366000613b3c836003614468565b6000868103613e4c57613e4586858761442d565b9050612568565b613e5b88888888888888614532565b98975050505050505050565b366000613b3c836002614468565b6000868103613e4c57613e4584878761445b565b366000613b3c836006614468565b366000613b3c836000614468565b6040516323b872dd60e01b8082526004820187905260248201869052604482018590526000918385606483013760206000856064018360008d5af19050600160005114601f3d11163d15178116925050509695505050505050565b60006001821480156111ce575082826000818110613f2057613f206154da565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f7800000000000000000000000000000000000000000000000000000000000000149392505050565b366000613b3c836001614468565b366000613b3c836007614468565b6000816004016040518581528385600483013760206000838360008b5af192505050801561137c573d8015613fd257600160005114601f3d11169150613fda565b6000863b1191505b50949350505050565b6040513d6000823e3d81fd5b6140028363a9059cbb60e01b84846146be565b612ea5576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600160ff1b831615801561410e576000846001600160a01b031663128acb08888461406488614700565b604080516001600160a01b038d1660208201526401000276a491016040516020818303038152906040526040518663ffffffff1660e01b81526004016140ae9594939291906156b1565b60408051808303816000875af11580156140cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f091906156eb565b915050614105816141009061570f565b614783565b9250505061137c565b6000846001600160a01b031663128acb08888461412a88614700565b604080516001600160a01b038d16602082015273fffd8963efd1fc6a506488495d951d5263988d2591016040516020818303038152906040526040518663ffffffff1660e01b81526004016141839594939291906156b1565b60408051808303816000875af11580156141a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c591906156eb565b5090506141056141008261570f565b804710156142245760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161185e565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614271576040519150601f19603f3d011682016040523d82523d6000602084013e614276565b606091505b5050905080612ea55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161185e565b600060048210156143115760405163779ab6bd60e11b815260040160405180910390fd5b50503590565b60006020820183101561433d5760405163779ab6bd60e11b815260040160405180910390fd5b509190910135919050565b3660008284101561436c5760405163779ab6bd60e11b815260040160405180910390fd5b50509182019291900390565b6000604051826041811461439757604081146143b157600091506143d9565b604085013560001a602083015260408560408401376143d9565b60208501358060ff1c601b01602084015260208660408501376001600160ff1b031660608301525b508015614425577f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16060820151101561442557848152600080526020600060808360015afa5060005191505b509392505050565b60008360018161443d8686615486565b614447919061549d565b6144519190615473565b61137c919061572b565b6000826144518584615486565b3660008060058460078111156144805761448061574d565b901b905061449261012086018661566a565b6144b79161010088013580851c63ffffffff9081169360209290921b861c16916154b0565b92509250509250929050565b60006001600160ff1b0382167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1811015614425576040518581528360ff1c601b016020820152846040820152816060820152600080526020600060808360015afa505060005195945050505050565b600060018790036145be576145478888613f00565b1561458c57858514614585576040517f49986e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5082612568565b6040517fbec74c8500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006145cd8b8b613dd7565b925092509250600080846001600160a01b031684848c8b8b6040516020016145f9959493929190615763565b60408051601f198184030181529082905261461391615782565b600060405180830381855afa9150503d806000811461464e576040519150601f19603f3d011682016040523d82523d6000602084013e614653565b606091505b509150915081158061466757508051602014155b1561469e576040517f110b8e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808060200190518101906146b2919061562f565b95505050505050612568565b60006040518481528360048201528260248201526020600060448360008a5af1915050801561137c573d8015613fd257600160005114601f3d11169150613fda565b60006001600160ff1b0382111561477f5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e74323536000000000000000000000000000000000000000000000000606482015260840161185e565b5090565b60008082121561477f5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161185e565b6001600160a01b038116811461155057600080fd5b80356147f5816147d5565b919050565b60008083601f84011261480c57600080fd5b50813567ffffffffffffffff81111561482457600080fd5b6020830191508360208260051b850101111561345f57600080fd5b60008060008060006080868803121561485757600080fd5b8535614862816147d5565b94506020860135935060408601359250606086013567ffffffffffffffff81111561488c57600080fd5b614898888289016147fa565b969995985093965092949392505050565b60008060008060008060008060006101208a8c0312156148c857600080fd5b89356148d3816147d5565b985060208a01356148e3816147d5565b975060408a01356148f3816147d5565b965060608a0135614903816147d5565b989b979a50959860808101359760a0820135975060c0820135965060e08201359550610100909101359350915050565b60008083601f84011261494557600080fd5b50813567ffffffffffffffff81111561495d57600080fd5b60208301915083602082850101111561345f57600080fd5b60008060008060008086880361014081121561499057600080fd5b873561499b816147d5565b965060e0601f19820112156149af57600080fd5b5060208701945061010087013567ffffffffffffffff808211156149d257600080fd5b6149de8a838b01614933565b90965094506101208901359150808211156149f857600080fd5b50614a0589828a01614933565b979a9699509497509295939492505050565b60008060008060008060008060c0898b031215614a3357600080fd5b8835614a3e816147d5565b97506020890135614a4e816147d5565b96506040890135955060608901359450608089013567ffffffffffffffff80821115614a7957600080fd5b614a858c838d016147fa565b909650945060a08b0135915080821115614a9e57600080fd5b50614aab8b828c01614933565b999c989b5096995094979396929594505050565b600060208284031215614ad157600080fd5b5035919050565b60006101408284031215614aeb57600080fd5b50919050565b600060208284031215614b0357600080fd5b813567ffffffffffffffff811115614b1a57600080fd5b61137c84828501614ad8565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b6557614b65614b26565b604052919050565b600060e08284031215614b7f57600080fd5b60405160e0810181811067ffffffffffffffff82111715614ba257614ba2614b26565b604052823581529050806020830135614bba816147d5565b60208201526040830135614bcd816147d5565b60408201526060830135614be0816147d5565b60608201526080830135614bf3816147d5565b8060808301525060a083013560a082015260c083013560c08201525092915050565b6000806000806101208587031215614c2c57600080fd5b614c368686614b6d565b935060e085013567ffffffffffffffff811115614c5257600080fd5b614c5e87828801614933565b959890975094956101000135949350505050565b600080600060408486031215614c8757600080fd5b83359250602084013567ffffffffffffffff811115614ca557600080fd5b614cb186828701614933565b9497909650939450505050565b60008060408385031215614cd157600080fd5b8235614cdc816147d5565b946020939093013593505050565b60008060008060006101408688031215614d0357600080fd5b614d0d8787614b6d565b945060e086013567ffffffffffffffff811115614d2957600080fd5b614d3588828901614933565b9095509350506101008601359150610120860135614d52816147d5565b809150509295509295909350565b60008060008060008060008060c0898b031215614d7c57600080fd5b883567ffffffffffffffff80821115614d9457600080fd5b614da08c838d01614ad8565b995060208b0135915080821115614db657600080fd5b614dc28c838d01614933565b909950975060408b0135915080821115614ddb57600080fd5b50614de88b828c01614933565b999c989b5096999698976060880135976080810135975060a0013595509350505050565b600060208284031215614e1e57600080fd5b81356111ce816147d5565b6000806000806000806000610160888a031215614e4557600080fd5b614e4f8989614b6d565b965060e088013567ffffffffffffffff80821115614e6c57600080fd5b614e788b838c01614933565b90985096506101008a013595506101208a01359150614e96826147d5565b9093506101408901359080821115614ead57600080fd5b50614eba8a828b01614933565b989b979a50959850939692959293505050565b600060208284031215614edf57600080fd5b813560ff811681146111ce57600080fd5b600080600080600080600080610100898b031215614f0d57600080fd5b8835614f18816147d5565b97506020890135614f28816147d5565b96506040890135614f38816147d5565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b60006020808385031215614f7a57600080fd5b823567ffffffffffffffff80821115614f9257600080fd5b818501915085601f830112614fa657600080fd5b813581811115614fb857614fb8614b26565b8060051b9150614fc9848301614b3c565b8181529183018401918481019088841115614fe357600080fd5b938501935b83851015613e5b57843582529385019390850190614fe8565b6020808252825182820181905260009190848201906040850190845b818110156150395783518352928401929184019160010161501d565b50909695505050505050565b600080600080610140858703121561505c57600080fd5b6150668686614b6d565b9660e08601359650610100860135956101200135945092505050565b60008060006040848603121561509757600080fd5b83356150a2816147d5565b9250602084013567ffffffffffffffff811115614ca557600080fd5b600080604083850312156150d157600080fd5b50508035926020909101359150565b60008060008060008060008060008060006101408c8e03121561510257600080fd5b8b3561510d816147d5565b9a5060208c013561511d816147d5565b995060408c013561512d816147d5565b985060608c013561513d816147d5565b975060808c0135965060a08c0135955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561517e57600080fd5b61518a8e828f01614933565b915080935050809150509295989b509295989b9093969950565b60008060008060008060008060008060006101008c8e0312156151c657600080fd5b67ffffffffffffffff808d3511156151dd57600080fd5b6151ea8e8e358f01614ad8565b9b508060208e013511156151fd57600080fd5b61520d8e60208f01358f01614933565b909b50995060408d013581101561522357600080fd5b6152338e60408f01358f01614933565b909950975060608d0135965060808d0135955060a08d0135945061525960c08e016147ea565b93508060e08e0135111561526c57600080fd5b5061527d8d60e08e01358e01614933565b81935080925050509295989b509295989b9093969950565b600080600080606085870312156152ab57600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156152d057600080fd5b6152dc878288016147fa565b95989497509550505050565b600080600080600080600080600060e08a8c03121561530657600080fd5b893567ffffffffffffffff8082111561531e57600080fd5b61532a8d838e01614ad8565b9a5060208c013591508082111561534057600080fd5b61534c8d838e01614933565b909a50985060408c013591508082111561536557600080fd5b506153728c828d01614933565b90975095505060608a0135935060808a0135925060a08a0135915060c08a013561539b816147d5565b809150509295985092959850929598565b60008060008060008060a087890312156153c557600080fd5b86356153d0816147d5565b955060208701356153e0816147d5565b94506040870135935060608701359250608087013567ffffffffffffffff81111561540a57600080fd5b614a0589828a016147fa565b6000806000806060858703121561542c57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561545157600080fd5b6152dc87828801614933565b634e487b7160e01b600052601160045260246000fd5b8181038181111561115e5761115e61545d565b808202811582820484141761115e5761115e61545d565b8082018082111561115e5761115e61545d565b600080858511156154c057600080fd5b838611156154cd57600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b6000600182016155025761550261545d565b5060010190565b8183823760009101908152919050565b60005b8381101561553457818101518382015260200161551c565b50506000910152565b60008151808452615555816020860160208601615519565b601f01601f19169290920160200192915050565b821515815260406020820152600061137c604083018461553d565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b88815260006001600160a01b03808a1660208401528089166040840152508660608301528560808301528460a083015260e060c08301526155f260e083018486615584565b9a9950505050505050505050565b6001600160a01b0386168152846020820152836040820152608060608201526000612568608083018486615584565b60006020828403121561564157600080fd5b5051919050565b60006020828403121561565a57600080fd5b815180151581146111ce57600080fd5b6000808335601e1984360301811261568157600080fd5b83018035915067ffffffffffffffff82111561569c57600080fd5b60200191503681900382131561345f57600080fd5b60006001600160a01b038088168352861515602084015285604084015280851660608401525060a0608083015261256860a083018461553d565b600080604083850312156156fe57600080fd5b505080516020909101519092909150565b6000600160ff1b82036157245761572461545d565b5060000390565b60008261574857634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fd5b8486823790930191825260208201526040810191909152606001919050565b60008251615794818460208701615519565b919091019291505056fea264697066735822122040321861ce858a2c911db7a2e1f42f4368d23b5251b80dd661a6f2abf19c358d64736f6c63430008110033"_hex, + + +}; +} diff --git a/test/internal_benchmarks/test_bytecodes.hpp b/test/internal_benchmarks/test_bytecodes.hpp new file mode 100644 index 0000000000..19ad2f1344 --- /dev/null +++ b/test/internal_benchmarks/test_bytecodes.hpp @@ -0,0 +1,13 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2024 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../utils/utils.hpp" +#include + +namespace evmone::test +{ +extern const std::array test_bytecodes; +} From 680b6d9d89220e60e73199231a2c76cef3457173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 22:03:19 +0200 Subject: [PATCH 70/74] clean up bench bytecodes --- test/internal_benchmarks/analysis_bench.cpp | 504 +------------------- 1 file changed, 5 insertions(+), 499 deletions(-) diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index 51d9d47127..aced7bafdc 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -5,6 +5,7 @@ #include "evmone/baseline.hpp" #include "test/experimental/jumpdest_analysis.hpp" #include "test/utils/utils.hpp" +#include "test_bytecodes.hpp" #include #include @@ -17,504 +18,7 @@ using namespace evmone::test; namespace { -const std::array test_bytecodes = { - // WETH: - "0x6060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014757806318160ddd146101a157806323b872dd146101ca5780632e1a7d4d14610243578063313ce5671461026657806370a082311461029557806395d89b41146102e2578063a9059cbb14610370578063d0e30db0146103ca578063dd62ed3e146103d4575b6100b7610440565b005b34156100c457600080fd5b6100cc6104dd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010c5780820151818401526020810190506100f1565b50505050905090810190601f1680156101395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015257600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061057b565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461066d565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b610229600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061068c565b604051808215151515815260200191505060405180910390f35b341561024e57600080fd5b61026460048080359060200190919050506109d9565b005b341561027157600080fd5b610279610b05565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a057600080fd5b6102cc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b18565b6040518082815260200191505060405180910390f35b34156102ed57600080fd5b6102f5610b30565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561033557808201518184015260208101905061031a565b50505050905090810190601f1680156103625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561037b57600080fd5b6103b0600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610bce565b604051808215151515815260200191505060405180910390f35b6103d2610440565b005b34156103df57600080fd5b61042a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610be3565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105735780601f1061054857610100808354040283529160200191610573565b820191906000526020600020905b81548152906001019060200180831161055657829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156106dc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156107b457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156108cf5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084457600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a2757600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515610ab457600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bc65780601f10610b9b57610100808354040283529160200191610bc6565b820191906000526020600020905b815481529060010190602001808311610ba957829003601f168201915b505050505081565b6000610bdb33848461068c565b905092915050565b60046020528160005260406000206020528060005260406000206000915091505054815600a165627a7a72305820deb4c2ccab3c2fdca32ab3f46728389c2fe2c165d5fafa07661e4e004f6c344a0029"_hex, - - // Uniswap V2: https://etherscan.io/address/0x00004ee988665cdda9a1080d5792cecd16dc1220 - "0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032"_hex, - - // Uniswap: Universal Router: 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD - "0x60a0604081815260049081361015610022575b505050361561002057600080fd5b005b600092833560e01c90816301ffc9a71461093d57508063150b7a02146108af57806324856bc3146107e85780633593564c146106b1578063709a1cc21461044f578063bc197c811461038a578063f23a6e61146102f95763fa461e330361001257346102f55760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f557813590602435926044359067ffffffffffffffff918281116102f1576100db9036908301610a97565b919092878613908115806102e7575b6102bf5783850186868203126102bb5785359182116102bb5761010e9186016136d0565b5060208401359373ffffffffffffffffffffffffffffffffffffffff938486168096036102bb5761013e9161415a565b959097602b89106102935786359260178460601c98019561016d62ffffff883560601c9660481c16868b614365565b3391160361026b571561026157508186105b15610197575050505061019493503391613ac2565b80f35b9395945091929091906042871061021b5750505083601711610217577f8000000000000000000000000000000000000000000000000000000000000000821015610217577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe961021194019161020c33916141b5565b6141e2565b50505080f35b8480fd5b91969550929391508454841161023957506101949394503391613ac2565b8590517f739dbe52000000000000000000000000000000000000000000000000000000008152fd5b965085821061017f565b8483517f32b13d91000000000000000000000000000000000000000000000000000000008152fd5b8382517f3b99b53d000000000000000000000000000000000000000000000000000000008152fd5b8980fd5b8286517f316cf0eb000000000000000000000000000000000000000000000000000000008152fd5b50888813156100ea565b8680fd5b8280fd5b5082346103875760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038757610332610a2b565b5061033b610a53565b506084359067ffffffffffffffff8211610387575060209261035f91369101610a97565b5050517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b80fd5b5082346103875760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610387576103c3610a2b565b506103cc610a53565b5067ffffffffffffffff9060443582811161044b576103ee9036908601610ac5565b505060643582811161044b576104079036908601610ac5565b5050608435918211610387575060209261042391369101610a97565b5050517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b5080fd5b50346102f557602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106ad5783833567ffffffffffffffff811161044b576104a1829136908701610a97565b90818551928392833781018381520390827f0000000000000000000000000554f068365ed43dcc98dcd7fd7a8208a5638c725af16104dd613675565b50156106855780517f70a082310000000000000000000000000000000000000000000000000000000081523084820152907f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e73ffffffffffffffffffffffffffffffffffffffff168383602481845afa92831561067b578693610646575b5081517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ea37093ce161f090e443f304e1bf3a8f14d7bb40169581019586526020860184905294849186918290899082906040015b03925af193841561063c577f1e8f03f716bc104bf7d728131967a0c771e85ab54d09c1e2d6ed9e0bc4e2a16c9461060f575b5051908152a180f35b61062e90843d8611610635575b61062681836135fa565b81019061388d565b5038610606565b503d61061c565b81513d87823e3d90fd5b9092508381813d8311610674575b61065e81836135fa565b810103126106705751916105d461055b565b8580fd5b503d610654565b82513d88823e3d90fd5b9050517f7d529919000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f55767ffffffffffffffff8235818111610217576106fb9036908501610a97565b91602435908111610670576107139036908601610ac5565b92909160443542116107c0573330146107b1576001958654958773ffffffffffffffffffffffffffffffffffffffff88160361078b5750509185949391610782937fffffffffffffffffffffffff00000000000000000000000000000000000000009586339116178755610b54565b81541617905580f35b517f6f5ffb7e000000000000000000000000000000000000000000000000000000008152fd5b90919293506101949450610b54565b8585517f5bf6f916000000000000000000000000000000000000000000000000000000008152fd5b50807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f55767ffffffffffffffff8235818111610217576108319036908501610a97565b91602435908111610670576108499036908601610ac5565b9290913330146107b1576001958654958773ffffffffffffffffffffffffffffffffffffffff88160361078b5750509185949391610782937fffffffffffffffffffffffff00000000000000000000000000000000000000009586339116178755610b54565b5082346103875760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610387576108e8610a2b565b506108f1610a53565b506064359067ffffffffffffffff8211610387575060209261091591369101610a97565b5050517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b849084346102f55760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f557357fffffffff0000000000000000000000000000000000000000000000000000000081168091036102f557602092507f4e2312e0000000000000000000000000000000000000000000000000000000008114908115610a01575b81156109d7575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836109d0565b7f150b7a0200000000000000000000000000000000000000000000000000000000811491506109c9565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b359073ffffffffffffffffffffffffffffffffffffffff82168203610a4e57565b9181601f84011215610a4e5782359167ffffffffffffffff8311610a4e5760208381860195010111610a4e57565b9181601f84011215610a4e5782359167ffffffffffffffff8311610a4e576020808501948460051b010111610a4e57565b919082519283825260005b848110610b405750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201610b01565b9192909260805282810361350d5791906000905b828210610b755750505050565b8382959394951015611b4c5760059282841b60805101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe19182608051360301821215610a4e578160805101359767ffffffffffffffff8911610a4e576020836080510101988036038a13610a4e57606097603f90818989013560f81c166001976020821060001461317157506010808210156127b4575060088082101561187e57508061109157505050610c2a908a614198565b92909860a08560805101013560001461108757610c6173ffffffffffffffffffffffffffffffffffffffff600154169b5b35613854565b9960408660805101013585829d927f80000000000000000000000000000000000000000000000000000000000000008314610fcf575b50959c95505b7f8000000000000000000000000000000000000000000000000000000000000000811015610a4e5760428610610fc85730915b86602b11610a4e578d91601783013560601c9083359462ffffff8660601c96610d1573ffffffffffffffffffffffffffffffffffffffff92839260481c16868a614365565b169084881015610fac57806401000276a4965b602b60405199604060208c01528160608c015260808b0137600060ab8a015216604088015260a0875260c087019587871067ffffffffffffffff881117610f7d576040948288958688527f128acb080000000000000000000000000000000000000000000000000000000087521660c48a0152868a1060e48a01526101048901521661012487015260a06101448701528160007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4088610deb610164820182610af6565b0301925af1928315610f71576000928394610f2f575b5050610e159310600014610f2857506141b5565b9a60428510610e5657309085601711610a4e5760177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe991019501949b610c9d565b50985098606091969597949392509160805101013511610efe575b1580610ed1575b610e8a57506001019291929092610b68565b90610ecd60409283519384937f2c4029e9000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190610af6565b0390fd5b507f8000000000000000000000000000000000000000000000000000000000000000828501351615610e78565b60046040517f39d35496000000000000000000000000000000000000000000000000000000008152fd5b90506141b5565b91929093506040843d604011610f69575b81610f4d604093866135fa565b8101031261038757505160e092909201519190610e1538610e01565b3d9150610f40565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8073fffd8963efd1fc6a506488495d951d5263988d2596610d28565b8b91610cd0565b60149192501061105d576020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301523560601c5afa908115610f715760009161102b575b503880610c97565b906020823d602011611055575b81611045602093836135fa565b8101031261038757505138611023565b3d9150611038565b60046040517f3b99b53d000000000000000000000000000000000000000000000000000000008152fd5b610c61309b610c5b565b6001819d969d9b989794959a999b146000146111b7575050506040926110bf84836080510101359382614198565b608051840160a00135156111ab5760606110f273ffffffffffffffffffffffffffffffffffffffff600154169435613854565b946080510101356000557f8000000000000000000000000000000000000000000000000000000000000000851015610a4e576111319361020c866141b5565b9091901561119c5750611143906141b5565b0361117357507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000555b610e71565b600490517fd4e0248e000000000000000000000000000000000000000000000000000000008152fd5b6111a691506141b5565b611143565b60606110f23094610c5b565b9194929391600281036112065750505061116e925073ffffffffffffffffffffffffffffffffffffffff600154166111ff604060608560805101013594608051010135613854565b91356139d0565b9193916003810361157857505060805181018084019390604090850312610a4e57823567ffffffffffffffff8111610a4e5782608051010192606084860312610a4e57604051946060860186811067ffffffffffffffff821117610f7d57604052602085013567ffffffffffffffff8111610a4e57850160208201809882011215610a4e5760208101359061129a826136a5565b926112a860405194856135fa565b8284526040602085019360071b830101918a8311610a4e57604001925b828410611513575050505085526112de60408501610a76565b956020860196875260606040870195013585526040846080510101359067ffffffffffffffff8211610a4e57602061131f92611325966080510101016136d0565b5061417b565b909173ffffffffffffffffffffffffffffffffffffffff600154169473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3163b15610a4e5794929391906040519586947f2a2d80d100000000000000000000000000000000000000000000000000000000865260048601526060602486015260c48501935193606060648701528451809152602060e487019501906000905b80821061149a575050509461143e9285949273ffffffffffffffffffffffffffffffffffffffff600098511660848701525160a48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc858403016044860152613537565b03818373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3165af18015610f715761148b575b50610e71565b61149490613576565b38611485565b9197965091929394602060806001928a5173ffffffffffffffffffffffffffffffffffffffff815116825273ffffffffffffffffffffffffffffffffffffffff848201511684830152606065ffffffffffff918260408201511660408501520151166060820152019801920188969795949392916113d8565b608060208584030112610a4e5760206080916040516115318161358a565b61153a87610a76565b8152611547838801610a76565b83820152611557604088016136bd565b6040820152611568606088016136bd565b60608201528152019301926112c5565b600495509193508482036116e757505090916040606061159e8286608051010135613854565b608051909501013573ffffffffffffffffffffffffffffffffffffffff908116933516806116145750479283106115ee575050806115de575b5050610e71565b6115e7916144d1565b38806115d7565b517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b9391908051937f70a082310000000000000000000000000000000000000000000000000000000085523083860152602085602481895afa9485156116dc576000956116a8575b50841061168257505081611671575b505050610e71565b61167a9261453f565b388080611669565b517f675cae38000000000000000000000000000000000000000000000000000000008152fd5b90946020823d6020116116d4575b816116c3602093836135fa565b81010312610387575051933861165a565b3d91506116b6565b82513d6000823e3d90fd5b8103611714575061116e925061170d604060608460805101013593608051010135613854565b90356138a5565b9091906006810361184e57506080510160608101359060409061173990820135613854565b9282158015611843575b61181b573573ffffffffffffffffffffffffffffffffffffffff16938461177f57505061116e92506117786127109147613984565b04906144d1565b8151907f70a082310000000000000000000000000000000000000000000000000000000082523090820152602081602481885afa91821561181157506000916117dd575b506117d661116e94939261271092613984565b049161453f565b906020823d602011611809575b816117f7602093836135fa565b810103126103875750516117d66117c3565b3d91506117ea565b513d6000823e3d90fd5b8482517fdeaa01e6000000000000000000000000000000000000000000000000000000008152fd5b506127108311611743565b83602491604051917fd76a1e9e000000000000000000000000000000000000000000000000000000008352820152fd5b819d969d9b989794959a999b93929314600014611b85575050506040916118ad83836080510101359185614198565b92909460a082608051010135600014611b7b576118e373ffffffffffffffffffffffffffffffffffffffff600154169135613854565b908615611b4c576118f385613a94565b8760011015611b4c5761191561195d9161190f60208901613a94565b90613c34565b907f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b938481611b32575b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff860193868511611b03576119b9946119be73ffffffffffffffffffffffffffffffffffffffff9687928a85613a84565b613a94565b16948651947f70a082310000000000000000000000000000000000000000000000000000000091828752841693600499858b89015260249460208987818d5afa988915611af857600099611ac3575b509160209695949391611a1f93613cad565b8751968793849283528a8301525afa928315611ab857600093611a83575b50906060611a519260805101013592613ab5565b10611a5d575050610e71565b517f849eaf98000000000000000000000000000000000000000000000000000000008152fd5b90926020823d602011611ab0575b81611a9e602093836135fa565b81010312610387575051916060611a3d565b3d9150611a91565b84513d6000823e3d90fd5b90986020823d602011611af0575b81611ade602093836135fa565b81010312610387575051976020611a0d565b3d9150611ad1565b8b513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b611b4492611b3f88613a94565b613ac2565b388084611965565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6118e33091610c5b565b919492939160098103611f66575050611b9e9082614198565b608051840160a0013515611f5c57611bcf73ffffffffffffffffffffffffffffffffffffffff600154169335613854565b92611bd9836136a5565b95611be760405197886135fa565b83875283901b820160208701368211610a4e5783905b828210611f44575050506000946002875110611f1a576040816080510101359680517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111611b035790815b611ca757505060805101606001358611611c7d578215611b4c5761116e9585611c7892611b3f85613a94565b613cad565b60046040517f8ab0bc16000000000000000000000000000000000000000000000000000000008152fd5b90977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89019750888811611b035773ffffffffffffffffffffffffffffffffffffffff611cf7611d6d9984613a70565b5116611d2373ffffffffffffffffffffffffffffffffffffffff611d1b8c86613a70565b511682613c34565b819a917f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b90604051907f0902f1ac00000000000000000000000000000000000000000000000000000000825260608260048173ffffffffffffffffffffffffffffffffffffffff87165afa9a8b15610f7157600092839c611ed1575b5073ffffffffffffffffffffffffffffffffffffffff1603611eb7576dffffffffffffffffffffffffffff8091169916905b9880158015611eaf575b611e855782611e0f91613984565b916103e892838102938185041490151715611b0357611e2d91613ab5565b6103e590818102918183041490151715611b0357611e4a91613997565b60018101809111611b0357978015611b03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019081611c4c565b60046040517f7b9c8916000000000000000000000000000000000000000000000000000000008152fd5b508115611e01565b6dffffffffffffffffffffffffffff998a16991690611df7565b611f0a919c5073ffffffffffffffffffffffffffffffffffffffff935060603d8111611f13575b611f0281836135fa565b810190613c77565b509b9092611dc5565b503d611ef8565b60046040517f20db8267000000000000000000000000000000000000000000000000000000008152fd5b60208091611f5184610a76565b815201910190611bfd565b611bcf3093610c5b565b92945091600a81036120cc5750608051830160e08101358101946020808701359450909291611f9991908703018461414d565b1161105d5773ffffffffffffffffffffffffffffffffffffffff93847f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31692856001541691843b15610a4e5760409587875198899687967f2b67b570000000000000000000000000000000000000000000000000000000008852600488015261202190610a76565b166024860152808883608051010161203890610a76565b16604486015265ffffffffffff808360805101606001612057906136bd565b166064870152826080510160800161206e906136bd565b166084860152816080510160a00161208590610a76565b1660a48501526080510160c0013560c484015261010060e48401526120b1916101048401918701613537565b03815a6000948591f1908115611811575061148b5750610e71565b600b8103612296575050506120eb604080926080510101359235613854565b91807f80000000000000000000000000000000000000000000000000000000000000008103612266575050475b8061212557505050610e71565b73ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b15610a4e578351927fd0e30db0000000000000000000000000000000000000000000000000000000008452600493600081868187875af1801561225b5761224c575b5030908616036121b4575b5050611669565b6122139460006020948651978895869485937fa9059cbb00000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1908115611811575061222d575b808080806121ad565b6122459060203d6020116106355761062681836135fa565b5038612224565b61225590613576565b386121a2565b86513d6000823e3d90fd5b47101561211857600482517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b600c810361242657505050906122ac9035613854565b9073ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660408051937f70a08231000000000000000000000000000000000000000000000000000000008552600430818701526024916020878481885afa968715611ab8576000976123f2575b506080510183013586106123cb578561234e575b50505050505050610e71565b833b15610a4e57600091869183855196879485937f2e1a7d4d0000000000000000000000000000000000000000000000000000000085528401525af190811561181157506123bc575b5030908316036123ac575b8080808080612342565b6123b5916144d1565b38806123a2565b6123c590613576565b38612397565b82517f6a12f104000000000000000000000000000000000000000000000000000000008152fd5b90966020823d60201161241e575b8161240d602093836135fa565b81010312610387575051958361232e565b3d9150612400565b600d8103612681575082608051010191602083019360208260805101850312610a4e573567ffffffffffffffff8111610a4e57849160805101019182011215610a4e57602081013590612478826136a5565b93604093612488855196876135fa565b838652602086019285849560071b820101928311610a4e578501925b82841061261f575050505073ffffffffffffffffffffffffffffffffffffffff90816001541684519060005b8281106125b357505050817f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31691823b15610a4e5783517f0d58b1db000000000000000000000000000000000000000000000000000000008152602060048201529451602486018190528592604484019290916000915b81831061256f57505050509181600081819503925af1908115611811575061148b5750610e71565b91938395506080602091846060600195975182815116845282868201511686850152828d820151168d85015201511660608201520195019301909187949392612547565b81856125bf838a613a70565b515116036125f6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611b03576001016124d0565b600486517fe7002877000000000000000000000000000000000000000000000000000000008152fd5b608060208584030112610a4e576020608091875161263c8161358a565b61264587610a76565b8152612652838801610a76565b83820152612661898801610a76565b8982015261267160608801610a76565b60608201528152019301926124a4565b9294505050600e810361278357506040918251907f70a0823100000000000000000000000000000000000000000000000000000000825260208260248173ffffffffffffffffffffffffffffffffffffffff806004983516888301528886608051010135165afa918215611ab85760009261274e575b5060805101606001351180159290612710575050610e71565b517fa3281672000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b9038806115d7565b90916020823d60201161277b575b81612769602093836135fa565b810103126103875750519060606126f7565b3d915061275c565b602490604051907fd76a1e9e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9150915060189b95939897999692949b808310600014612d435750810361282a5750505060009250906127e883928261417b565b81604051928392833781018481520391357f00000000000000000000000000000000000000adc04c56bf30ac9d3c0aaf14dc5af1612824613675565b90610e71565b6011810361288157505050600092509061284583928261417b565b81604051928392833781018481520391357f0000000000000000000000000000000000e655fae4d56241588680f86e3b23775af1612824613675565b601281036128d857505050600092509061289c83928261417b565b81604051928392833781018481520391357f000000000000000000000000941a6d105802cccaa06de58a13a6f49ebdcd481c5af1612824613675565b919392509060138103612a3e575050909150357f000000000000000000000000b47e3cd837ddf8e4c57f05d70ab865de6e193bbb916040600080825160208101907f8264fe9800000000000000000000000000000000000000000000000000000000825260248781830152815261294e816135de565b5190606086608051010135885af192612965613675565b948415612a04578273ffffffffffffffffffffffffffffffffffffffff612993921694608051010135613854565b90833b15610a4e5782517f8b72a2ec00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301526024820152916000908390604490829084905af1908115611811575061148b5750610e71565b505091925050517fae9bdf0000000000000000000000000000000000000000000000000000000000602082015260048152612824816135c2565b60158103612b4f57505090604091828051917f6352211e0000000000000000000000000000000000000000000000000000000083526020836024816004976060816080510101358983015273ffffffffffffffffffffffffffffffffffffffff968791608051010135165afa928315612b4457600093612b05575b5081903516911614918215612acf575050610e71565b517f7dbe7e89000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b6020939193813d602011612b3c575b81612b21602093836135fa565b8101031261044b575190828216820361038757509181612ab9565b3d9150612b14565b85513d6000823e3d90fd5b60168103612c765750506040918251907efdd58e00000000000000000000000000000000000000000000000000000000825260208280612bc160049660608660805101013590358884016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b038173ffffffffffffffffffffffffffffffffffffffff8886608051010135165afa918215611ab857600092612c41575b5060809081510101351191821592612c0b575050610e71565b517f483a6929000000000000000000000000000000000000000000000000000000006020820152908152909150612746816135c2565b90916020823d602011612c6e575b81612c5c602093836135fa565b81010312610387575051906080612bf2565b3d9150612c4f565b909290601714612c87575050610e71565b60409073ffffffffffffffffffffffffffffffffffffffff612caf8383608051010135613854565b93351692833b15610a4e5782517f42842e0e00000000000000000000000000000000000000000000000000000000815260805130600483015273ffffffffffffffffffffffffffffffffffffffff909216602482015291016060013560448201529160009083908183816064810103925af19081156118115750612d34575b806115d7565b612d3d90613576565b38612d2e565b9396938214159050612d7e5750505061282492507f00000000000000000000000074312363e45dcaba76c59ec49a7aa8a65a67eed391613717565b60198103612dd5575050506000925090612d9983928261417b565b81604051928392833781018481520391357f0000000000000000000000002b2e8cda09bba9660dca5cb6233787738ad683295af1612824613675565b601a8103612e2c575050506000925090612df083928261417b565b81604051928392833781018481520391357f000000000000000000000000a42f6cada809bcf417deefbdd69c5c5a909249c05af1612824613675565b601b8103612f53575050506000612e4481928461417b565b9390604094818651928392833781018481520391357f00000000000000000000000074312363e45dcaba76c59ec49a7aa8a65a67eed35af1918291612e87613675565b92612e95575b505090610e71565b73ffffffffffffffffffffffffffffffffffffffff608083815101013516612ec4606084608051010135613854565b90825190612ed1826135a6565b60008252803b15610a4e57612f2d94600080948651978895869485937ff242432a00000000000000000000000000000000000000000000000000000000855260a060c0836080510101359260805101013590306004870161380f565b03925af19081156118115750612f44575b80612e8d565b612f4d90613576565b38612f3e565b91949091601c8103612f8e5750505061282492507f000000000000000000000000cda72070e455bb31c7690a170224ce43623d0b6f91613717565b9193929091601d81036131175750506060816080510101359060409173ffffffffffffffffffffffffffffffffffffffff612fcf8484608051010135613854565b9435168351947efdd58e0000000000000000000000000000000000000000000000000000000086526004936020878061302e87308a84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b0381865afa96871561225b576000976130e2575b50608090815101013586106130ba57845161305c816135a6565b60008152823b15610a4e576000946130a486928851998a97889687957ff242432a0000000000000000000000000000000000000000000000000000000087523090870161380f565b03925af1908115611811575061148b5750610e71565b8385517f675cae38000000000000000000000000000000000000000000000000000000008152fd5b90966020823d60201161310f575b816130fd602093836135fa565b81010312610387575051956080613042565b3d91506130f0565b929450925050601e810361278357508161313560009392849361417b565b81604051928392833781018481520391357f00000000000000000000000020f780a973856b93f63670377900c1d2a50a77c45af1612824613675565b9499989a92506020819d9792969d989498146000146131da575050505050508061319e600093849361417b565b81604051928392833781018481520391357f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd65af1612824613675565b602190808203613351575050505090916131ff6131f7868661415a565b96909561417b565b929061324160409788519760208901997f24856bc3000000000000000000000000000000000000000000000000000000008b5260248a01526064890191613537565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc878203016044880152818152602082818301951b82010195856000915b8483106132d357505050505050505091816132c5600094938594037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b519082305af1612824613675565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085820301885288358284360301811215610a4e578301906020823592019167ffffffffffffffff8111610a4e578036038313610a4e5761334160209283928b95613537565b9a0198019695949301919061327f565b929750929593509350602281146000146127835750604080936080510101359060009060028310156134e1575050808491156000146134895750506000907f0000000000000000000000001e0049783f008a0085193e00003d00cd54003c71925b6020838251937f095ea7b3000000000000000000000000000000000000000000000000000000008552600496878601526024947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff868201526044968792355af13d15601f3d1187600051141617161561342e5750505050610e71565b91600e7f415050524f56455f4641494c45440000000000000000000000000000000000009260206064969551957f08c379a0000000000000000000000000000000000000000000000000000000008752860152840152820152fd5b036134b8576000907f0000000000000000000000002b2e8cda09bba9660dca5cb6233787738ad68329926133b2565b600482517f5461585f000000000000000000000000000000000000000000000000000000008152fd5b602492507f4e487b71000000000000000000000000000000000000000000000000000000008252600452fd5b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b67ffffffffffffffff8111610f7d57604052565b6080810190811067ffffffffffffffff821117610f7d57604052565b6020810190811067ffffffffffffffff821117610f7d57604052565b6040810190811067ffffffffffffffff821117610f7d57604052565b6060810190811067ffffffffffffffff821117610f7d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610f7d57604052565b67ffffffffffffffff8111610f7d57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156136a0573d906136868261363b565b9161369460405193846135fa565b82523d6000602084013e565b606090565b67ffffffffffffffff8111610f7d5760051b60200190565b359065ffffffffffff82168203610a4e57565b81601f82011215610a4e578035906136e78261363b565b926136f560405194856135fa565b82845260208383010111610a4e57816000926020809301838601378301015290565b919290613724908361417b565b90938460405195869384378201906000958693838580955203918635905af19261374c613675565b9284613756575050565b73ffffffffffffffffffffffffffffffffffffffff60608201351661377e6040830135613854565b91813b156106ad576040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff93909316602484015260800135604483015290919081908390606490829084905af190811561380357506137f85750565b61380190613576565b565b604051903d90823e3d90fd5b919261385195949160a09473ffffffffffffffffffffffffffffffffffffffff8092168552166020840152604083015260608201528160808201520190610af6565b90565b73ffffffffffffffffffffffffffffffffffffffff908082166001810361387e5750506001541690565b90915060020361385157503090565b90816020910312610a4e57518015158103610a4e5790565b9092919073ffffffffffffffffffffffffffffffffffffffff16806138cf575061380191926144d1565b7f80000000000000000000000000000000000000000000000000000000000000008214613902575b92613801929361453f565b9050604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481855afa938415610f7157600094613951575b5092906138f7565b6020813d821161397c575b81613969602093836135fa565b8101031261021757519350613801613949565b3d915061395c565b81810292918115918404141715611b0357565b81156139a1570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b919273ffffffffffffffffffffffffffffffffffffffff91827f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31693843b15610a4e5760009484869281608496816040519b8c9a8b997f36c78516000000000000000000000000000000000000000000000000000000008b521660048a01521660248801521660448601521660648401525af18015610f71576137f85750565b8051821015611b4c5760209160051b010190565b9190811015611b4c5760051b0190565b3573ffffffffffffffffffffffffffffffffffffffff81168103610a4e5790565b91908203918211611b0357565b92919073ffffffffffffffffffffffffffffffffffffffff8082163003613aee575050613801926138a5565b8084959411613b02576138019416926139d0565b60046040517fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff93613c2d916040519060208201927fffffffffffffffffffffffffffffffffffffffff000000000000000000000000809260601b16845260601b16603482015260288152613b8f816135de565b519020613c01604051938492602084019687917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b5190201690565b73ffffffffffffffffffffffffffffffffffffffff8281169082161015613c585791565b9091565b51906dffffffffffffffffffffffffffff82168203610a4e57565b90816060910312610a4e57613c8b81613c5c565b916040613c9a60208401613c5c565b92015163ffffffff81168103610a4e5790565b9260028210614123578115611b4c57613cc584613a94565b9160019481861015611b4c5791613ce360209461190f868601613a94565b50926000935b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84018510613d1c575050505050505050565b613d2a6119b9868685613a84565b92613d3b6119b98a88018786613a84565b936040908151957f0902f1ac00000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff80941694606092600493808a86818b5afa998a1561225b57908d9594939291600091829c6140fd575b50508780916dffffffffffffffffffffffffffff8091169c16921692168214998a6000146140f7575b8651958680947f70a082310000000000000000000000000000000000000000000000000000000082528b8883015260249889915afa9283156140ec578e6000946140bb575b5050808303918115938480156140b3575b61408b57826103e5808602958604149114171561405e57613e439083613984565b926103e880830292830414171561403157613e689291613e629161414d565b90613997565b971561402957600097905b898b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe820181101561401d579161190f6119b9613eb9936002613f039c9601908d613a84565b8198917f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f613b2c565b965b988551918d83019367ffffffffffffffff9484811086821117613ff057885260008452813b15610a4e5760008a93613f8382968b519c8d97889687957f022c0d9f0000000000000000000000000000000000000000000000000000000087528d8701528d860152166044840152608060648401526084830190610af6565b03925af18015611ab857908d969594939291613fa8575b505050505094019391613ce9565b909192938095965011613fc45750505287903880808080613f9a565b6041907f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b876041887f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b5050508b956000613f05565b600090613e73565b856011867f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b866011877f4e487b7100000000000000000000000000000000000000000000000000000000600052526000fd5b8689517f7b9c8916000000000000000000000000000000000000000000000000000000008152fd5b508115613e22565b8181959293953d83116140e5575b6140d381836135fa565b8101031261038757505191388e613e11565b503d6140c9565b87513d6000823e3d90fd5b90613dcc565b899c50899250908161411a92903d10611f1357611f0281836135fa565b509b9091613da3565b60046040517fae52ad0c000000000000000000000000000000000000000000000000000000008152fd5b91908201809211611b0357565b91823583019161417460208435958186019503018561414d565b1161105d57565b91602083013583019161417460208435958186019503018561414d565b91606083013583019161417460208435958186019503018561414d565b7f80000000000000000000000000000000000000000000000000000000000000008114611b035760000390565b939193602b841061105d578462ffffff6000614267946142ee6142999935988960601c9a8b9a61423b601789013560601c9d8e109c73ffffffffffffffffffffffffffffffffffffffff9e8f998a9460481c1691614365565b16968b861461434a576401000276a49a5b60409d8e9b8c93845196879560208701526060860191613537565b91168b830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826135fa565b848851998a98899788967f128acb080000000000000000000000000000000000000000000000000000000088521660048701528c6024870152604486015216606484015260a0608484015260a4830190610af6565b03925af190811561433f576000938492614309575b50509192565b9080949250813d8311614338575b61432181836135fa565b810103126103875750602082519201513880614303565b503d614317565b83513d6000823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d259a61424c565b73ffffffffffffffffffffffffffffffffffffffff92838316848316116144c9575b62ffffff90846040519481602087019516855216604085015216606083015260608252608082019082821067ffffffffffffffff831117610f7d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80613c2d9183604052845190209361449c60a08201957fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54907f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98488917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608101845201826135fa565b909190614387565b600080809381935af1156144e157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152fd5b60009182604492602095604051937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af13d15601f3d116001600051141617161561459257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fdfea2646970667358221220b2d6a39827110492aaa15cba3556e23894a51f2f635dc99ae66d21764ad4d90b64736f6c63430008110033"_hex, - - // 0x7a250d5630b4cf539739df2c5dacb4c659f2488d - "0x60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8484614608565b90505b92915050565b60008060006113ca7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f34888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b60606113917f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8484613f60565b60008060006131107f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8e7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28b348c8c614ef2565b9094509250600061349c7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f89896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f88886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f85856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f8b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c63430006060033"_hex, - - // 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 - "0x60806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633659cfe6146100775780634f1ef286146100ba5780635c60da1b146101085780638f2839701461015f578063f851a440146101a2575b6100756101f9565b005b34801561008357600080fd5b506100b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610213565b005b610106600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001919091929391929390505050610268565b005b34801561011457600080fd5b5061011d610308565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561016b57600080fd5b506101a0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610360565b005b3480156101ae57600080fd5b506101b761051e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610201610576565b61021161020c610651565b610682565b565b61021b6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025c57610257816106d9565b610265565b6102646101f9565b5b50565b6102706106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fa576102ac836106d9565b3073ffffffffffffffffffffffffffffffffffffffff163483836040518083838082843782019150509250505060006040518083038185875af19250505015156102f557600080fd5b610303565b6103026101f9565b5b505050565b60006103126106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156103545761034d610651565b905061035d565b61035c6101f9565b5b90565b6103686106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561051257600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001807f43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f81526020017f787920746f20746865207a65726f20616464726573730000000000000000000081525060400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61048f6106a8565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161050d81610748565b61051b565b61051a6101f9565b5b50565b60006105286106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561056a576105636106a8565b9050610573565b6105726101f9565b5b90565b61057e6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515610647576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e20667281526020017f6f6d207468652070726f78792061646d696e000000000000000000000000000081525060400191505060405180910390fd5b61064f610777565b565b6000807f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c36001029050805491505090565b3660008037600080366000845af43d6000803e80600081146106a3573d6000f35b3d6000fd5b6000807f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b6001029050805491505090565b6106e281610779565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b60010290508181555050565b565b60006107848261084b565b151561081e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001807f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f81526020017f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000081525060400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c360010290508181555050565b600080823b9050600081119150509190505600a165627a7a72305820a4a547cfc7202c5acaaae74d428e988bc62ad5024eb0165532d3a8f91db4ed240029"_hex, - - // 0xdac17f958d2ee523a2206206994597c13d831ec7 - "0x606060405260043610610196576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde031461019b5780630753c30c14610229578063095ea7b3146102625780630e136b19146102a45780630ecb93c0146102d157806318160ddd1461030a57806323b872dd1461033357806326976e3f1461039457806327e235e3146103e9578063313ce56714610436578063353907141461045f5780633eaaf86b146104885780633f4ba83a146104b157806359bf1abe146104c65780635c658165146105175780635c975abb1461058357806370a08231146105b05780638456cb59146105fd578063893d20e8146106125780638da5cb5b1461066757806395d89b41146106bc578063a9059cbb1461074a578063c0324c771461078c578063cc872b66146107b8578063db006a75146107db578063dd62ed3e146107fe578063dd644f721461086a578063e47d606014610893578063e4997dc5146108e4578063e5b5019a1461091d578063f2fde38b14610946578063f3bdc2281461097f575b600080fd5b34156101a657600080fd5b6101ae6109b8565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ee5780820151818401526020810190506101d3565b50505050905090810190601f16801561021b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561023457600080fd5b610260600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a56565b005b341561026d57600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610b73565b005b34156102af57600080fd5b6102b7610cc1565b604051808215151515815260200191505060405180910390f35b34156102dc57600080fd5b610308600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cd4565b005b341561031557600080fd5b61031d610ded565b6040518082815260200191505060405180910390f35b341561033e57600080fd5b610392600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610ebd565b005b341561039f57600080fd5b6103a761109d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156103f457600080fd5b610420600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506110c3565b6040518082815260200191505060405180910390f35b341561044157600080fd5b6104496110db565b6040518082815260200191505060405180910390f35b341561046a57600080fd5b6104726110e1565b6040518082815260200191505060405180910390f35b341561049357600080fd5b61049b6110e7565b6040518082815260200191505060405180910390f35b34156104bc57600080fd5b6104c46110ed565b005b34156104d157600080fd5b6104fd600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506111ab565b604051808215151515815260200191505060405180910390f35b341561052257600080fd5b61056d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611201565b6040518082815260200191505060405180910390f35b341561058e57600080fd5b610596611226565b604051808215151515815260200191505060405180910390f35b34156105bb57600080fd5b6105e7600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611239565b6040518082815260200191505060405180910390f35b341561060857600080fd5b610610611348565b005b341561061d57600080fd5b610625611408565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561067257600080fd5b61067a611431565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156106c757600080fd5b6106cf611456565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561070f5780820151818401526020810190506106f4565b50505050905090810190601f16801561073c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561075557600080fd5b61078a600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506114f4565b005b341561079757600080fd5b6107b6600480803590602001909190803590602001909190505061169e565b005b34156107c357600080fd5b6107d96004808035906020019091905050611783565b005b34156107e657600080fd5b6107fc600480803590602001909190505061197a565b005b341561080957600080fd5b610854600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611b0d565b6040518082815260200191505060405180910390f35b341561087557600080fd5b61087d611c52565b6040518082815260200191505060405180910390f35b341561089e57600080fd5b6108ca600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611c58565b604051808215151515815260200191505060405180910390f35b34156108ef57600080fd5b61091b600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611c78565b005b341561092857600080fd5b610930611d91565b6040518082815260200191505060405180910390f35b341561095157600080fd5b61097d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611db5565b005b341561098a57600080fd5b6109b6600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611e8a565b005b60078054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4e5780601f10610a2357610100808354040283529160200191610a4e565b820191906000526020600020905b815481529060010190602001808311610a3157829003601f168201915b505050505081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610ab157600080fd5b6001600a60146101000a81548160ff02191690831515021790555080600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcc358699805e9a8b7f77b522628c7cb9abd07d9efb86b6fb616af1609036a99e81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b604060048101600036905010151515610b8b57600080fd5b600a60149054906101000a900460ff1615610cb157600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aee92d333385856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b1515610c9857600080fd5b6102c65a03f11515610ca957600080fd5b505050610cbc565b610cbb838361200e565b5b505050565b600a60149054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d2f57600080fd5b6001600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507f42e160154868087d6bfdc0ca23d96a1c1cfa32f1b72ba9ba27b69b98a0d819dc81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b6000600a60149054906101000a900460ff1615610eb457600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6000604051602001526040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1515610e9257600080fd5b6102c65a03f11515610ea357600080fd5b505050604051805190509050610eba565b60015490505b90565b600060149054906101000a900460ff16151515610ed957600080fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151515610f3257600080fd5b600a60149054906101000a900460ff161561108c57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638b477adb338585856040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050600060405180830381600087803b151561107357600080fd5b6102c65a03f1151561108457600080fd5b505050611098565b6110978383836121ab565b5b505050565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915090505481565b60095481565b60045481565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561114857600080fd5b600060149054906101000a900460ff16151561116357600080fd5b60008060146101000a81548160ff0219169083151502179055507f7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b3360405160405180910390a1565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6005602052816000526040600020602052806000526040600020600091509150505481565b600060149054906101000a900460ff1681565b6000600a60149054906101000a900460ff161561133757600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561131557600080fd5b6102c65a03f1151561132657600080fd5b505050604051805190509050611343565b61134082612652565b90505b919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113a357600080fd5b600060149054906101000a900460ff161515156113bf57600080fd5b6001600060146101000a81548160ff0219169083151502179055507f6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff62560405160405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60088054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156114ec5780601f106114c1576101008083540402835291602001916114ec565b820191906000526020600020905b8154815290600101906020018083116114cf57829003601f168201915b505050505081565b600060149054906101000a900460ff1615151561151057600080fd5b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615151561156957600080fd5b600a60149054906101000a900460ff161561168f57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e18980a3384846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b151561167657600080fd5b6102c65a03f1151561168757600080fd5b50505061169a565b611699828261269b565b5b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116f957600080fd5b60148210151561170857600080fd5b60328110151561171757600080fd5b81600381905550611736600954600a0a82612a0390919063ffffffff16565b6004819055507fb044a1e409eac5c48e5af22d4af52670dd1a99059537a78b31b48c6500a6354e600354600454604051808381526020018281526020019250505060405180910390a15050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117de57600080fd5b60015481600154011115156117f257600080fd5b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054011115156118c257600080fd5b80600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550806001600082825401925050819055507fcb8241adb0c3fdb35b70c24ce35c5eb0c17af7431c99f827d44a445ca624176a816040518082815260200191505060405180910390a150565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156119d557600080fd5b80600154101515156119e657600080fd5b80600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515611a5557600080fd5b8060016000828254039250508190555080600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507f702d5967f45f6513a38ffc42d6ba9bf230bd40e8f53b16363c7eb4fd2deb9a44816040518082815260200191505060405180910390a150565b6000600a60149054906101000a900460ff1615611c3f57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1515611c1d57600080fd5b6102c65a03f11515611c2e57600080fd5b505050604051805190509050611c4c565b611c498383612a3e565b90505b92915050565b60035481565b60066020528060005260406000206000915054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611cd357600080fd5b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507fd7e9ec6e6ecd65492dce6bf513cd6867560d49544421d0783ddf06e76c24470c81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611e1057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611e8757806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611ee757600080fd5b600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611f3f57600080fd5b611f4882611239565b90506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550806001600082825403925050819055507f61e6e66b0d6339b2980aecc6ccc0039736791f0ccde9ed512e789a7fbdd698c68282604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15050565b60406004810160003690501015151561202657600080fd5b600082141580156120b457506000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b1515156120c057600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3505050565b60008060006060600481016000369050101515156121c857600080fd5b600560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054935061227061271061226260035488612a0390919063ffffffff16565b612ac590919063ffffffff16565b92506004548311156122825760045492505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84101561233e576122bd8585612ae090919063ffffffff16565b600560008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b6123518386612ae090919063ffffffff16565b91506123a585600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ae090919063ffffffff16565b600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061243a82600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060008311156125e4576124f983600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a35b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a350505050505050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000806040600481016000369050101515156126b657600080fd5b6126df6127106126d160035487612a0390919063ffffffff16565b612ac590919063ffffffff16565b92506004548311156126f15760045492505b6127048385612ae090919063ffffffff16565b915061275884600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612ae090919063ffffffff16565b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506127ed82600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000831115612997576128ac83600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612af990919063ffffffff16565b600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a35b8473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a35050505050565b6000806000841415612a185760009150612a37565b8284029050828482811515612a2957fe5b04141515612a3357fe5b8091505b5092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000808284811515612ad357fe5b0490508091505092915050565b6000828211151515612aee57fe5b818303905092915050565b6000808284019050838110151515612b0d57fe5b80915050929150505600a165627a7a72305820645ee12d73db47fd78ba77fa1f824c3c8f9184061b3b10386beb4dc9236abb280029"_hex, - - // 0x1111111254eeb25477b68fb85ed929f73a960582 - "0x6080604052600436106102f65760003560e01c80637e54f0921161018f578063bf15fcd8116100e1578063d365c6951161008a578063f2fde38b11610064578063f2fde38b14610859578063f78dc25314610879578063fa461e331461088c57600080fd5b8063d365c69514610813578063e449022e14610833578063e5d7bde61461084657600080fd5b8063c805a666116100bb578063c805a66614610799578063ca4ece22146107b9578063cf6fc6e3146107d957600080fd5b8063bf15fcd814610744578063bfa7514314610764578063c53a02921461078457600080fd5b8063942461bb11610143578063bc80f1a81161011d578063bc80f1a8146106f1578063bd61951d14610704578063bddccd351461072457600080fd5b8063942461bb146106915780639570eeee146106be578063bc1ed74c146106d157600080fd5b806383197ef01161017457806383197ef01461064157806384bd6d29146106565780638da5cb5b1461066957600080fd5b80637e54f092146105f4578063825caba11461062157600080fd5b80635a0998431161024857806370ae92d2116101fc57806372c244a8116101d657806372c244a81461059457806374261145146105b457806378e3214f146105d457600080fd5b806370ae92d21461053257806370ccbd311461055f578063715018a61461057f57600080fd5b806363592c2b1161022d57806363592c2b146104d25780636c838250146104f25780636fe7b0ba1461051257600080fd5b80635a099843146104ac57806362e238bb146104bf57600080fd5b80632d9a56f6116102aa5780633eca9c0a116102845780633eca9c0a1461041b5780634f38e2b81461044957806356f161241461046957600080fd5b80632d9a56f6146103bb57806337e7316f146103db5780633c15fd91146103fb57600080fd5b806312aa3caf116102db57806312aa3caf146103435780632521b9301461036b5780632cc2878d1461038b57600080fd5b80630502b1c51461030a578063093d4fa51461033057600080fd5b36610305576103036108ac565b005b600080fd5b61031d61031836600461483f565b6108b6565b6040519081526020015b60405180910390f35b61031d61033e3660046148a9565b6108d0565b610356610351366004614975565b610d16565b60408051928352602083019190915201610327565b34801561037757600080fd5b5061031d610386366004614a17565b610fd1565b34801561039757600080fd5b506103ab6103a6366004614abf565b611001565b6040519015158152602001610327565b3480156103c757600080fd5b506103566103d6366004614af1565b61104b565b3480156103e757600080fd5b5061031d6103f6366004614af1565b61114a565b34801561040757600080fd5b5061031d610416366004614a17565b611164565b61042e610429366004614c15565b611188565b60408051938452602084019290925290820152606001610327565b34801561045557600080fd5b506103ab610464366004614c72565b6111aa565b34801561047557600080fd5b5061031d610484366004614cbe565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b61042e6104ba366004614cea565b6111d5565b61042e6104cd366004614d60565b61132b565b3480156104de57600080fd5b506103ab6104ed366004614abf565b421090565b3480156104fe57600080fd5b506103ab61050d366004614af1565b611355565b34801561051e57600080fd5b506103ab61052d366004614c72565b611384565b34801561053e57600080fd5b5061031d61054d366004614e0c565b60016020526000908152604090205481565b34801561056b57600080fd5b5061042e61057a366004614e29565b6113aa565b34801561058b57600080fd5b506103036113f1565b3480156105a057600080fd5b506103036105af366004614ecd565b611403565b3480156105c057600080fd5b506103ab6105cf366004614c72565b6114b2565b3480156105e057600080fd5b506103036105ef366004614cbe565b611524565b34801561060057600080fd5b5061031d61060f366004614abf565b60009081526002602052604090205490565b34801561062d57600080fd5b5061030361063c366004614abf565b611544565b34801561064d57600080fd5b50610303611553565b61031d610664366004614ef0565b61155e565b34801561067557600080fd5b506000546040516001600160a01b039091168152602001610327565b34801561069d57600080fd5b506106b16106ac366004614f67565b611571565b6040516103279190615001565b61042e6106cc366004615045565b61162a565b3480156106dd57600080fd5b5061031d6106ec366004614abf565b611767565b61031d6106ff36600461483f565b6117b7565b34801561071057600080fd5b5061030361071f366004615082565b6117c6565b34801561073057600080fd5b5061030361073f3660046150be565b611867565b34801561075057600080fd5b5061031d61075f366004615082565b611872565b34801561077057600080fd5b506103ab61077f366004614c72565b6118bd565b34801561079057600080fd5b50610303611930565b3480156107a557600080fd5b5061031d6107b43660046150e0565b61193a565b3480156107c557600080fd5b506103ab6107d4366004614c72565b611971565b3480156107e557600080fd5b506103ab6107f4366004614cbe565b6001600160a01b03919091166000908152600160205260409020541490565b34801561081f57600080fd5b5061042e61082e3660046151a4565b611998565b61031d610841366004615295565b611a2c565b61042e6108543660046152e8565b611a3b565b34801561086557600080fd5b50610303610874366004614e0c565b6124cb565b61031d6108873660046153ac565b612558565b34801561089857600080fd5b506103036108a7366004615416565b612573565b6108b4612785565b565b60006108c63387878787876127be565b9695505050505050565b60006001600160a01b0388161580156109085786341461090357604051631841b4e160e01b815260040160405180910390fd5b610a24565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316896001600160a01b0316036109f057506001341561096357604051631841b4e160e01b815260040160405180910390fd5b6040516323b872dd60e01b808252336004830152306024830152604482018990527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d60e01b9060008060648382885af16109c6573d6000823e3d81fd5b8181528a60048201526000806024836000885af16109e7573d6000823e3d81fd5b50505050610a24565b3415610a0f57604051631841b4e160e01b815260040160405180910390fd5b610a246001600160a01b038a16338d8a612b30565b8015610ab85760008b905060006327a9b42460e01b90506040518181528a60048201528960248201528860448201528760648201528c60848201528560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149838d875af1610ab0573d6000823e3d81fd5b505050610d07565b6001600160a01b0388161580610aff57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316886001600160a01b0316145b15610c75576040517f4cb6864c00000000000000000000000000000000000000000000000000000000808252600482018b90526024820189905260448201889052606482018790528c918a1560018114610b5e57306084830152610b65565b8d60848301525b508560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149836000875af1610bb8573d6000823e3d81fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031603610c6e57604051630d0e30db60e41b8082527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29163a9059cbb60e01b906000806004838f885af1610c42573d6000823e3d81fd5b8181528f60048201528b60248201526000806044836000885af1610c69573d6000823e3d81fd5b505050505b5050610d07565b60008b90506000632b651a6c60e01b90506040518181528b60048201528a60248201528960448201528860648201528760848201528c60a48201528560ff1c601b0160c48201528660e48201526001600160ff1b03861661010482015261014061012482015264a62929c86960d31b610163820152600080610169836000875af1610d03573d6000823e3d81fd5b5050505b50939998505050505050505050565b6000808660a00135600003610d57576040517f0262dde400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d666020890189614e0c565b90506000610d7a60408a0160208b01614e0c565b90506000610d90836001600160a01b0316612bcd565b905060c08a013560021615610dd55780610dab576000610db1565b89608001355b3411610dd057604051631841b4e160e01b815260040160405180910390fd5b610e06565b80610de1576000610de7565b89608001355b3414610e0657604051631841b4e160e01b815260040160405180910390fd5b80610e4f578715610e2557610e256001600160a01b0384168a8a612c06565b610e4f33610e3960608d0160408e01614e0c565b6001600160a01b038616919060808e0135612b30565b610e608b338c608001358a8a612cbf565b60808a01359350610e7a6001600160a01b03831630612d1f565b945084600003610eb6576040517f28ebf24700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000199094019360c08a013560011615610f4f576000610edf6001600160a01b03851630612d1f565b90506001811115610f0e5760001901610ef88186615473565b9450610f0e6001600160a01b0385163383612dca565b610f1c8560a08d0135615486565b610f2a60808d013588615486565b1015610f495760405163f32bec2f60e01b815260040160405180910390fd5b50610f74565b8960a00135851015610f745760405163f32bec2f60e01b815260040160405180910390fd5b600080610f8760808d0160608e01614e0c565b6001600160a01b031614610faa57610fa560808c0160608d01614e0c565b610fac565b335b9050610fc26001600160a01b0384168288612dca565b50505050965096945050505050565b6000610fe76001600160a01b0389168484612c06565b610ff48988888888612eaa565b9998505050505050505050565b600060d082901c60a083901c65ffffffffffff168361101f83421090565b801561104257506001600160a01b03811660009081526001602052604090205482145b95945050505050565b6000803361105f6080850160608601614e0c565b6001600160a01b03161461109f576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110a88361114a565b6000818152600260205260409020549250905060001982016110f6576040517f41a26a6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518281526020810184905233917fcbfa7d191838ece7ba4783ca3a30afd316619b7f368094b57ee7ffde9a923db1910160405180910390a26000818152600260205260409020600190559092909150565b600061115e611157613131565b8390613258565b92915050565b600061117a6001600160a01b0389168484612c06565b610ff48989898989896127be565b600080600061119a87878787336111d5565b9250925092509450945094915050565b60008060006111b985856132d7565b915091508180156111c957508581115b925050505b9392505050565b60008060006112356111e5613131565b601f198a0180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8516156112a957600160fd1b851615801590611259575060418614155b15611277576040516317c2b1f160e01b815260040160405180910390fd5b6112878860600151828989613466565b6112a4576040516317c2b1f160e01b815260040160405180910390fd5b6112d6565b6112b988606001518289896134bb565b6112d6576040516317c2b1f160e01b815260040160405180910390fd5b6112e1888686613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a1955095509592505050565b60008060006113418b8b8b8b8b8b8b8b33611a3b565b925092509250985098509895505050505050565b600080600061136b61136685613b2e565b6132d7565b9150915081801561137c5750806001145b949350505050565b600080600061139385856132d7565b915091508180156111c95750909414949350505050565b60008060006113d185858c604001516001600160a01b0316612c069092919063ffffffff16565b6113de8a8a8a8a8a6111d5565b9250925092509750975097945050505050565b6113f9613b45565b6108b46000613b9f565b8060ff16600003611440576040517fbd71636d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526001602052604081205461145e9060ff84169061549d565b336000818152600160205260409081902083905551919250907ffc69110dd11eb791755e4abd6b7d281bae236de95736d38a23782814be5e10db906114a69084815260200190565b60405180910390a25050565b60008080805b63ffffffff87821c1692508215611517576000806114db61136686868a8c6154b0565b915091508180156114ec5750806001145b156114ff576001955050505050506111ce565b50839250611510905060208261549d565b90506114b8565b5060009695505050505050565b61152c613b45565b6115406001600160a01b0383163383612dca565b5050565b61155033826000613c07565b50565b61155b613b45565b33ff5b6000610ff489338a8a8a8a8a8a8a6108d0565b60606000825167ffffffffffffffff81111561158f5761158f614b26565b6040519080825280602002602001820160405280156115b8578160200160208202803683370190505b50905060005b835181101561162357600260008583815181106115dd576115dd6154da565b6020026020010151815260200190815260200160002054828281518110611606576116066154da565b60209081029190910101528061161b816154f0565b9150506115be565b5092915050565b600080600061168a61163a613131565b601f19890180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8416156116e657600160fd1b8416156116d6576116b48760600151828888613c9b565b6116d1576040516317c2b1f160e01b815260040160405180910390fd5b611713565b6116b48760600151828888613d05565b6116f68760600151828888613d5a565b611713576040516317c2b1f160e01b815260040160405180910390fd5b61171e878533613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a19450945094915050565b600081815260026020526040812054806117ad576040517fb838de9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000190192915050565b60006108c68686868686612eaa565b600080846001600160a01b031684846040516117e3929190615509565b600060405180830381855af49150503d806000811461181e576040519150601f19603f3d011682016040523d82523d6000602084013e611823565b606091505b509150915081816040517f1934afc800000000000000000000000000000000000000000000000000000000815260040161185e929190615569565b60405180910390fd5b611540338383613c07565b6000806000611882868686613da9565b9150915081611042576040517f1f1b8f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080805b63ffffffff87821c1692508215611923576000806118e661136686868a8c6154b0565b915091508115806118f8575080600114155b1561190b576000955050505050506111ce565b5083925061191c905060208261549d565b90506118c3565b5060019695505050505050565b6108b46001611403565b60006119506001600160a01b038b168484612c06565b6119618c8c8c8c8c8c8c8c8c6108d0565b9c9b505050505050505050505050565b600080600061198085856132d7565b915091508180156111c9575094909410949350505050565b6000808060148410156119d7576040517fd9e1c6dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006119e68888613dd7565b91945092509050611a016001600160a01b0384168383612c06565b505050611a158e8e8e8e8e8e8e8e8e611a3b565b9250925092509b509b509b98505050505050505050565b60006110423386868686612eaa565b600080806001600160a01b038416611a7f576040517fb0c4d05f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a888c61114a565b6000818152600260205260409020548894508793509091508c906000198101611add576040517fecef366400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611aef60c0840160a08501614e0c565b6001600160a01b031614158015611b1e575033611b1260c0840160a08501614e0c565b6001600160a01b031614155b15611b55576040517fd4dfdafe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80611c5857611b75611b6d6080840160608501614e0c565b848f8f6134bb565b611bab576040517f5cd5d23300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060c0810135366000611bbd84613e15565b91509150600160ff1b89166000148015611bd8575060148110155b15611c51576000366000611bec8585613dd7565b91945092509050611c076001600160a01b0384168383612c06565b60008881526002602052604090205415611c4d576040517fc5f2be5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505b5050611c5d565b600019015b6000611c6883613b2e565b90501115611caf57611c7982611355565b611caf576040517fb6629c0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415841503611ce9576040517ee2a52200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611d795780851115611cfd578094505b611d1b611d0983613e23565b8460c00135888660e001358689613e31565b93506001600160ff1b038716611d318682615486565b611d3b8b87615486565b1115611d73576040517ffb8ae12900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611e44565b611d97611d8583613e67565b8460e00135878660c001358689613e75565b945080851115611dec57809450611db0611d0983613e23565b935087841115611dec576040517f939c420400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160ff1b038716611e008582615486565b611e0a8a88615486565b1015611e42576040517f481ea39200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b841580611e4f575083155b15611e86576040517ffba5a27600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84810390508060010160026000858152602001908152602001600020819055508d6060016020810190611eb99190614e0c565b6001600160a01b03167fb9ed0243fdf00f0545c63a0af8850c090d86bb46682baec4bf3c496814fe4f028483604051611efc929190918252602082015260400190565b60405180910390a26014611f0f83613e89565b905010611fb2576000366000611f2c611f2786613e89565b613dd7565b919450925090506001600160a01b0383166396a10e3387611f536080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b8152600401611f7c9897969594939291906155ad565b600060405180830381600087803b158015611f9657600080fd5b505af1158015611faa573d6000803e3d6000fd5b505050505050505b611fe5611fc56040840160208501614e0c565b611fd56080850160608601614e0c565b8888611fe087613e97565b613ea5565b61201b576040517f70a03f4800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148a106120f35760003660006120328e8e613dd7565b9250925092506000836001600160a01b031663ccee33d7338b8b87876040518663ffffffff1660e01b815260040161206e959493929190615600565b6020604051808303816000875af115801561208d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b1919061562f565b905087811180156120d057506120ce6120c987613e67565b613f00565b155b80156120e557506120e36120c987613e23565b155b156120ee578097505b505050505b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21661212d6060840160408501614e0c565b6001600160a01b03161480156121435750600034115b15612359578334101561216957604051631841b4e160e01b815260040160405180910390fd5b833411156121df57604051600090339034879003908381818185875af1925050503d80600081146121b6576040519150601f19603f3d011682016040523d82523d6000602084013e6121bb565b606091505b50509050806121dd5760405163b12d13eb60e01b815260040160405180910390fd5b505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216925063a9059cbb91506000905061229760a0860160808701614e0c565b6001600160a01b0316146122ba576122b560a0850160808601614e0c565b6122ca565b6122ca6080850160608601614e0c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018790526044016020604051808303816000875af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123539190615648565b50612411565b341561237857604051631841b4e160e01b815260040160405180910390fd5b6123db61238b6060840160408501614e0c565b33600061239e60a0870160808801614e0c565b6001600160a01b0316146123c1576123bc60a0860160808701614e0c565b6123d1565b6123d16080860160608701614e0c565b87611fe087613f75565b612411576040517f478a520500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601461241c83613f83565b9050106124ba576000366000612434611f2786613f83565b919450925090506001600160a01b038316633504ed628761245b6080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b81526004016124849897969594939291906155ad565b600060405180830381600087803b15801561249e57600080fd5b505af11580156124b2573d6000803e3d6000fd5b505050505050505b505099509950999650505050505050565b6124d3613b45565b6001600160a01b03811661254f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161185e565b61155081613b9f565b60006125688787878787876127be565b979650505050505050565b6125cc565b3d6000803e3d6000fd5b8061258f5761258f612578565b600160005114601f3d11163d151780611540577ff27f64e40000000000000000000000000000000000000000000000000000000060005260046000fd5b604051601581017f0dfe1681d21220a7ddca3f43a9059cbb23b872dd0000000000000000000000008252602081600484335afa61260b5761260b612578565b60208082016004808501335afa61262457612624612578565b602060408201600460088501335afa61263f5761263f612578565b600080600088136001811461265d5760208401519250879150612665565b835192508891505b507fff1f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000084526060832083527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460208401526001600160a01b0360558520169250338318156126f6577fb2c027220000000000000000000000000000000000000000000000000000000060005260046000fd5b60843592507f0dfe1681d21220a7ddca3f43a9059cbb23b872dd00000000000000000000000084523083146001811461275757836014860152336034860152816054860152612752602060006064601089016000885af1612582565b61277a565b33601086015281603086015261277a602060006044600c89016000885af1612582565b505050505050505050565b3233036108b4576040517f1b10b0f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128b9565b7f0902f1ac0000000000000000000000000000000000000000000000000000000081526000604082600484875afa6127ff576127ff612578565b60603d14612831577f85cd58dc0000000000000000000000000000000000000000000000000000000060005260046000fd5b81516020830151861561284057905b8785029250633b9aca008202830181840204925050507f022c0d9f000000000000000000000000000000000000000000000000000000008252841594508415810260048301528481026024830152866044830152608060648301526000608483015260008060a4846000885af16108c6576108c6612578565b6dffffffffffffffffffffffffffff8511156128f9577fcf0b4d3a0000000000000000000000000000000000000000000000000000000060005260046000fd5b60405160c081016040528260051b84018435886000811461296957341561292b57631841b4e160e01b60005260046000fd5b6323b872dd60e01b84523360048501526001600160a01b03821660248501528860448501526129646020600060648760008f5af1612582565b6129ff565b34891461298157631841b4e160e01b60005260046000fd5b630d0e30db60e41b84526000806004868c73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129b5576129b5612578565b63a9059cbb60e01b84526001600160a01b0382166004850152886024850152600080604486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129ff576129ff612578565b50879350602086015b82811015612a50578035612a446001600160a01b03821663ffffffff60a01b851660a01c600160ff1b86166001600160a01b0387168a8a6127c5565b95509150602001612a08565b50600160fe1b81168015612adf57612a873063ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b9450632e1a7d4d60e01b8452846004850152600080602486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1612ac457612ac4612578565b600080600080888f5af1612ada57612ada612578565b612b0b565b612b088b63ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b94505b50505050838110156108c65760405163f32bec2f60e01b815260040160405180910390fd5b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af19150508015612b8e573d8015612b8457600160005114601f3d11169150612b8c565b6000873b1191505b505b80612bc5576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b60006001600160a01b038216158061115e57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600060e0829003612c4457612c3d847fd505accf000000000000000000000000000000000000000000000000000000008585613f91565b9050612cac565b610100829003612c7a57612c3d847f8fcbaf0c000000000000000000000000000000000000000000000000000000008585613f91565b6040517f6827585700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80612cb957612cb9613fe3565b50505050565b6040517f4b64e4920000000000000000000000000000000000000000000000000000000080825260048201869052908284602483013784836024830101526000808460440183348b5af1612d16573d6000823e3d81fd5b50505050505050565b6000612d2a83612bcd565b15612d4057506001600160a01b0381163161115e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015612d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc3919061562f565b905061115e565b8015612ea557612dd983612bcd565b15612e915780471015612e18576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b03168261138890604051600060405180830381858888f193505050503d8060008114612e6a576040519150601f19603f3d011682016040523d82523d6000602084013e612e6f565b606091505b5050905080612cb95760405163b12d13eb60e01b815260040160405180910390fd5b612ea56001600160a01b0384168383613fef565b505050565b600081808203612ee6576040517f67e7c0f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8591506000198101341515600080600160fd1b888886818110612f0b57612f0b6154da565b90506020020135161190508115612fb157883414612f3c57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08a6040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f9757600080fd5b505af1158015612fab573d6000803e3d6000fd5b50505050505b600184111561305157612feb3083612fc95733612fcb565b305b89896000818110612fde57612fde6154da565b9050602002013588614038565b945060015b838110156130265761301c30308a8a8581811061300f5761300f6154da565b9050602002013589614038565b9550600101612ff0565b5061304a81613035578a613037565b305b30898987818110612fde57612fde6154da565b945061306f565b61306c8161305f578a613061565b305b83612fc95733612fcb565b94505b878510156130905760405163f32bec2f60e01b815260040160405180910390fd5b801561312457604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156130f857600080fd5b505af115801561310c573d6000803e3d6000fd5b50613124925050506001600160a01b038b16866141d4565b5050505095945050505050565b6000306001600160a01b037f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605821614801561318a57507f000000000000000000000000000000000000000000000000000000000000000146145b156131b457507f1c0eb4c27d5b523ca136c0b3b83a4dcac8b70225b38be8507ba1a3f2af03cfca90565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f5c6cbfb2848b981a8f93044b3530be1fac304ecd5042396ca8729cb8fdd718f3828401527fceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c160608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000368161326a61012086018661566a565b60405191935091507f0a244ca8a150ac294c14fcff9277051ced9a5b23e966a0ff0522e989da23116c9082848237828120610140820152610120876020830137818152610160902060405161190160f01b81526002810187905260228101829052604290209094506108c6565b60008060006132e685856142ed565b60e01c905060006132f986866004614317565b9050632cc2878c19820161333057600161331282611001565b61331d576000613320565b60015b90945060ff16925061345f915050565b63bf15fcd88210156133be57636fe7b0ba82101561338257634f38e2b71982016133665760016133128261046489896064614348565b6363592c2a19820161337d57600161331282421090565b61344d565b636fe7b0b91982016133a05760016133128261052d89896064614348565b637426114419820161337d576001613312826105cf89896064614348565b63ca4ece228210156134115763bf15fcd71982016133f35760016133e88261075f89896064614348565b93509350505061345f565b63bfa7514219820161337d5760016133128261077f89896064614348565b63ca4ece2119820161342f576001613312826107d489896064614348565b63cf6fc6e219820161344d576001613312826107f489896024614317565b613458308787613da9565b9350935050505b9250929050565b600080631626ba7e60e01b905060405181815285600482015260406024820152836044820152838560648301376020600085606401838a5afa156134b15760203d1460005183141692505b5050949350505050565b60006001600160a01b0385166134d35750600061137c565b60408214806134e25750604182145b80156135095750846001600160a01b03166134fe858585614378565b6001600160a01b0316145b156135165750600161137c565b61104285858585613466565b6000806001600160a01b038316613565576040517f692e45e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606085015160808601516001600160a01b031615801590613593575060808601516001600160a01b03163314155b156135ca576040517fe8c6632100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff604082901c1680158015906135e957508042115b15613620576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61362c83836000613c07565b505060a086015160c08701517f0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716600081900361366f57829550819450613715565b600160ff1b8816156136ca57828111156136b5576040517faa34b69600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8095506136c383838861442d565b9450613715565b81811115613704576040517f7f902a9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80945061371283838761445b565b95505b5050508260001480613725575081155b1561375c576040517f07b6e79f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686602001516001600160a01b03161480156137c257507f1000000000000000000000000000000000000000000000000000000000000000851615155b1561395a576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018590527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906323b872dd906064016020604051808303816000875af115801561383c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138609190615648565b50604051632e1a7d4d60e01b8152600481018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156138c357600080fd5b505af11580156138d7573d6000803e3d6000fd5b505050506000846001600160a01b03168461138890604051600060405180830381858888f193505050503d806000811461392d576040519150601f19603f3d011682016040523d82523d6000602084013e613932565b606091505b50509050806139545760405163b12d13eb60e01b815260040160405180910390fd5b50613974565b6020860151613974906001600160a01b0316828686612b30565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686604001516001600160a01b03161480156139b95750600034115b15613aec578134146139de57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a3957600080fd5b505af1158015613a4d573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018790527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063a9059cbb925060440190506020604051808303816000875af1158015613ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae69190615648565b50613b25565b3415613b0b57604051631841b4e160e01b815260040160405180910390fd5b6040860151613b25906001600160a01b0316338385612b30565b50935093915050565b366000613b3c836004614468565b91509150915091565b6000546001600160a01b031633146108b45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161185e565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038316600090815260036020908152604080832066ffffffffffffff600887901c16808552928190529220549091600160ff86161b841791808316839003613c82576040517ff71fbda200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000938452602091909152604090922091179055505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604160448201528460648201526001600160ff1b03841660848201528360ff1c601b0160a48201536020600060a5838a5afa156134b15750600051143d6020141695945050505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604060448201528460648201528360848201526020600060a4838a5afa156134b15750600051143d6020141695945050505050565b60006001600160a01b038516613d725750600061137c565b846001600160a01b0316613d878585856144c3565b6001600160a01b031603613d9d5750600161137c565b61104285858585613d05565b60008060405183858237602060008583895afa3d602014169250508115613dcf57506000515b935093915050565b600036816014841015613dfd5760405163779ab6bd60e11b815260040160405180910390fd5b505050813560601c9260149092019160131990910190565b366000613b3c836005614468565b366000613b3c836003614468565b6000868103613e4c57613e4586858761442d565b9050612568565b613e5b88888888888888614532565b98975050505050505050565b366000613b3c836002614468565b6000868103613e4c57613e4584878761445b565b366000613b3c836006614468565b366000613b3c836000614468565b6040516323b872dd60e01b8082526004820187905260248201869052604482018590526000918385606483013760206000856064018360008d5af19050600160005114601f3d11163d15178116925050509695505050505050565b60006001821480156111ce575082826000818110613f2057613f206154da565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f7800000000000000000000000000000000000000000000000000000000000000149392505050565b366000613b3c836001614468565b366000613b3c836007614468565b6000816004016040518581528385600483013760206000838360008b5af192505050801561137c573d8015613fd257600160005114601f3d11169150613fda565b6000863b1191505b50949350505050565b6040513d6000823e3d81fd5b6140028363a9059cbb60e01b84846146be565b612ea5576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600160ff1b831615801561410e576000846001600160a01b031663128acb08888461406488614700565b604080516001600160a01b038d1660208201526401000276a491016040516020818303038152906040526040518663ffffffff1660e01b81526004016140ae9594939291906156b1565b60408051808303816000875af11580156140cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f091906156eb565b915050614105816141009061570f565b614783565b9250505061137c565b6000846001600160a01b031663128acb08888461412a88614700565b604080516001600160a01b038d16602082015273fffd8963efd1fc6a506488495d951d5263988d2591016040516020818303038152906040526040518663ffffffff1660e01b81526004016141839594939291906156b1565b60408051808303816000875af11580156141a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c591906156eb565b5090506141056141008261570f565b804710156142245760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161185e565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614271576040519150601f19603f3d011682016040523d82523d6000602084013e614276565b606091505b5050905080612ea55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161185e565b600060048210156143115760405163779ab6bd60e11b815260040160405180910390fd5b50503590565b60006020820183101561433d5760405163779ab6bd60e11b815260040160405180910390fd5b509190910135919050565b3660008284101561436c5760405163779ab6bd60e11b815260040160405180910390fd5b50509182019291900390565b6000604051826041811461439757604081146143b157600091506143d9565b604085013560001a602083015260408560408401376143d9565b60208501358060ff1c601b01602084015260208660408501376001600160ff1b031660608301525b508015614425577f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16060820151101561442557848152600080526020600060808360015afa5060005191505b509392505050565b60008360018161443d8686615486565b614447919061549d565b6144519190615473565b61137c919061572b565b6000826144518584615486565b3660008060058460078111156144805761448061574d565b901b905061449261012086018661566a565b6144b79161010088013580851c63ffffffff9081169360209290921b861c16916154b0565b92509250509250929050565b60006001600160ff1b0382167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1811015614425576040518581528360ff1c601b016020820152846040820152816060820152600080526020600060808360015afa505060005195945050505050565b600060018790036145be576145478888613f00565b1561458c57858514614585576040517f49986e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5082612568565b6040517fbec74c8500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006145cd8b8b613dd7565b925092509250600080846001600160a01b031684848c8b8b6040516020016145f9959493929190615763565b60408051601f198184030181529082905261461391615782565b600060405180830381855afa9150503d806000811461464e576040519150601f19603f3d011682016040523d82523d6000602084013e614653565b606091505b509150915081158061466757508051602014155b1561469e576040517f110b8e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808060200190518101906146b2919061562f565b95505050505050612568565b60006040518481528360048201528260248201526020600060448360008a5af1915050801561137c573d8015613fd257600160005114601f3d11169150613fda565b60006001600160ff1b0382111561477f5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e74323536000000000000000000000000000000000000000000000000606482015260840161185e565b5090565b60008082121561477f5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161185e565b6001600160a01b038116811461155057600080fd5b80356147f5816147d5565b919050565b60008083601f84011261480c57600080fd5b50813567ffffffffffffffff81111561482457600080fd5b6020830191508360208260051b850101111561345f57600080fd5b60008060008060006080868803121561485757600080fd5b8535614862816147d5565b94506020860135935060408601359250606086013567ffffffffffffffff81111561488c57600080fd5b614898888289016147fa565b969995985093965092949392505050565b60008060008060008060008060006101208a8c0312156148c857600080fd5b89356148d3816147d5565b985060208a01356148e3816147d5565b975060408a01356148f3816147d5565b965060608a0135614903816147d5565b989b979a50959860808101359760a0820135975060c0820135965060e08201359550610100909101359350915050565b60008083601f84011261494557600080fd5b50813567ffffffffffffffff81111561495d57600080fd5b60208301915083602082850101111561345f57600080fd5b60008060008060008086880361014081121561499057600080fd5b873561499b816147d5565b965060e0601f19820112156149af57600080fd5b5060208701945061010087013567ffffffffffffffff808211156149d257600080fd5b6149de8a838b01614933565b90965094506101208901359150808211156149f857600080fd5b50614a0589828a01614933565b979a9699509497509295939492505050565b60008060008060008060008060c0898b031215614a3357600080fd5b8835614a3e816147d5565b97506020890135614a4e816147d5565b96506040890135955060608901359450608089013567ffffffffffffffff80821115614a7957600080fd5b614a858c838d016147fa565b909650945060a08b0135915080821115614a9e57600080fd5b50614aab8b828c01614933565b999c989b5096995094979396929594505050565b600060208284031215614ad157600080fd5b5035919050565b60006101408284031215614aeb57600080fd5b50919050565b600060208284031215614b0357600080fd5b813567ffffffffffffffff811115614b1a57600080fd5b61137c84828501614ad8565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b6557614b65614b26565b604052919050565b600060e08284031215614b7f57600080fd5b60405160e0810181811067ffffffffffffffff82111715614ba257614ba2614b26565b604052823581529050806020830135614bba816147d5565b60208201526040830135614bcd816147d5565b60408201526060830135614be0816147d5565b60608201526080830135614bf3816147d5565b8060808301525060a083013560a082015260c083013560c08201525092915050565b6000806000806101208587031215614c2c57600080fd5b614c368686614b6d565b935060e085013567ffffffffffffffff811115614c5257600080fd5b614c5e87828801614933565b959890975094956101000135949350505050565b600080600060408486031215614c8757600080fd5b83359250602084013567ffffffffffffffff811115614ca557600080fd5b614cb186828701614933565b9497909650939450505050565b60008060408385031215614cd157600080fd5b8235614cdc816147d5565b946020939093013593505050565b60008060008060006101408688031215614d0357600080fd5b614d0d8787614b6d565b945060e086013567ffffffffffffffff811115614d2957600080fd5b614d3588828901614933565b9095509350506101008601359150610120860135614d52816147d5565b809150509295509295909350565b60008060008060008060008060c0898b031215614d7c57600080fd5b883567ffffffffffffffff80821115614d9457600080fd5b614da08c838d01614ad8565b995060208b0135915080821115614db657600080fd5b614dc28c838d01614933565b909950975060408b0135915080821115614ddb57600080fd5b50614de88b828c01614933565b999c989b5096999698976060880135976080810135975060a0013595509350505050565b600060208284031215614e1e57600080fd5b81356111ce816147d5565b6000806000806000806000610160888a031215614e4557600080fd5b614e4f8989614b6d565b965060e088013567ffffffffffffffff80821115614e6c57600080fd5b614e788b838c01614933565b90985096506101008a013595506101208a01359150614e96826147d5565b9093506101408901359080821115614ead57600080fd5b50614eba8a828b01614933565b989b979a50959850939692959293505050565b600060208284031215614edf57600080fd5b813560ff811681146111ce57600080fd5b600080600080600080600080610100898b031215614f0d57600080fd5b8835614f18816147d5565b97506020890135614f28816147d5565b96506040890135614f38816147d5565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b60006020808385031215614f7a57600080fd5b823567ffffffffffffffff80821115614f9257600080fd5b818501915085601f830112614fa657600080fd5b813581811115614fb857614fb8614b26565b8060051b9150614fc9848301614b3c565b8181529183018401918481019088841115614fe357600080fd5b938501935b83851015613e5b57843582529385019390850190614fe8565b6020808252825182820181905260009190848201906040850190845b818110156150395783518352928401929184019160010161501d565b50909695505050505050565b600080600080610140858703121561505c57600080fd5b6150668686614b6d565b9660e08601359650610100860135956101200135945092505050565b60008060006040848603121561509757600080fd5b83356150a2816147d5565b9250602084013567ffffffffffffffff811115614ca557600080fd5b600080604083850312156150d157600080fd5b50508035926020909101359150565b60008060008060008060008060008060006101408c8e03121561510257600080fd5b8b3561510d816147d5565b9a5060208c013561511d816147d5565b995060408c013561512d816147d5565b985060608c013561513d816147d5565b975060808c0135965060a08c0135955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561517e57600080fd5b61518a8e828f01614933565b915080935050809150509295989b509295989b9093969950565b60008060008060008060008060008060006101008c8e0312156151c657600080fd5b67ffffffffffffffff808d3511156151dd57600080fd5b6151ea8e8e358f01614ad8565b9b508060208e013511156151fd57600080fd5b61520d8e60208f01358f01614933565b909b50995060408d013581101561522357600080fd5b6152338e60408f01358f01614933565b909950975060608d0135965060808d0135955060a08d0135945061525960c08e016147ea565b93508060e08e0135111561526c57600080fd5b5061527d8d60e08e01358e01614933565b81935080925050509295989b509295989b9093969950565b600080600080606085870312156152ab57600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156152d057600080fd5b6152dc878288016147fa565b95989497509550505050565b600080600080600080600080600060e08a8c03121561530657600080fd5b893567ffffffffffffffff8082111561531e57600080fd5b61532a8d838e01614ad8565b9a5060208c013591508082111561534057600080fd5b61534c8d838e01614933565b909a50985060408c013591508082111561536557600080fd5b506153728c828d01614933565b90975095505060608a0135935060808a0135925060a08a0135915060c08a013561539b816147d5565b809150509295985092959850929598565b60008060008060008060a087890312156153c557600080fd5b86356153d0816147d5565b955060208701356153e0816147d5565b94506040870135935060608701359250608087013567ffffffffffffffff81111561540a57600080fd5b614a0589828a016147fa565b6000806000806060858703121561542c57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561545157600080fd5b6152dc87828801614933565b634e487b7160e01b600052601160045260246000fd5b8181038181111561115e5761115e61545d565b808202811582820484141761115e5761115e61545d565b8082018082111561115e5761115e61545d565b600080858511156154c057600080fd5b838611156154cd57600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b6000600182016155025761550261545d565b5060010190565b8183823760009101908152919050565b60005b8381101561553457818101518382015260200161551c565b50506000910152565b60008151808452615555816020860160208601615519565b601f01601f19169290920160200192915050565b821515815260406020820152600061137c604083018461553d565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b88815260006001600160a01b03808a1660208401528089166040840152508660608301528560808301528460a083015260e060c08301526155f260e083018486615584565b9a9950505050505050505050565b6001600160a01b0386168152846020820152836040820152608060608201526000612568608083018486615584565b60006020828403121561564157600080fd5b5051919050565b60006020828403121561565a57600080fd5b815180151581146111ce57600080fd5b6000808335601e1984360301811261568157600080fd5b83018035915067ffffffffffffffff82111561569c57600080fd5b60200191503681900382131561345f57600080fd5b60006001600160a01b038088168352861515602084015285604084015280851660608401525060a0608083015261256860a083018461553d565b600080604083850312156156fe57600080fd5b505080516020909101519092909150565b6000600160ff1b82036157245761572461545d565b5060000390565b60008261574857634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fd5b8486823790930191825260208201526040810191909152606001919050565b60008251615794818460208701615519565b919091019291505056fea264697066735822122040321861ce858a2c911db7a2e1f42f4368d23b5251b80dd661a6f2abf19c358d64736f6c63430008110033"_hex, - - // blake2_shifts + weierstrudel + sha1_div. - "608060405234801561001057600080fd5b50600436106100365760003560e01c80631e0924231461003b578063d299" - "dac0146102bb575b600080fd5b610282600480360360a081101561005157600080fd5b810190602081018135640100" - "00000081111561006c57600080fd5b82018360208201111561007e57600080fd5b8035906020019184600183028401" - "11640100000000831117156100a057600080fd5b91908080601f016020809104026020016040519081016040528093" - "9291908181526020018383808284376000920191909152509295949360208101935035915050640100000000811115" - "6100f357600080fd5b82018360208201111561010557600080fd5b8035906020019184600183028401116401000000" - "008311171561012757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152" - "602001838380828437600092019190915250929594936020810193503591505064010000000081111561017a576000" - "80fd5b82018360208201111561018c57600080fd5b8035906020019184600183028401116401000000008311171561" - "01ae57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380" - "828437600092019190915250929594936020810193503591505064010000000081111561020157600080fd5b820183" - "60208201111561021357600080fd5b8035906020019184600183028401116401000000008311171561023557600080" - "fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092" - "0191909152509295505050903567ffffffffffffffff1691506103f49050565b604051808261010080838360005b83" - "8110156102a8578181015183820152602001610290565b5050505090500191505060405180910390f35b6102826004" - "80360360608110156102d157600080fd5b8101906020810181356401000000008111156102ec57600080fd5b820183" - "6020820111156102fe57600080fd5b8035906020019184600183028401116401000000008311171561032057600080" - "fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092" - "019190915250929594936020810193503591505064010000000081111561037357600080fd5b820183602082011115" - "61038557600080fd5b803590602001918460018302840111640100000000831117156103a757600080fd5b91908080" - "601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250" - "9295505050903567ffffffffffffffff1691506104489050565b6103fc61156d565b61040461158d565b61040c6115" - "6d565b61042982858961041b8a610485565b6104248a610485565b610538565b61043382896106dc565b61043d8282" - "61079b565b979650505050505050565b61045061156d565b61047d8484602060405190810160405280600081525060" - "20604051908101604052806000815250866103f4565b949350505050565b61048d6115ca565b60005b825181101561" - "04fb5760088184018101519067ffffffffffffffff82166007841660010182026040031b9084908404600281106104" - "c957fe5b6020020151188360088404600281106104de57fe5b67ffffffffffffffff90921660209290920201525060" - "0101610490565b5061050d8160005b60200201516108cd565b67ffffffffffffffff16815261052481600161050356" - "5b67ffffffffffffffff166020820152919050565b67ffffffffffffffff84161580610559575060408467ffffffff" - "ffffffff16115b80610565575060408351115b1561056f57600080fd5b61057761156d565b50604080516101008101" - "8252676a09e667f3bcc908815267bb67ae8584caa73b6020820152673c6ef372fe94f82b9181019190915267a54ff5" - "3a5f1d36f1606082015267510e527fade682d16080820152679b05688c2b3e6c1f60a0820152671f83d9abfb41bd6b" - "60c0820152675be0cd19137e217960e082015260005b600881101561063d5781816008811061060a57fe5b60200201" - "5187602001518260088110151561062157fe5b67ffffffffffffffff90921660209290920201526001016105f5565b" - "50835160208781018051805167ffffffffffffffff94851660081b1889186301010000188416905285518151608090" - "81018051909218851690915286830151825160a0018051909118851690528551825160c00180519091188516905291" - "850151905160e00180519091188316905286821690880152845190600090821611156106d3576106cb87866106dc56" - "5b608060608801525b50505050505050565b60005b815181101561079657826060015167ffffffffffffffff166080" - "141561074057606083015160408401805167ffffffffffffffff9092169091016fffffffffffffffffffffffffffff" - "ffff16905261073883600061094f565b600060608401525b60608301805167ffffffffffffffff6001820181169092" - "52166107616115e5565b508351835160009085908590811061077557fe5b90602001015160f81c60f81b60f81c9050" - "80838301535050506001016106df565b505050565b60608201805160408401805167ffffffffffffffff8084169182" - "016fffffffffffffffffffffffffffffffff1690925260019092011690915260006107de6115e5565b508351825b60" - "808110156107f95782818301536001016107e3565b5061080585600161094f565b60005b6080860151600890048110" - "1561085457602086015161082c90826008811061050357fe5b85826008811061083857fe5b67ffffffffffffffff90" - "92166020929092020152600101610808565b506040856080015110156108c657608085015160208601516008600783" - "16810260400392610889929190046008811061050357fe5b67ffffffffffffffff16901c8460088760800151811515" - "6108a657fe5b04600881106108b157fe5b67ffffffffffffffff90921660209290920201525b5050505050565b6000" - "67010000000000000060ff8316026501000000000061ff00841602630100000062ff000085160261010063ff000000" - "861681029064ff00000000871604630100000065ff00000000008816046501000000000066ff000000000000891604" - "67010000000000000067ff000000000000008a16041818181818181892915050565b610957611604565b61095f6116" - "04565b61096761156d565b506040805161010081018252676a09e667f3bcc908815267bb67ae8584caa73b60208201" - "52673c6ef372fe94f82b9181019190915267a54ff53a5f1d36f1606082015267510e527fade682d16080820152679b" - "05688c2b3e6c1f60a0820152671f83d9abfb41bd6b60c0820152675be0cd19137e217960e082015260005b60088110" - "15610a5f57602086015181600881106109fe57fe5b6020020151848260108110610a0f57fe5b67ffffffffffffffff" - "9092166020929092020152818160088110610a2f57fe5b6020020151846008830160108110610a4357fe5b67ffffff" - "ffffffffff90921660209290920201526001016109e5565b506040850180516101808501805167ffffffffffffffff" - "928316188216905290516101a085018051680100000000000000006fffffffffffffffffffffffffffffffff909316" - "9290920490911890911690528315610acc576101c0830180511967ffffffffffffffff1690525b600080805b601081" - "60ff161015610b56576000925060038116801515610b0c578851600460ff84160460ff16600481101515610b0457fe" - "5b602002015192505b67ffffffffffffffff83826003036040021c169350610b2a846108cd565b8660ff8416601081" - "10610b3957fe5b67ffffffffffffffff909216602092909202015250600101610ad1565b50610b7985600060046008" - "600c89845b60200201518a60015b60200201516113e8565b610b9685600160056009600d8960025b60200201518a60" - "03610b6f565b610bb38560026006600a600e8960045b60200201518a6005610b6f565b610bd08560036007600b600f" - "8960065b60200201518a6007610b6f565b610bed8560006005600a600f8960085b60200201518a6009610b6f565b61" - "0c0a8560016006600b600c89600a5b60200201518a600b610b6f565b610c2785600260076008600d89600c5b602002" - "01518a600d610b6f565b610c4385600360046009600e89815b60200201518a600f610b6f565b610c60856000600460" - "08600c89600e5b60200201518a600a610b6f565b610c7d85600160056009600d8960045b60200201518a6008610b6f" - "565b610c918560026006600a600e896009610c36565b610cae8560036007600b600f89600d5b60200201518a600661" - "0b6f565b610ccb8560006005600a600f8960015b60200201518a600c610b6f565b610ce88560016006600b600c8960" - "005b60200201518a6002610b6f565b610cfc85600260076008600d89600b610bc3565b610d1085600360046009600e" - "896005610b89565b610d2485600060046008600c89600b610c70565b610d4185600160056009600d89600c5b602002" - "01518a6000610b6f565b610d558560026006600a600e896005610cdb565b610d688560036007600b600f8981610c1a" - "565b610d848560006005600a600f89825b60200201518a600e610b6f565b610d988560016006600b600c896003610c" - "a1565b610dab85600260076008600d8983610b66565b610dc785600360046009600e89825b60200201518a6004610b" - "6f565b610ddb85600060046008600c896007610be0565b610def85600160056009600d896003610b66565b610e0385" - "60026006600a600e89600d610cbe565b610e168560036007600b600f8982610d77565b610e2a8560006005600a600f" - "896002610ca1565b610e3e8560016006600b600c896005610c53565b610e5285600260076008600d896004610d3456" - "5b610e6685600360046009600e89600f610c70565b610e7a85600060046008600c896009610d34565b610e8d856001" - "60056009600d8983610bc3565b610ea08560026006600a600e8984610dba565b610eb48560036007600b600f89600a" - "610c36565b610ec88560006005600a600f89600e610b66565b610edb8560016006600b600c8982610cbe565b610eef" - "85600260076008600d896006610c70565b610f0285600360046009600e8984610c1a565b610f168560006004600860" - "0c896002610cbe565b610f2a85600160056009600d896006610c53565b610f3e8560026006600a600e896000610bfd" - "565b610f528560036007600b600f896008610b89565b610f668560006005600a600f896004610c1a565b610f7a8560" - "016006600b600c896007610ba6565b610f8e85600260076008600d89600f610d77565b610fa285600360046009600e" - "896001610be0565b610fb585600060046008600c8981610ba6565b610fc885600160056009600d8984610c36565b61" - "0fdb8560026006600a600e8981610c1a565b610fef8560036007600b600f896004610c53565b611002856000600560" - "0a600f8984610bc3565b6110158560016006600b600c8983610b89565b61102985600260076008600d896009610cdb" - "565b61103d85600360046009600e896008610bfd565b61105185600060046008600c89600d610bfd565b6110658560" - "0160056009600d896007610d77565b6110798560026006600a600e89600c610b66565b61108c8560036007600b600f" - "8984610be0565b61109f8560006005600a600f8983610d34565b6110b38560016006600b600c89600f610dba565b61" - "10c685600260076008600d8982610ca1565b6110da85600360046009600e896002610c53565b6110ee856000600460" - "08600c896006610c36565b61110285600160056009600d89600e610be0565b6111168560026006600a600e89600b61" - "0b89565b61112a8560036007600b600f896000610c70565b61113e8560006005600a600f89600c610cdb565b611152" - "8560016006600b600c89600d610bc3565b61116685600260076008600d896001610dba565b61117a85600360046009" - "600e89600a610ba6565b61118e85600060046008600c89600a610cdb565b6111a285600160056009600d896008610d" - "ba565b6111b68560026006600a600e896007610ca1565b6111ca8560036007600b600f896001610ba6565b6111dd85" - "60006005600a600f8981610bfd565b6111f18560016006600b600c896009610d77565b61120585600260076008600d" - "896003610cbe565b61121985600360046009600e89600d610d34565b61122c85600060046008600c8984610b66565b" - "61124085600160056009600d896002610b89565b6112548560026006600a600e896004610ba6565b61126885600360" - "07600b600f896006610bc3565b61127c8560006005600a600f896008610be0565b6112908560016006600b600c8960" - "0a610bfd565b6112a485600260076008600d89600c610c1a565b6112b785600360046009600e8981610c36565b6112" - "cb85600060046008600c89600e610c53565b6112df85600160056009600d896004610c70565b6112f3856002600660" - "0a600e896009610c36565b6113078560036007600b600f89600d610ca1565b61131b8560006005600a600f89600161" - "0cbe565b61132f8560016006600b600c896000610cdb565b61134385600260076008600d89600b610bc3565b611357" - "85600360046009600e896005610b89565b60005b60088160ff1610156113de578560ff600883011660108110611378" - "57fe5b60200201518660ff83166010811061138c57fe5b602002015189602001518360ff166008811015156113a657" - "fe5b6020020151181888602001518260ff166008811015156113c257fe5b67ffffffffffffffff9092166020929092" - "02015260010161135a565b5050505050505050565b60008787601081106113f657fe5b602002015190506000888760" - "10811061140b57fe5b60200201519050600089876010811061142057fe5b6020020151905060008a87601081106114" - "3557fe5b6020020151905068010000000000000000868486010893508318602081811c91901b67ffffffffffffffff" - "161868010000000000000000818308915067ffffffffffffffff82841860281b1682841860181c1892506801000000" - "0000000000858486010893508318601081901c60309190911b67ffffffffffffffff16186801000000000000000081" - "8308928318603f81901c60019190911b67ffffffffffffffff1618929150838b8b601081106114e957fe5b67ffffff" - "ffffffffff9092166020929092020152828b8a6010811061150a57fe5b67ffffffffffffffff909216602092909202" - "0152818b896010811061152b57fe5b67ffffffffffffffff9092166020929092020152808b886010811061154c57fe" - "5b67ffffffffffffffff90921660209290920201525050505050505050505050565b61010060405190810160405280" - "6008906020820280388339509192915050565b6101e0604051908101604052806115a26115e5565b81526020016115" - "af61156d565b81526000602082018190526040820181905260609091015290565b6040805180820182529060029082" - "9080388339509192915050565b6080604051908101604052806004906020820280388339509192915050565b610200" - "60405190810160405280601090602082028038833950919291505056fea165627a7a72305820a59dc9d098d29bacdd" - "88cb50c25c96ed4ba3047fd46a5c6ecf57e447a3c699100029" - "346060600036030617156100195761019060005260206000fd5b6060600036030460021b603e016102006136c66000" - "396004810281600302826005020182601e018103838203848203858203868203878203888203606060003603048080" - "01600a1b60e0019060061b6000015b60017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0" - "0000018235067f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190067f30644e72e1" - "31a029b85045b68181585d2833e84879b9709143e1f593f000000180807fffffffffffffffffffffffffffffffffff" - "ffffffffffffffffffffffffffffff70024ccef014a773d2cf7a7bd9d4391eb18d850970024ccef014a773d2cf7a7b" - "d9d4391eb18d85028082109103036789d3256894d213e3097f30644e72e131a029b85045b68181585d2833e84879b9" - "709143e1f593f00000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6802d91d" - "232ec7e0b3d786096802d91d232ec7e0b3d786028082109103037f30644e72e131a029b85045b68181585cb8e665ff" - "8b011694c1d039a872b0eed9090891818377b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd090860051b" - "9060051b5b937ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0001938e6005026060" - "600036030461080002610200010390806101e01651565b908e019060041c806101e01651565b8060031c6103e01686" - "01828f019283516002018085528f03015260081c601001806101e01651565b8060021c6103e0168601828d01928351" - "6002018085528d03015260071c601001806101e01651565b8060011c6103e0168601828b019283516002018085528b" - "03015260061c601001806101e01651565b806103e01686018289019283516002018085528903015260051c60100180" - "6101e01651565b601f811161021b57509060018303926101da5750505060200180360361006c575050505050505050" - "5050506000037f912CEB58A394E07D28F0D12384840918C6843FB439555FA7B461A4448976F7D57f60C89CE5C26340" - "5370A08B6D0302B0BB2F02D522D0E3951A7841182DB0F9FA8E7f30644E72E131A029B85045B68181585D97816A9168" - "71CA8D3C208C16D87CFD477759e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe60c0528260a05281608052" - "6000604003600360003603048001038060605280359060200135828080848009840960030883828009146103b65761" - "019060005260206000fd5b82818009838160021b818080838809968009600302818180098783038001018a03806000" - "528701099209840380019180016040528101602052826020518201600051840182808280098061040a5760006000fd" - "5b818184099382828909830383808084800983800101880891820181930982878a09018b03829561052a565b604060" - "6051036060528084808083800980930981606051358190066060516020013582900682808084800984096003088382" - "80091461047a5761019060005260206000fd5b9409920985818009868160021b818082870981038187800960030290" - "82828009818001018060a051036000520109920980010160a051036020528583800182098060405290919286808084" - "8009938409948309878094860984038492838180098480808385096020510984019160005109840185808280098061" - "04fd5760006000fd5b818184099382828909830383808084800983800101880891820181930982878a090160805103" - "8280968199095b83818009848080838509602051098401916000510984018580828009806105515760006000fd5b81" - "8184099382828909830383808084800983800101880891820181930982878a09016080510382809681990983818009" - "848080838509602051098401916000510984018580828009806105a45760006000fd5b818184099382828909830383" - "808084800983800101880891820181930982878a090160805103828096819909838180098480808385096020510984" - "01916000510984018580828009806105f75760006000fd5b8181840993828289098303838080848009838001018808" - "91820181930982878a0901608051038280968199098381800984808083850960205109840191600051098401858082" - "80098061064a5760006000fd5b818184099382828909830383808084800983800101880891820181930982878a0901" - "60805103828096819909838180098480808385096020510984019160005109840185808280098061069d5760006000" - "fd5b818184099382828909830383808084800983800101880891820181930982878a09016080510382809681990983" - "818009848080838509602051098401916000510984018580828009806106f05760006000fd5b818184099382828909" - "830383808084800983800101880891820181930982878a09016080510382808097819a096040510960006060510361" - "0435573d526001600160606000360304600f036101cd0261074501565b91849083098061732052806176e052840380" - "6172e0526177205291839083098303838160c05109806176c05261770052806172c052617300529209930993840980" - "61736052806176a0528203806172a0526177605292830983038360c051820980617680526177405280617280526173" - "405292099309938409806173a0528061766052820380617260526177a05292830983038360c0518209806176405261" - "77805280617240526173805292099309938409806173e0528061762052820380617220526177e05292830983038360" - "c051820980617600526177c05280617200526173c052920993099384098061742052806175e0528203806171e05261" - "78205292830983038360c0518209806175c05261780052806171c05261740052920993099384098061746052806175" - "a0528203806171a0526178605292830983038360c05182098061758052617840528061718052617440529209930993" - "8409806174a0528061756052820380617160526178a05292830983038360c051820980617540526178805280617140" - "526174805292099309938409806174e0528061752052820380617120526178e05292830985038560c0518209806175" - "00526178c05280617100526174c052920992095b918490830980616b205280616ee052840380616ae052616f205291" - "839083098303838160c0510980616ec052616f005280616ac052616b00529209930993840980616b605280616ea052" - "820380616aa052616f605292830983038360c051820980616e8052616f405280616a8052616b405292099309938409" - "80616ba05280616e6052820380616a6052616fa05292830983038360c051820980616e4052616f805280616a405261" - "6b80529209930993840980616be05280616e2052820380616a2052616fe05292830983038360c051820980616e0052" - "616fc05280616a0052616bc0529209930993840980616c205280616de0528203806169e05261702052928309830383" - "60c051820980616dc05261700052806169c052616c00529209930993840980616c605280616da0528203806169a052" - "6170605292830983038360c051820980616d8052617040528061698052616c40529209930993840980616ca0528061" - "6d6052820380616960526170a05292830983038360c051820980616d4052617080528061694052616c805292099309" - "93840980616ce05280616d2052820380616920526170e05292830985038560c051820980616d00526170c052806169" - "0052616cc052920992095b91849083098061632052806166e0528403806162e0526167205291839083098303838160" - "c05109806166c05261670052806162c05261630052920993099384098061636052806166a0528203806162a0526167" - "605292830983038360c051820980616680526167405280616280526163405292099309938409806163a05280616660" - "52820380616260526167a05292830983038360c0518209806166405261678052806162405261638052920993099384" - "09806163e0528061662052820380616220526167e05292830983038360c051820980616600526167c0528061620052" - "6163c052920993099384098061642052806165e0528203806161e0526168205292830983038360c0518209806165c0" - "5261680052806161c05261640052920993099384098061646052806165a0528203806161a052616860529283098303" - "8360c051820980616580526168405280616180526164405292099309938409806164a0528061656052820380616160" - "526168a05292830983038360c051820980616540526168805280616140526164805292099309938409806164e05280" - "61652052820380616120526168e05292830985038560c051820980616500526168c05280616100526164c052920992" - "095b918490830980615b205280615ee052840380615ae052615f205291839083098303838160c0510980615ec05261" - "5f005280615ac052615b00529209930993840980615b605280615ea052820380615aa052615f605292830983038360" - "c051820980615e8052615f405280615a8052615b40529209930993840980615ba05280615e6052820380615a605261" - "5fa05292830983038360c051820980615e4052615f805280615a4052615b80529209930993840980615be05280615e" - "2052820380615a2052615fe05292830983038360c051820980615e0052615fc05280615a0052615bc0529209930993" - "840980615c205280615de0528203806159e0526160205292830983038360c051820980615dc05261600052806159c0" - "52615c00529209930993840980615c605280615da0528203806159a0526160605292830983038360c051820980615d" - "8052616040528061598052615c40529209930993840980615ca05280615d6052820380615960526160a05292830983" - "038360c051820980615d4052616080528061594052615c80529209930993840980615ce05280615d20528203806159" - "20526160e05292830985038560c051820980615d00526160c0528061590052615cc052920992095b91849083098061" - "532052806156e0528403806152e0526157205291839083098303838160c05109806156c05261570052806152c05261" - "530052920993099384098061536052806156a0528203806152a0526157605292830983038360c05182098061568052" - "6157405280615280526153405292099309938409806153a0528061566052820380615260526157a052928309830383" - "60c051820980615640526157805280615240526153805292099309938409806153e052806156205282038061522052" - "6157e05292830983038360c051820980615600526157c05280615200526153c0529209930993840980615420528061" - "55e0528203806151e0526158205292830983038360c0518209806155c05261580052806151c0526154005292099309" - "9384098061546052806155a0528203806151a0526158605292830983038360c0518209806155805261584052806151" - "80526154405292099309938409806154a0528061556052820380615160526158a05292830983038360c05182098061" - "5540526158805280615140526154805292099309938409806154e0528061552052820380615120526158e052928309" - "85038560c051820980615500526158c05280615100526154c052920992095b918490830980614b205280614ee05284" - "0380614ae052614f205291839083098303838160c0510980614ec052614f005280614ac052614b0052920993099384" - "0980614b605280614ea052820380614aa052614f605292830983038360c051820980614e8052614f405280614a8052" - "614b40529209930993840980614ba05280614e6052820380614a6052614fa05292830983038360c051820980614e40" - "52614f805280614a4052614b80529209930993840980614be05280614e2052820380614a2052614fe0529283098303" - "8360c051820980614e0052614fc05280614a0052614bc0529209930993840980614c205280614de0528203806149e0" - "526150205292830983038360c051820980614dc05261500052806149c052614c00529209930993840980614c605280" - "614da0528203806149a0526150605292830983038360c051820980614d8052615040528061498052614c4052920993" - "0993840980614ca05280614d6052820380614960526150a05292830983038360c051820980614d4052615080528061" - "494052614c80529209930993840980614ce05280614d2052820380614920526150e05292830985038560c051820980" - "614d00526150c0528061490052614cc052920992095b91849083098061432052806146e0528403806142e052614720" - "5291839083098303838160c05109806146c05261470052806142c05261430052920993099384098061436052806146" - "a0528203806142a0526147605292830983038360c05182098061468052614740528061428052614340529209930993" - "8409806143a0528061466052820380614260526147a05292830983038360c051820980614640526147805280614240" - "526143805292099309938409806143e0528061462052820380614220526147e05292830983038360c0518209806146" - "00526147c05280614200526143c052920993099384098061442052806145e0528203806141e0526148205292830983" - "038360c0518209806145c05261480052806141c05261440052920993099384098061446052806145a0528203806141" - "a0526148605292830983038360c051820980614580526148405280614180526144405292099309938409806144a052" - "8061456052820380614160526148a05292830983038360c05182098061454052614880528061414052614480529209" - "9309938409806144e0528061452052820380614120526148e05292830985038560c051820980614500526148c05280" - "614100526144c052920992095b918490830980613b205280613ee052840380613ae052613f20529183908309830383" - "8160c0510980613ec052613f005280613ac052613b00529209930993840980613b605280613ea052820380613aa052" - "613f605292830983038360c051820980613e8052613f405280613a8052613b40529209930993840980613ba0528061" - "3e6052820380613a6052613fa05292830983038360c051820980613e4052613f805280613a4052613b805292099309" - "93840980613be05280613e2052820380613a2052613fe05292830983038360c051820980613e0052613fc05280613a" - "0052613bc0529209930993840980613c205280613de0528203806139e0526140205292830983038360c05182098061" - "3dc05261400052806139c052613c00529209930993840980613c605280613da0528203806139a05261406052928309" - "83038360c051820980613d8052614040528061398052613c40529209930993840980613ca05280613d605282038061" - "3960526140a05292830983038360c051820980613d4052614080528061394052613c80529209930993840980613ce0" - "5280613d2052820380613920526140e05292830985038560c051820980613d00526140c0528061390052613cc05292" - "0992095b91849083098061332052806136e0528403806132e0526137205291839083098303838160c05109806136c0" - "5261370052806132c05261330052920993099384098061336052806136a0528203806132a052613760529283098303" - "8360c051820980613680526137405280613280526133405292099309938409806133a0528061366052820380613260" - "526137a05292830983038360c051820980613640526137805280613240526133805292099309938409806133e05280" - "61362052820380613220526137e05292830983038360c051820980613600526137c05280613200526133c052920993" - "099384098061342052806135e0528203806131e0526138205292830983038360c0518209806135c052613800528061" - "31c05261340052920993099384098061346052806135a0528203806131a0526138605292830983038360c051820980" - "613580526138405280613180526134405292099309938409806134a0528061356052820380613160526138a0529283" - "0983038360c051820980613540526138805280613140526134805292099309938409806134e0528061352052820380" - "613120526138e05292830985038560c051820980613500526138c05280613100526134c052920992095b9184908309" - "80612b205280612ee052840380612ae052612f205291839083098303838160c0510980612ec052612f005280612ac0" - "52612b00529209930993840980612b605280612ea052820380612aa052612f605292830983038360c051820980612e" - "8052612f405280612a8052612b40529209930993840980612ba05280612e6052820380612a6052612fa05292830983" - "038360c051820980612e4052612f805280612a4052612b80529209930993840980612be05280612e2052820380612a" - "2052612fe05292830983038360c051820980612e0052612fc05280612a0052612bc0529209930993840980612c2052" - "80612de0528203806129e0526130205292830983038360c051820980612dc05261300052806129c052612c00529209" - "930993840980612c605280612da0528203806129a0526130605292830983038360c051820980612d80526130405280" - "61298052612c40529209930993840980612ca05280612d6052820380612960526130a05292830983038360c0518209" - "80612d4052613080528061294052612c80529209930993840980612ce05280612d2052820380612920526130e05292" - "830985038560c051820980612d00526130c0528061290052612cc052920992095b91849083098061232052806126e0" - "528403806122e0526127205291839083098303838160c05109806126c05261270052806122c0526123005292099309" - "9384098061236052806126a0528203806122a0526127605292830983038360c0518209806126805261274052806122" - "80526123405292099309938409806123a0528061266052820380612260526127a05292830983038360c05182098061" - "2640526127805280612240526123805292099309938409806123e0528061262052820380612220526127e052928309" - "83038360c051820980612600526127c05280612200526123c052920993099384098061242052806125e05282038061" - "21e0526128205292830983038360c0518209806125c05261280052806121c052612400529209930993840980612460" - "52806125a0528203806121a0526128605292830983038360c051820980612580526128405280612180526124405292" - "099309938409806124a0528061256052820380612160526128a05292830983038360c0518209806125405261288052" - "80612140526124805292099309938409806124e0528061252052820380612120526128e05292830985038560c05182" - "0980612500526128c05280612100526124c052920992095b918490830980611b205280611ee052840380611ae05261" - "1f205291839083098303838160c0510980611ec052611f005280611ac052611b00529209930993840980611b605280" - "611ea052820380611aa052611f605292830983038360c051820980611e8052611f405280611a8052611b4052920993" - "0993840980611ba05280611e6052820380611a6052611fa05292830983038360c051820980611e4052611f80528061" - "1a4052611b80529209930993840980611be05280611e2052820380611a2052611fe05292830983038360c051820980" - "611e0052611fc05280611a0052611bc0529209930993840980611c205280611de0528203806119e052612020529283" - "0983038360c051820980611dc05261200052806119c052611c00529209930993840980611c605280611da052820380" - "6119a0526120605292830983038360c051820980611d8052612040528061198052611c40529209930993840980611c" - "a05280611d6052820380611960526120a05292830983038360c051820980611d4052612080528061194052611c8052" - "9209930993840980611ce05280611d2052820380611920526120e05292830985038560c051820980611d00526120c0" - "528061190052611cc052920992095b91849083098061132052806116e0528403806112e05261172052918390830983" - "03838160c05109806116c05261170052806112c05261130052920993099384098061136052806116a0528203806112" - "a0526117605292830983038360c051820980611680526117405280611280526113405292099309938409806113a052" - "8061166052820380611260526117a05292830983038360c05182098061164052611780528061124052611380529209" - "9309938409806113e0528061162052820380611220526117e05292830983038360c051820980611600526117c05280" - "611200526113c052920993099384098061142052806115e0528203806111e0526118205292830983038360c0518209" - "806115c05261180052806111c05261140052920993099384098061146052806115a0528203806111a0526118605292" - "830983038360c051820980611580526118405280611180526114405292099309938409806114a05280611560528203" - "80611160526118a05292830983038360c0518209806115405261188052806111405261148052920993099384098061" - "14e0528061152052820380611120526118e05292830985038560c051820980611500526118c05280611100526114c0" - "52920992095b918490830980610b205280610ee052840380610ae052610f205291839083098303838160c051098061" - "0ec052610f005280610ac052610b00529209930993840980610b605280610ea052820380610aa052610f6052928309" - "83038360c051820980610e8052610f405280610a8052610b40529209930993840980610ba05280610e605282038061" - "0a6052610fa05292830983038360c051820980610e4052610f805280610a4052610b80529209930993840980610be0" - "5280610e2052820380610a2052610fe05292830983038360c051820980610e0052610fc05280610a0052610bc05292" - "09930993840980610c205280610de0528203806109e0526110205292830983038360c051820980610dc05261100052" - "806109c052610c00529209930993840980610c605280610da0528203806109a0526110605292830983038360c05182" - "0980610d8052611040528061098052610c40529209930993840980610ca05280610d6052820380610960526110a052" - "92830983038360c051820980610d4052611080528061094052610c80529209930993840980610ce05280610d205282" - "0380610920526110e05292830985038560c051820980610d00526110c0528061090052610cc052920992095b918490" - "83098061032052806106e0528403806102e0526107205291839083098303838160c05109806106c052610700528061" - "02c05261030052920993099384098061036052806106a0528203806102a0526107605292830983038360c051820980" - "610680526107405280610280526103405292099309938409806103a0528061066052820380610260526107a0529283" - "0983038360c051820980610640526107805280610240526103805292099309938409806103e0528061062052820380" - "610220526107e05292830983038360c051820980610600526107c05280610200526103c05292099309938409806104" - "2052806105e0528203806101e0526108205292830983038360c0518209806105c05261080052806101c05261040052" - "920993099384098061046052806105a0528203806101a0526108605292830983038360c05182098061058052610840" - "5280610180526104405292099309938409806104a0528061056052820380610160526108a05292830983038360c051" - "820980610540526108805280610140526104805298090981038160c051820980610500526108c05280610100526104" - "c052930909806104e0528061052052810380610120526108e0523d518460071b606060003603046108000261020001" - "035b850180511561225657607c6138c6601e3980518103601e870301516202ffe01680518403906020015184036001" - "60606000360304610800026102000151603e01606060003603046108000261020001526002848a019451035161ffff" - "16565b858082800981605a8703516202ffe01680602001518286850983910986019282915109860181808083800981" - "84820999098103968189818780098a800101089809940993850109018603905b85808280098160588703516202ffe0" - "168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101" - "089809940993850109018603905b85808280098160568703516202ffe0168060200151828685098391098601928291" - "510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280" - "098160548703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103" - "968189818780098a800101089809940993850109018603905b85808280098160528703516202ffe016806020015182" - "8685098391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385" - "0109018603905b85808280098160508703516202ffe016806020015182868509839109860192829151098601818080" - "8380098184820999098103968189818780098a800101089809940993850109018603905b858082800981604e870351" - "6202ffe016806020015182868509839109860192829151098601818080838009818482099909810396818981878009" - "8a800101089809940993850109018603905b858082800981604c8703516202ffe01680602001518286850983910986" - "01928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b" - "858082800981604a8703516202ffe01680602001518286850983910986019282915109860181808083800981848209" - "99098103968189818780098a800101089809940993850109018603905b85808280098160488703516202ffe0168060" - "200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101089809" - "940993850109018603905b85808280098160468703516202ffe0168060200151828685098391098601928291510986" - "018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280098160" - "448703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189" - "818780098a800101089809940993850109018603905b85808280098160428703516202ffe016806020015182868509" - "8391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385010901" - "8603905b85808280098160408703516202ffe016806020015182868509839109860192829151098601818080838009" - "8184820999098103968189818780098a800101089809940993850109018603905b858082800981603e8703516202ff" - "e0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a8001" - "01089809940993850109018603905b858082800981603c8703516202ffe01680602001518286850983910986019282" - "91510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b858082" - "800981603a8703516202ffe01680602001518286850983910986019282915109860181808083800981848209990981" - "03968189818780098a800101089809940993850109018603905b85808280098160388703516202ffe0168060200151" - "828685098391098601928291510986018180808380098184820999098103968189818780098a800101089809940993" - "850109018603905b85808280098160368703516202ffe0168060200151828685098391098601928291510986018180" - "808380098184820999098103968189818780098a800101089809940993850109018603905b85808280098160348703" - "516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189818780" - "098a800101089809940993850109018603905b85808280098160328703516202ffe016806020015182868509839109" - "8601928291510986018180808380098184820999098103968189818780098a80010108980994099385010901860390" - "5b85808280098160308703516202ffe016806020015182868509839109860192829151098601818080838009818482" - "0999098103968189818780098a800101089809940993850109018603905b858082800981602e8703516202ffe01680" - "60200151828685098391098601928291510986018180808380098184820999098103968189818780098a8001010898" - "09940993850109018603905b858082800981602c8703516202ffe01680602001518286850983910986019282915109" - "86018180808380098184820999098103968189818780098a800101089809940993850109018603905b858082800981" - "602a8703516202ffe01680602001518286850983910986019282915109860181808083800981848209990981039681" - "89818780098a800101089809940993850109018603905b85808280098160288703516202ffe0168060200151828685" - "098391098601928291510986018180808380098184820999098103968189818780098a800101089809940993850109" - "018603905b85808280098160268703516202ffe0168060200151828685098391098601928291510986018180808380" - "098184820999098103968189818780098a800101089809940993850109018603905b85808280098160248703516202" - "ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a80" - "0101089809940993850109018603905b85808280098160228703516202ffe016806020015182868509839109860192" - "8291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b8580" - "8280098160208703516202ffe016806020015182868509839109860192829151098601818080838009818482099909" - "8103968189818780098a800101089809940993850109018603905b8582800192830986818001818080838909810397" - "800960030281818009888001019788010992090191869109850388840193515161ffff16565b858082800981605a87" - "03516202ffe01680602001518286850983910986019282915109860181808083800981848209990981039681898187" - "80098a800101089809940993850109018603905b85808280098160588703516202ffe0168060200151828685098391" - "098601928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603" - "905b85808280098160568703516202ffe0168060200151828685098391098601928291510986018180808380098184" - "820999098103968189818780098a800101089809940993850109018603905b85808280098160548703516202ffe016" - "8060200151828685098391098601928291510986018180808380098184820999098103968189818780098a80010108" - "9809940993850109018603905b85808280098160528703516202ffe016806020015182868509839109860192829151" - "0986018180808380098184820999098103968189818780098a800101089809940993850109018603905b8580828009" - "8160508703516202ffe016806020015182868509839109860192829151098601818080838009818482099909810396" - "8189818780098a800101089809940993850109018603905b858082800981604e8703516202ffe01680602001518286" - "85098391098601928291510986018180808380098184820999098103968189818780098a8001010898099409938501" - "09018603905b858082800981604c8703516202ffe01680602001518286850983910986019282915109860181808083" - "80098184820999098103968189818780098a800101089809940993850109018603905b858082800981604a87035162" - "02ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a" - "800101089809940993850109018603905b85808280098160488703516202ffe0168060200151828685098391098601" - "928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b85" - "808280098160468703516202ffe0168060200151828685098391098601928291510986018180808380098184820999" - "098103968189818780098a800101089809940993850109018603905b85808280098160448703516202ffe016806020" - "0151828685098391098601928291510986018180808380098184820999098103968189818780098a80010108980994" - "0993850109018603905b85808280098160428703516202ffe016806020015182868509839109860192829151098601" - "8180808380098184820999098103968189818780098a800101089809940993850109018603905b8580828009816040" - "8703516202ffe016806020015182868509839109860192829151098601818080838009818482099909810396818981" - "8780098a800101089809940993850109018603905b858082800981603e8703516202ffe01680602001518286850983" - "91098601928291510986018180808380098184820999098103968189818780098a8001010898099409938501090186" - "03905b858082800981603c8703516202ffe01680602001518286850983910986019282915109860181808083800981" - "84820999098103968189818780098a800101089809940993850109018603905b858082800981603a8703516202ffe0" - "168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101" - "089809940993850109018603905b85808280098160388703516202ffe0168060200151828685098391098601928291" - "510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280" - "098160368703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103" - "968189818780098a800101089809940993850109018603905b85808280098160348703516202ffe016806020015182" - "8685098391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385" - "0109018603905b85808280098160328703516202ffe016806020015182868509839109860192829151098601818080" - "8380098184820999098103968189818780098a800101089809940993850109018603905b8580828009816030870351" - "6202ffe016806020015182868509839109860192829151098601818080838009818482099909810396818981878009" - "8a800101089809940993850109018603905b858082800981602e8703516202ffe01680602001518286850983910986" - "01928291510986018180808380098184820999098103968189818780098a800101089809940993850109018603905b" - "858082800981602c8703516202ffe01680602001518286850983910986019282915109860181808083800981848209" - "99098103968189818780098a800101089809940993850109018603905b858082800981602a8703516202ffe0168060" - "200151828685098391098601928291510986018180808380098184820999098103968189818780098a800101089809" - "940993850109018603905b85808280098160288703516202ffe0168060200151828685098391098601928291510986" - "018180808380098184820999098103968189818780098a800101089809940993850109018603905b85808280098160" - "268703516202ffe0168060200151828685098391098601928291510986018180808380098184820999098103968189" - "818780098a800101089809940993850109018603905b85808280098160248703516202ffe016806020015182868509" - "8391098601928291510986018180808380098184820999098103968189818780098a80010108980994099385010901" - "8603905b85808280098160228703516202ffe016806020015182868509839109860192829151098601818080838009" - "8184820999098103968189818780098a800101089809940993850109018603905b85808280098160208703516202ff" - "e0168060200151828685098391098601928291510986018180808380098184820999098103968189818780098a8001" - "01089809940993850109018603905b806136a757505050508460071b606060003603046108000261020001035b8501" - "8051156134dd57603e6060600036030461080002610200015103606060003603046108000261020001528051810360" - "1e870301516202ffe0168051840390602001518403600160028451038452835161353757613627565b858082800981" - "86516002810388528703601e8d0301516202ffe0168060200151828685098391098601928291510986018180808380" - "09806135ff57876135a8575050505086516002810388528703601e8d0301516202ffe0168060200151820395505190" - "0394505050506001613620565b818680096135ea575050505050505085828001928309868180018180808389098103" - "978009600302818180098880010197880109920901918691098503613620565b505050505050505050506000600160" - "00613620565b8184820999098103968189818780098a800101089809940993850109018603905b8351613537575b83" - "6060600036030461080002610200011461367a57858280019283098681800181808083890981039780096003028181" - "800988800101978801099209019186910985039288019283511561362757613537565b806136a75780158260011484" - "1516166136935760006000fd5b60405260205260005250505050505060603df35b8486910960405284900684036020" - "528390063d5250505050505060603df300000000000000000000000000000000000000000000000000000000000002" - "c700000000000000000000000000000000000000000000000000000000000002a20000000000000000000000000000" - "00000000000000000000000000000000027a0000000000000000000000000000000000000000000000000000000000" - "0002a20000000000000000000000000000000000000000000000000000000000000252000000000000000000000000" - "00000000000000000000000000000000000002a2000000000000000000000000000000000000000000000000000000" - "000000027a00000000000000000000000000000000000000000000000000000000000002a200000000000000000000" - "0000000000000000000000000000000000000000022a00000000000000000000000000000000000000000000000000" - "000000000002a2000000000000000000000000000000000000000000000000000000000000027a0000000000000000" - "0000000000000000000000000000000000000000000002a20000000000000000000000000000000000000000000000" - "00000000000000025200000000000000000000000000000000000000000000000000000000000002a2000000000000" - "000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000" - "00000000000000000002a22b9d2b512b052ab92a6d2a2129d52989293d28f128a52859280d27c12775272926dd2691" - "264525f925ad2561251524c9247d243123e52399234d230122b534bf3473342733db338f334332f732ab325f321331" - "c7317b312f30e33097304b2fff2fb32f672f1b2ecf2e832e372deb2d9f2d532d072cbb2c6f2c232bd7" - "608060405234801561001057600080fd5b5060043610610047577c0100000000000000000000000000000000000000" - "00000000000000000060003504631605782b811461004c575b600080fd5b6100f26004803603602081101561006257" - "600080fd5b81019060208101813564010000000081111561007d57600080fd5b82018360208201111561008f576000" - "80fd5b803590602001918460018302840111640100000000831117156100b157600080fd5b91908080601f01602080" - "9104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610127" - "945050505050565b604080517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009092" - "168252519081900360200190f35b60006040518251602084019350604067ffffffffffffffc0600183011601600982" - "820310600181146101585761015f565b6040820191505b50776745230100efcdab890098badcfe001032547600c3d2" - "e1f06101d0565b6000838310156101c9575080820151928290039260208410156101c9577fffffffffffffffffffff" - "ffffffffffffffffffffffffffffffffffffffffffff60208590036101000a0119165b9392505050565b60005b8281" - "1015610686576101e684828961017e565b85526101f684602083018961017e565b6020860152604081850310600181" - "1461020e57610217565b60808286038701535b506040830381146001811461022b57610239565b6020860180516008" - "87021790525b5060405b6080811015610339578581017fffffffffffffffffffffffffffffffffffffffffffffffff" - "ffffffffffffffc08101517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8820151" - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08301517fffffffffffffffffffff" - "fffffffffffffffffffffffffffffffffffffffffff48401516002911891909218189081027ffffffffefffffffeff" - "fffffefffffffefffffffefffffffefffffffefffffffe1663800000009091047c0100000001000000010000000100" - "00000100000001000000010000000116179052600c0161023d565b5060805b61014081101561043a578581017fffff" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808101517fffffffffffffffffffffffffff" - "ffffffffffffffffffffffffffffffffffff908201517fffffffffffffffffffffffffffffffffffffffffffffffff" - "ffffffffffffffc08301517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8840151" - "6004911891909218189081027ffffffffcfffffffcfffffffcfffffffcfffffffcfffffffcfffffffcfffffffc1663" - "400000009091047c03000000030000000300000003000000030000000300000003000000031617905260180161033d" - "565b508160008060005b605081101561065c5760148104801561047257600181146104ae57600281146104e8576003" - "81146105275761055d565b6501000000000085046a0100000000000000000000860481186f01000000000000000000" - "000000000000870416189350635a827999925061055d565b6501000000000085046f01000000000000000000000000" - "00000086046a0100000000000000000000870418189350636ed9eba1925061055d565b6a0100000000000000000000" - "85046f010000000000000000000000000000008604818117650100000000008804169116179350638f1bbcdc925061" - "055d565b6501000000000085046f0100000000000000000000000000000086046a0100000000000000000000870418" - "18935063ca62c1d692505b50601f770800000000000000000000000000000000000000000000008504168063ffffff" - "e073080000000000000000000000000000000000000087041617905080840190508063ffffffff8616019050808301" - "9050807c0100000000000000000000000000000000000000000000000000000000600484028c015104019050740100" - "0000000000000000000000000000000000000081026501000000000086041794506a0100000000000000000000633f" - "ffffff6a040000000000000000000087041663c00000006604000000000000880416170277ffffffff00ffffffff00" - "0000000000ffffffff00ffffffff861617945050600181019050610442565b5050509190910177ffffffff00ffffff" - "ff00ffffffff00ffffffff00ffffffff16906040016101d3565b506c0100000000000000000000000063ffffffff82" - "1667ffffffff000000006101008404166bffffffff0000000000000000620100008504166fffffffff000000000000" - "000000000000630100000086041673ffffffff00000000000000000000000000000000640100000000870416171717" - "170294505050505091905056fea165627a7a7230582083396642a98f6018c81ca24dc0c2af8e842bd33a6b8d7f0863" - "2dc1bc372e466a0029"_hex, -}; + enum : uint8_t { @@ -794,6 +298,7 @@ void build_jumpdest(benchmark::State& state) state.counters["bytes"] = { static_cast(static_cast(code.size()) * state.iterations()), Counter::kIsRate}; + state.counters["size"] = {static_cast(static_cast(code.size()))}; } using namespace evmone; @@ -810,9 +315,10 @@ void jumpdest_analysis(State& state) DoNotOptimize(r); } - state.counters["bytes"] = { + state.counters["rate"] = { static_cast(static_cast(code.size()) * state.iterations()), Counter::kIsRate}; + state.counters["size"] = {static_cast(static_cast(code.size()))}; } } // namespace From f5943500b397110ebc66ec37873508d4a6747d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 12 Oct 2024 22:21:37 +0200 Subject: [PATCH 71/74] 10 bytecodes --- test/internal_benchmarks/test_bytecodes.cpp | 9 ++++++++- test/internal_benchmarks/test_bytecodes.hpp | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/internal_benchmarks/test_bytecodes.cpp b/test/internal_benchmarks/test_bytecodes.cpp index 3315b7956f..fd06447a89 100644 --- a/test/internal_benchmarks/test_bytecodes.cpp +++ b/test/internal_benchmarks/test_bytecodes.cpp @@ -30,6 +30,13 @@ const std::array test_bytecodes{ // 0x1111111254eeb25477b68fb85ed929f73a960582 "0x6080604052600436106102f65760003560e01c80637e54f0921161018f578063bf15fcd8116100e1578063d365c6951161008a578063f2fde38b11610064578063f2fde38b14610859578063f78dc25314610879578063fa461e331461088c57600080fd5b8063d365c69514610813578063e449022e14610833578063e5d7bde61461084657600080fd5b8063c805a666116100bb578063c805a66614610799578063ca4ece22146107b9578063cf6fc6e3146107d957600080fd5b8063bf15fcd814610744578063bfa7514314610764578063c53a02921461078457600080fd5b8063942461bb11610143578063bc80f1a81161011d578063bc80f1a8146106f1578063bd61951d14610704578063bddccd351461072457600080fd5b8063942461bb146106915780639570eeee146106be578063bc1ed74c146106d157600080fd5b806383197ef01161017457806383197ef01461064157806384bd6d29146106565780638da5cb5b1461066957600080fd5b80637e54f092146105f4578063825caba11461062157600080fd5b80635a0998431161024857806370ae92d2116101fc57806372c244a8116101d657806372c244a81461059457806374261145146105b457806378e3214f146105d457600080fd5b806370ae92d21461053257806370ccbd311461055f578063715018a61461057f57600080fd5b806363592c2b1161022d57806363592c2b146104d25780636c838250146104f25780636fe7b0ba1461051257600080fd5b80635a099843146104ac57806362e238bb146104bf57600080fd5b80632d9a56f6116102aa5780633eca9c0a116102845780633eca9c0a1461041b5780634f38e2b81461044957806356f161241461046957600080fd5b80632d9a56f6146103bb57806337e7316f146103db5780633c15fd91146103fb57600080fd5b806312aa3caf116102db57806312aa3caf146103435780632521b9301461036b5780632cc2878d1461038b57600080fd5b80630502b1c51461030a578063093d4fa51461033057600080fd5b36610305576103036108ac565b005b600080fd5b61031d61031836600461483f565b6108b6565b6040519081526020015b60405180910390f35b61031d61033e3660046148a9565b6108d0565b610356610351366004614975565b610d16565b60408051928352602083019190915201610327565b34801561037757600080fd5b5061031d610386366004614a17565b610fd1565b34801561039757600080fd5b506103ab6103a6366004614abf565b611001565b6040519015158152602001610327565b3480156103c757600080fd5b506103566103d6366004614af1565b61104b565b3480156103e757600080fd5b5061031d6103f6366004614af1565b61114a565b34801561040757600080fd5b5061031d610416366004614a17565b611164565b61042e610429366004614c15565b611188565b60408051938452602084019290925290820152606001610327565b34801561045557600080fd5b506103ab610464366004614c72565b6111aa565b34801561047557600080fd5b5061031d610484366004614cbe565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b61042e6104ba366004614cea565b6111d5565b61042e6104cd366004614d60565b61132b565b3480156104de57600080fd5b506103ab6104ed366004614abf565b421090565b3480156104fe57600080fd5b506103ab61050d366004614af1565b611355565b34801561051e57600080fd5b506103ab61052d366004614c72565b611384565b34801561053e57600080fd5b5061031d61054d366004614e0c565b60016020526000908152604090205481565b34801561056b57600080fd5b5061042e61057a366004614e29565b6113aa565b34801561058b57600080fd5b506103036113f1565b3480156105a057600080fd5b506103036105af366004614ecd565b611403565b3480156105c057600080fd5b506103ab6105cf366004614c72565b6114b2565b3480156105e057600080fd5b506103036105ef366004614cbe565b611524565b34801561060057600080fd5b5061031d61060f366004614abf565b60009081526002602052604090205490565b34801561062d57600080fd5b5061030361063c366004614abf565b611544565b34801561064d57600080fd5b50610303611553565b61031d610664366004614ef0565b61155e565b34801561067557600080fd5b506000546040516001600160a01b039091168152602001610327565b34801561069d57600080fd5b506106b16106ac366004614f67565b611571565b6040516103279190615001565b61042e6106cc366004615045565b61162a565b3480156106dd57600080fd5b5061031d6106ec366004614abf565b611767565b61031d6106ff36600461483f565b6117b7565b34801561071057600080fd5b5061030361071f366004615082565b6117c6565b34801561073057600080fd5b5061030361073f3660046150be565b611867565b34801561075057600080fd5b5061031d61075f366004615082565b611872565b34801561077057600080fd5b506103ab61077f366004614c72565b6118bd565b34801561079057600080fd5b50610303611930565b3480156107a557600080fd5b5061031d6107b43660046150e0565b61193a565b3480156107c557600080fd5b506103ab6107d4366004614c72565b611971565b3480156107e557600080fd5b506103ab6107f4366004614cbe565b6001600160a01b03919091166000908152600160205260409020541490565b34801561081f57600080fd5b5061042e61082e3660046151a4565b611998565b61031d610841366004615295565b611a2c565b61042e6108543660046152e8565b611a3b565b34801561086557600080fd5b50610303610874366004614e0c565b6124cb565b61031d6108873660046153ac565b612558565b34801561089857600080fd5b506103036108a7366004615416565b612573565b6108b4612785565b565b60006108c63387878787876127be565b9695505050505050565b60006001600160a01b0388161580156109085786341461090357604051631841b4e160e01b815260040160405180910390fd5b610a24565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316896001600160a01b0316036109f057506001341561096357604051631841b4e160e01b815260040160405180910390fd5b6040516323b872dd60e01b808252336004830152306024830152604482018990527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d60e01b9060008060648382885af16109c6573d6000823e3d81fd5b8181528a60048201526000806024836000885af16109e7573d6000823e3d81fd5b50505050610a24565b3415610a0f57604051631841b4e160e01b815260040160405180910390fd5b610a246001600160a01b038a16338d8a612b30565b8015610ab85760008b905060006327a9b42460e01b90506040518181528a60048201528960248201528860448201528760648201528c60848201528560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149838d875af1610ab0573d6000823e3d81fd5b505050610d07565b6001600160a01b0388161580610aff57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316886001600160a01b0316145b15610c75576040517f4cb6864c00000000000000000000000000000000000000000000000000000000808252600482018b90526024820189905260448201889052606482018790528c918a1560018114610b5e57306084830152610b65565b8d60848301525b508560ff1c601b0160a48201528660c48201526001600160ff1b03861660e482015261012061010482015264a62929c86960d31b610143820152600080610149836000875af1610bb8573d6000823e3d81fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168a6001600160a01b031603610c6e57604051630d0e30db60e41b8082527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29163a9059cbb60e01b906000806004838f885af1610c42573d6000823e3d81fd5b8181528f60048201528b60248201526000806044836000885af1610c69573d6000823e3d81fd5b505050505b5050610d07565b60008b90506000632b651a6c60e01b90506040518181528b60048201528a60248201528960448201528860648201528760848201528c60a48201528560ff1c601b0160c48201528660e48201526001600160ff1b03861661010482015261014061012482015264a62929c86960d31b610163820152600080610169836000875af1610d03573d6000823e3d81fd5b5050505b50939998505050505050505050565b6000808660a00135600003610d57576040517f0262dde400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d666020890189614e0c565b90506000610d7a60408a0160208b01614e0c565b90506000610d90836001600160a01b0316612bcd565b905060c08a013560021615610dd55780610dab576000610db1565b89608001355b3411610dd057604051631841b4e160e01b815260040160405180910390fd5b610e06565b80610de1576000610de7565b89608001355b3414610e0657604051631841b4e160e01b815260040160405180910390fd5b80610e4f578715610e2557610e256001600160a01b0384168a8a612c06565b610e4f33610e3960608d0160408e01614e0c565b6001600160a01b038616919060808e0135612b30565b610e608b338c608001358a8a612cbf565b60808a01359350610e7a6001600160a01b03831630612d1f565b945084600003610eb6576040517f28ebf24700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000199094019360c08a013560011615610f4f576000610edf6001600160a01b03851630612d1f565b90506001811115610f0e5760001901610ef88186615473565b9450610f0e6001600160a01b0385163383612dca565b610f1c8560a08d0135615486565b610f2a60808d013588615486565b1015610f495760405163f32bec2f60e01b815260040160405180910390fd5b50610f74565b8960a00135851015610f745760405163f32bec2f60e01b815260040160405180910390fd5b600080610f8760808d0160608e01614e0c565b6001600160a01b031614610faa57610fa560808c0160608d01614e0c565b610fac565b335b9050610fc26001600160a01b0384168288612dca565b50505050965096945050505050565b6000610fe76001600160a01b0389168484612c06565b610ff48988888888612eaa565b9998505050505050505050565b600060d082901c60a083901c65ffffffffffff168361101f83421090565b801561104257506001600160a01b03811660009081526001602052604090205482145b95945050505050565b6000803361105f6080850160608601614e0c565b6001600160a01b03161461109f576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110a88361114a565b6000818152600260205260409020549250905060001982016110f6576040517f41a26a6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518281526020810184905233917fcbfa7d191838ece7ba4783ca3a30afd316619b7f368094b57ee7ffde9a923db1910160405180910390a26000818152600260205260409020600190559092909150565b600061115e611157613131565b8390613258565b92915050565b600061117a6001600160a01b0389168484612c06565b610ff48989898989896127be565b600080600061119a87878787336111d5565b9250925092509450945094915050565b60008060006111b985856132d7565b915091508180156111c957508581115b925050505b9392505050565b60008060006112356111e5613131565b601f198a0180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8516156112a957600160fd1b851615801590611259575060418614155b15611277576040516317c2b1f160e01b815260040160405180910390fd5b6112878860600151828989613466565b6112a4576040516317c2b1f160e01b815260040160405180910390fd5b6112d6565b6112b988606001518289896134bb565b6112d6576040516317c2b1f160e01b815260040160405180910390fd5b6112e1888686613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a1955095509592505050565b60008060006113418b8b8b8b8b8b8b8b33611a3b565b925092509250985098509895505050505050565b600080600061136b61136685613b2e565b6132d7565b9150915081801561137c5750806001145b949350505050565b600080600061139385856132d7565b915091508180156111c95750909414949350505050565b60008060006113d185858c604001516001600160a01b0316612c069092919063ffffffff16565b6113de8a8a8a8a8a6111d5565b9250925092509750975097945050505050565b6113f9613b45565b6108b46000613b9f565b8060ff16600003611440576040517fbd71636d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526001602052604081205461145e9060ff84169061549d565b336000818152600160205260409081902083905551919250907ffc69110dd11eb791755e4abd6b7d281bae236de95736d38a23782814be5e10db906114a69084815260200190565b60405180910390a25050565b60008080805b63ffffffff87821c1692508215611517576000806114db61136686868a8c6154b0565b915091508180156114ec5750806001145b156114ff576001955050505050506111ce565b50839250611510905060208261549d565b90506114b8565b5060009695505050505050565b61152c613b45565b6115406001600160a01b0383163383612dca565b5050565b61155033826000613c07565b50565b61155b613b45565b33ff5b6000610ff489338a8a8a8a8a8a8a6108d0565b60606000825167ffffffffffffffff81111561158f5761158f614b26565b6040519080825280602002602001820160405280156115b8578160200160208202803683370190505b50905060005b835181101561162357600260008583815181106115dd576115dd6154da565b6020026020010151815260200190815260200160002054828281518110611606576116066154da565b60209081029190910101528061161b816154f0565b9150506115be565b5092915050565b600080600061168a61163a613131565b601f19890180517f74ab4f0cde46aaf927859983f7d04002116dd057d4c4941f6dbfb775c3e31f4582526101008220915260405161190160f01b8152600281019290925260228201526042902090565b9050600160fe1b8416156116e657600160fd1b8416156116d6576116b48760600151828888613c9b565b6116d1576040516317c2b1f160e01b815260040160405180910390fd5b611713565b6116b48760600151828888613d05565b6116f68760600151828888613d5a565b611713576040516317c2b1f160e01b815260040160405180910390fd5b61171e878533613522565b60408051848152602081018490529295509093507fc3b639f02b125bfa160e50739b8c44eb2d1b6908e2b6d5925c6d770f2ca78127910160405180910390a19450945094915050565b600081815260026020526040812054806117ad576040517fb838de9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000190192915050565b60006108c68686868686612eaa565b600080846001600160a01b031684846040516117e3929190615509565b600060405180830381855af49150503d806000811461181e576040519150601f19603f3d011682016040523d82523d6000602084013e611823565b606091505b509150915081816040517f1934afc800000000000000000000000000000000000000000000000000000000815260040161185e929190615569565b60405180910390fd5b611540338383613c07565b6000806000611882868686613da9565b9150915081611042576040517f1f1b8f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080805b63ffffffff87821c1692508215611923576000806118e661136686868a8c6154b0565b915091508115806118f8575080600114155b1561190b576000955050505050506111ce565b5083925061191c905060208261549d565b90506118c3565b5060019695505050505050565b6108b46001611403565b60006119506001600160a01b038b168484612c06565b6119618c8c8c8c8c8c8c8c8c6108d0565b9c9b505050505050505050505050565b600080600061198085856132d7565b915091508180156111c9575094909410949350505050565b6000808060148410156119d7576040517fd9e1c6dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006119e68888613dd7565b91945092509050611a016001600160a01b0384168383612c06565b505050611a158e8e8e8e8e8e8e8e8e611a3b565b9250925092509b509b509b98505050505050505050565b60006110423386868686612eaa565b600080806001600160a01b038416611a7f576040517fb0c4d05f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a888c61114a565b6000818152600260205260409020548894508793509091508c906000198101611add576040517fecef366400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611aef60c0840160a08501614e0c565b6001600160a01b031614158015611b1e575033611b1260c0840160a08501614e0c565b6001600160a01b031614155b15611b55576040517fd4dfdafe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80611c5857611b75611b6d6080840160608501614e0c565b848f8f6134bb565b611bab576040517f5cd5d23300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060c0810135366000611bbd84613e15565b91509150600160ff1b89166000148015611bd8575060148110155b15611c51576000366000611bec8585613dd7565b91945092509050611c076001600160a01b0384168383612c06565b60008881526002602052604090205415611c4d576040517fc5f2be5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505b5050611c5d565b600019015b6000611c6883613b2e565b90501115611caf57611c7982611355565b611caf576040517fb6629c0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8415841503611ce9576040517ee2a52200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611d795780851115611cfd578094505b611d1b611d0983613e23565b8460c00135888660e001358689613e31565b93506001600160ff1b038716611d318682615486565b611d3b8b87615486565b1115611d73576040517ffb8ae12900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611e44565b611d97611d8583613e67565b8460e00135878660c001358689613e75565b945080851115611dec57809450611db0611d0983613e23565b935087841115611dec576040517f939c420400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160ff1b038716611e008582615486565b611e0a8a88615486565b1015611e42576040517f481ea39200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b841580611e4f575083155b15611e86576040517ffba5a27600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84810390508060010160026000858152602001908152602001600020819055508d6060016020810190611eb99190614e0c565b6001600160a01b03167fb9ed0243fdf00f0545c63a0af8850c090d86bb46682baec4bf3c496814fe4f028483604051611efc929190918252602082015260400190565b60405180910390a26014611f0f83613e89565b905010611fb2576000366000611f2c611f2786613e89565b613dd7565b919450925090506001600160a01b0383166396a10e3387611f536080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b8152600401611f7c9897969594939291906155ad565b600060405180830381600087803b158015611f9657600080fd5b505af1158015611faa573d6000803e3d6000fd5b505050505050505b611fe5611fc56040840160208501614e0c565b611fd56080850160608601614e0c565b8888611fe087613e97565b613ea5565b61201b576040517f70a03f4800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148a106120f35760003660006120328e8e613dd7565b9250925092506000836001600160a01b031663ccee33d7338b8b87876040518663ffffffff1660e01b815260040161206e959493929190615600565b6020604051808303816000875af115801561208d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b1919061562f565b905087811180156120d057506120ce6120c987613e67565b613f00565b155b80156120e557506120e36120c987613e23565b155b156120ee578097505b505050505b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21661212d6060840160408501614e0c565b6001600160a01b03161480156121435750600034115b15612359578334101561216957604051631841b4e160e01b815260040160405180910390fd5b833411156121df57604051600090339034879003908381818185875af1925050503d80600081146121b6576040519150601f19603f3d011682016040523d82523d6000602084013e6121bb565b606091505b50509050806121dd5760405163b12d13eb60e01b815260040160405180910390fd5b505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561223a57600080fd5b505af115801561224e573d6000803e3d6000fd5b50506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216925063a9059cbb91506000905061229760a0860160808701614e0c565b6001600160a01b0316146122ba576122b560a0850160808601614e0c565b6122ca565b6122ca6080850160608601614e0c565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018790526044016020604051808303816000875af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123539190615648565b50612411565b341561237857604051631841b4e160e01b815260040160405180910390fd5b6123db61238b6060840160408501614e0c565b33600061239e60a0870160808801614e0c565b6001600160a01b0316146123c1576123bc60a0860160808701614e0c565b6123d1565b6123d16080860160608701614e0c565b87611fe087613f75565b612411576040517f478a520500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601461241c83613f83565b9050106124ba576000366000612434611f2786613f83565b919450925090506001600160a01b038316633504ed628761245b6080890160608a01614e0c565b338c8c8a89896040518963ffffffff1660e01b81526004016124849897969594939291906155ad565b600060405180830381600087803b15801561249e57600080fd5b505af11580156124b2573d6000803e3d6000fd5b505050505050505b505099509950999650505050505050565b6124d3613b45565b6001600160a01b03811661254f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161185e565b61155081613b9f565b60006125688787878787876127be565b979650505050505050565b6125cc565b3d6000803e3d6000fd5b8061258f5761258f612578565b600160005114601f3d11163d151780611540577ff27f64e40000000000000000000000000000000000000000000000000000000060005260046000fd5b604051601581017f0dfe1681d21220a7ddca3f43a9059cbb23b872dd0000000000000000000000008252602081600484335afa61260b5761260b612578565b60208082016004808501335afa61262457612624612578565b602060408201600460088501335afa61263f5761263f612578565b600080600088136001811461265d5760208401519250879150612665565b835192508891505b507fff1f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000084526060832083527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460208401526001600160a01b0360558520169250338318156126f6577fb2c027220000000000000000000000000000000000000000000000000000000060005260046000fd5b60843592507f0dfe1681d21220a7ddca3f43a9059cbb23b872dd00000000000000000000000084523083146001811461275757836014860152336034860152816054860152612752602060006064601089016000885af1612582565b61277a565b33601086015281603086015261277a602060006044600c89016000885af1612582565b505050505050505050565b3233036108b4576040517f1b10b0f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128b9565b7f0902f1ac0000000000000000000000000000000000000000000000000000000081526000604082600484875afa6127ff576127ff612578565b60603d14612831577f85cd58dc0000000000000000000000000000000000000000000000000000000060005260046000fd5b81516020830151861561284057905b8785029250633b9aca008202830181840204925050507f022c0d9f000000000000000000000000000000000000000000000000000000008252841594508415810260048301528481026024830152866044830152608060648301526000608483015260008060a4846000885af16108c6576108c6612578565b6dffffffffffffffffffffffffffff8511156128f9577fcf0b4d3a0000000000000000000000000000000000000000000000000000000060005260046000fd5b60405160c081016040528260051b84018435886000811461296957341561292b57631841b4e160e01b60005260046000fd5b6323b872dd60e01b84523360048501526001600160a01b03821660248501528860448501526129646020600060648760008f5af1612582565b6129ff565b34891461298157631841b4e160e01b60005260046000fd5b630d0e30db60e41b84526000806004868c73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129b5576129b5612578565b63a9059cbb60e01b84526001600160a01b0382166004850152886024850152600080604486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af16129ff576129ff612578565b50879350602086015b82811015612a50578035612a446001600160a01b03821663ffffffff60a01b851660a01c600160ff1b86166001600160a01b0387168a8a6127c5565b95509150602001612a08565b50600160fe1b81168015612adf57612a873063ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b9450632e1a7d4d60e01b8452846004850152600080602486600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1612ac457612ac4612578565b600080600080888f5af1612ada57612ada612578565b612b0b565b612b088b63ffffffff60a01b841660a01c600160ff1b85166001600160a01b03861689896127c5565b94505b50505050838110156108c65760405163f32bec2f60e01b815260040160405180910390fd5b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af19150508015612b8e573d8015612b8457600160005114601f3d11169150612b8c565b6000873b1191505b505b80612bc5576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b60006001600160a01b038216158061115e57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600060e0829003612c4457612c3d847fd505accf000000000000000000000000000000000000000000000000000000008585613f91565b9050612cac565b610100829003612c7a57612c3d847f8fcbaf0c000000000000000000000000000000000000000000000000000000008585613f91565b6040517f6827585700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80612cb957612cb9613fe3565b50505050565b6040517f4b64e4920000000000000000000000000000000000000000000000000000000080825260048201869052908284602483013784836024830101526000808460440183348b5af1612d16573d6000823e3d81fd5b50505050505050565b6000612d2a83612bcd565b15612d4057506001600160a01b0381163161115e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015612d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc3919061562f565b905061115e565b8015612ea557612dd983612bcd565b15612e915780471015612e18576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b03168261138890604051600060405180830381858888f193505050503d8060008114612e6a576040519150601f19603f3d011682016040523d82523d6000602084013e612e6f565b606091505b5050905080612cb95760405163b12d13eb60e01b815260040160405180910390fd5b612ea56001600160a01b0384168383613fef565b505050565b600081808203612ee6576040517f67e7c0f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8591506000198101341515600080600160fd1b888886818110612f0b57612f0b6154da565b90506020020135161190508115612fb157883414612f3c57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08a6040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f9757600080fd5b505af1158015612fab573d6000803e3d6000fd5b50505050505b600184111561305157612feb3083612fc95733612fcb565b305b89896000818110612fde57612fde6154da565b9050602002013588614038565b945060015b838110156130265761301c30308a8a8581811061300f5761300f6154da565b9050602002013589614038565b9550600101612ff0565b5061304a81613035578a613037565b305b30898987818110612fde57612fde6154da565b945061306f565b61306c8161305f578a613061565b305b83612fc95733612fcb565b94505b878510156130905760405163f32bec2f60e01b815260040160405180910390fd5b801561312457604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156130f857600080fd5b505af115801561310c573d6000803e3d6000fd5b50613124925050506001600160a01b038b16866141d4565b5050505095945050505050565b6000306001600160a01b037f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605821614801561318a57507f000000000000000000000000000000000000000000000000000000000000000146145b156131b457507f1c0eb4c27d5b523ca136c0b3b83a4dcac8b70225b38be8507ba1a3f2af03cfca90565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f5c6cbfb2848b981a8f93044b3530be1fac304ecd5042396ca8729cb8fdd718f3828401527fceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c160608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000368161326a61012086018661566a565b60405191935091507f0a244ca8a150ac294c14fcff9277051ced9a5b23e966a0ff0522e989da23116c9082848237828120610140820152610120876020830137818152610160902060405161190160f01b81526002810187905260228101829052604290209094506108c6565b60008060006132e685856142ed565b60e01c905060006132f986866004614317565b9050632cc2878c19820161333057600161331282611001565b61331d576000613320565b60015b90945060ff16925061345f915050565b63bf15fcd88210156133be57636fe7b0ba82101561338257634f38e2b71982016133665760016133128261046489896064614348565b6363592c2a19820161337d57600161331282421090565b61344d565b636fe7b0b91982016133a05760016133128261052d89896064614348565b637426114419820161337d576001613312826105cf89896064614348565b63ca4ece228210156134115763bf15fcd71982016133f35760016133e88261075f89896064614348565b93509350505061345f565b63bfa7514219820161337d5760016133128261077f89896064614348565b63ca4ece2119820161342f576001613312826107d489896064614348565b63cf6fc6e219820161344d576001613312826107f489896024614317565b613458308787613da9565b9350935050505b9250929050565b600080631626ba7e60e01b905060405181815285600482015260406024820152836044820152838560648301376020600085606401838a5afa156134b15760203d1460005183141692505b5050949350505050565b60006001600160a01b0385166134d35750600061137c565b60408214806134e25750604182145b80156135095750846001600160a01b03166134fe858585614378565b6001600160a01b0316145b156135165750600161137c565b61104285858585613466565b6000806001600160a01b038316613565576040517f692e45e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606085015160808601516001600160a01b031615801590613593575060808601516001600160a01b03163314155b156135ca576040517fe8c6632100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff604082901c1680158015906135e957508042115b15613620576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61362c83836000613c07565b505060a086015160c08701517f0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716600081900361366f57829550819450613715565b600160ff1b8816156136ca57828111156136b5576040517faa34b69600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8095506136c383838861442d565b9450613715565b81811115613704576040517f7f902a9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80945061371283838761445b565b95505b5050508260001480613725575081155b1561375c576040517f07b6e79f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686602001516001600160a01b03161480156137c257507f1000000000000000000000000000000000000000000000000000000000000000851615155b1561395a576040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018590527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906323b872dd906064016020604051808303816000875af115801561383c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138609190615648565b50604051632e1a7d4d60e01b8152600481018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156138c357600080fd5b505af11580156138d7573d6000803e3d6000fd5b505050506000846001600160a01b03168461138890604051600060405180830381858888f193505050503d806000811461392d576040519150601f19603f3d011682016040523d82523d6000602084013e613932565b606091505b50509050806139545760405163b12d13eb60e01b815260040160405180910390fd5b50613974565b6020860151613974906001600160a01b0316828686612b30565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031686604001516001600160a01b03161480156139b95750600034115b15613aec578134146139de57604051631841b4e160e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613a3957600080fd5b505af1158015613a4d573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018790527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063a9059cbb925060440190506020604051808303816000875af1158015613ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae69190615648565b50613b25565b3415613b0b57604051631841b4e160e01b815260040160405180910390fd5b6040860151613b25906001600160a01b0316338385612b30565b50935093915050565b366000613b3c836004614468565b91509150915091565b6000546001600160a01b031633146108b45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161185e565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038316600090815260036020908152604080832066ffffffffffffff600887901c16808552928190529220549091600160ff86161b841791808316839003613c82576040517ff71fbda200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000938452602091909152604090922091179055505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604160448201528460648201526001600160ff1b03841660848201528360ff1c601b0160a48201536020600060a5838a5afa156134b15750600051143d6020141695945050505050565b600080631626ba7e60e01b905060405181815285600482015260406024820152604060448201528460648201528360848201526020600060a4838a5afa156134b15750600051143d6020141695945050505050565b60006001600160a01b038516613d725750600061137c565b846001600160a01b0316613d878585856144c3565b6001600160a01b031603613d9d5750600161137c565b61104285858585613d05565b60008060405183858237602060008583895afa3d602014169250508115613dcf57506000515b935093915050565b600036816014841015613dfd5760405163779ab6bd60e11b815260040160405180910390fd5b505050813560601c9260149092019160131990910190565b366000613b3c836005614468565b366000613b3c836003614468565b6000868103613e4c57613e4586858761442d565b9050612568565b613e5b88888888888888614532565b98975050505050505050565b366000613b3c836002614468565b6000868103613e4c57613e4584878761445b565b366000613b3c836006614468565b366000613b3c836000614468565b6040516323b872dd60e01b8082526004820187905260248201869052604482018590526000918385606483013760206000856064018360008d5af19050600160005114601f3d11163d15178116925050509695505050505050565b60006001821480156111ce575082826000818110613f2057613f206154da565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f7800000000000000000000000000000000000000000000000000000000000000149392505050565b366000613b3c836001614468565b366000613b3c836007614468565b6000816004016040518581528385600483013760206000838360008b5af192505050801561137c573d8015613fd257600160005114601f3d11169150613fda565b6000863b1191505b50949350505050565b6040513d6000823e3d81fd5b6140028363a9059cbb60e01b84846146be565b612ea5576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600160ff1b831615801561410e576000846001600160a01b031663128acb08888461406488614700565b604080516001600160a01b038d1660208201526401000276a491016040516020818303038152906040526040518663ffffffff1660e01b81526004016140ae9594939291906156b1565b60408051808303816000875af11580156140cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f091906156eb565b915050614105816141009061570f565b614783565b9250505061137c565b6000846001600160a01b031663128acb08888461412a88614700565b604080516001600160a01b038d16602082015273fffd8963efd1fc6a506488495d951d5263988d2591016040516020818303038152906040526040518663ffffffff1660e01b81526004016141839594939291906156b1565b60408051808303816000875af11580156141a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c591906156eb565b5090506141056141008261570f565b804710156142245760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161185e565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614271576040519150601f19603f3d011682016040523d82523d6000602084013e614276565b606091505b5050905080612ea55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161185e565b600060048210156143115760405163779ab6bd60e11b815260040160405180910390fd5b50503590565b60006020820183101561433d5760405163779ab6bd60e11b815260040160405180910390fd5b509190910135919050565b3660008284101561436c5760405163779ab6bd60e11b815260040160405180910390fd5b50509182019291900390565b6000604051826041811461439757604081146143b157600091506143d9565b604085013560001a602083015260408560408401376143d9565b60208501358060ff1c601b01602084015260208660408501376001600160ff1b031660608301525b508015614425577f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16060820151101561442557848152600080526020600060808360015afa5060005191505b509392505050565b60008360018161443d8686615486565b614447919061549d565b6144519190615473565b61137c919061572b565b6000826144518584615486565b3660008060058460078111156144805761448061574d565b901b905061449261012086018661566a565b6144b79161010088013580851c63ffffffff9081169360209290921b861c16916154b0565b92509250509250929050565b60006001600160ff1b0382167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1811015614425576040518581528360ff1c601b016020820152846040820152816060820152600080526020600060808360015afa505060005195945050505050565b600060018790036145be576145478888613f00565b1561458c57858514614585576040517f49986e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5082612568565b6040517fbec74c8500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660006145cd8b8b613dd7565b925092509250600080846001600160a01b031684848c8b8b6040516020016145f9959493929190615763565b60408051601f198184030181529082905261461391615782565b600060405180830381855afa9150503d806000811461464e576040519150601f19603f3d011682016040523d82523d6000602084013e614653565b606091505b509150915081158061466757508051602014155b1561469e576040517f110b8e7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808060200190518101906146b2919061562f565b95505050505050612568565b60006040518481528360048201528260248201526020600060448360008a5af1915050801561137c573d8015613fd257600160005114601f3d11169150613fda565b60006001600160ff1b0382111561477f5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e74323536000000000000000000000000000000000000000000000000606482015260840161185e565b5090565b60008082121561477f5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161185e565b6001600160a01b038116811461155057600080fd5b80356147f5816147d5565b919050565b60008083601f84011261480c57600080fd5b50813567ffffffffffffffff81111561482457600080fd5b6020830191508360208260051b850101111561345f57600080fd5b60008060008060006080868803121561485757600080fd5b8535614862816147d5565b94506020860135935060408601359250606086013567ffffffffffffffff81111561488c57600080fd5b614898888289016147fa565b969995985093965092949392505050565b60008060008060008060008060006101208a8c0312156148c857600080fd5b89356148d3816147d5565b985060208a01356148e3816147d5565b975060408a01356148f3816147d5565b965060608a0135614903816147d5565b989b979a50959860808101359760a0820135975060c0820135965060e08201359550610100909101359350915050565b60008083601f84011261494557600080fd5b50813567ffffffffffffffff81111561495d57600080fd5b60208301915083602082850101111561345f57600080fd5b60008060008060008086880361014081121561499057600080fd5b873561499b816147d5565b965060e0601f19820112156149af57600080fd5b5060208701945061010087013567ffffffffffffffff808211156149d257600080fd5b6149de8a838b01614933565b90965094506101208901359150808211156149f857600080fd5b50614a0589828a01614933565b979a9699509497509295939492505050565b60008060008060008060008060c0898b031215614a3357600080fd5b8835614a3e816147d5565b97506020890135614a4e816147d5565b96506040890135955060608901359450608089013567ffffffffffffffff80821115614a7957600080fd5b614a858c838d016147fa565b909650945060a08b0135915080821115614a9e57600080fd5b50614aab8b828c01614933565b999c989b5096995094979396929594505050565b600060208284031215614ad157600080fd5b5035919050565b60006101408284031215614aeb57600080fd5b50919050565b600060208284031215614b0357600080fd5b813567ffffffffffffffff811115614b1a57600080fd5b61137c84828501614ad8565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614b6557614b65614b26565b604052919050565b600060e08284031215614b7f57600080fd5b60405160e0810181811067ffffffffffffffff82111715614ba257614ba2614b26565b604052823581529050806020830135614bba816147d5565b60208201526040830135614bcd816147d5565b60408201526060830135614be0816147d5565b60608201526080830135614bf3816147d5565b8060808301525060a083013560a082015260c083013560c08201525092915050565b6000806000806101208587031215614c2c57600080fd5b614c368686614b6d565b935060e085013567ffffffffffffffff811115614c5257600080fd5b614c5e87828801614933565b959890975094956101000135949350505050565b600080600060408486031215614c8757600080fd5b83359250602084013567ffffffffffffffff811115614ca557600080fd5b614cb186828701614933565b9497909650939450505050565b60008060408385031215614cd157600080fd5b8235614cdc816147d5565b946020939093013593505050565b60008060008060006101408688031215614d0357600080fd5b614d0d8787614b6d565b945060e086013567ffffffffffffffff811115614d2957600080fd5b614d3588828901614933565b9095509350506101008601359150610120860135614d52816147d5565b809150509295509295909350565b60008060008060008060008060c0898b031215614d7c57600080fd5b883567ffffffffffffffff80821115614d9457600080fd5b614da08c838d01614ad8565b995060208b0135915080821115614db657600080fd5b614dc28c838d01614933565b909950975060408b0135915080821115614ddb57600080fd5b50614de88b828c01614933565b999c989b5096999698976060880135976080810135975060a0013595509350505050565b600060208284031215614e1e57600080fd5b81356111ce816147d5565b6000806000806000806000610160888a031215614e4557600080fd5b614e4f8989614b6d565b965060e088013567ffffffffffffffff80821115614e6c57600080fd5b614e788b838c01614933565b90985096506101008a013595506101208a01359150614e96826147d5565b9093506101408901359080821115614ead57600080fd5b50614eba8a828b01614933565b989b979a50959850939692959293505050565b600060208284031215614edf57600080fd5b813560ff811681146111ce57600080fd5b600080600080600080600080610100898b031215614f0d57600080fd5b8835614f18816147d5565b97506020890135614f28816147d5565b96506040890135614f38816147d5565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b60006020808385031215614f7a57600080fd5b823567ffffffffffffffff80821115614f9257600080fd5b818501915085601f830112614fa657600080fd5b813581811115614fb857614fb8614b26565b8060051b9150614fc9848301614b3c565b8181529183018401918481019088841115614fe357600080fd5b938501935b83851015613e5b57843582529385019390850190614fe8565b6020808252825182820181905260009190848201906040850190845b818110156150395783518352928401929184019160010161501d565b50909695505050505050565b600080600080610140858703121561505c57600080fd5b6150668686614b6d565b9660e08601359650610100860135956101200135945092505050565b60008060006040848603121561509757600080fd5b83356150a2816147d5565b9250602084013567ffffffffffffffff811115614ca557600080fd5b600080604083850312156150d157600080fd5b50508035926020909101359150565b60008060008060008060008060008060006101408c8e03121561510257600080fd5b8b3561510d816147d5565b9a5060208c013561511d816147d5565b995060408c013561512d816147d5565b985060608c013561513d816147d5565b975060808c0135965060a08c0135955060c08c0135945060e08c013593506101008c013592506101208c013567ffffffffffffffff81111561517e57600080fd5b61518a8e828f01614933565b915080935050809150509295989b509295989b9093969950565b60008060008060008060008060008060006101008c8e0312156151c657600080fd5b67ffffffffffffffff808d3511156151dd57600080fd5b6151ea8e8e358f01614ad8565b9b508060208e013511156151fd57600080fd5b61520d8e60208f01358f01614933565b909b50995060408d013581101561522357600080fd5b6152338e60408f01358f01614933565b909950975060608d0135965060808d0135955060a08d0135945061525960c08e016147ea565b93508060e08e0135111561526c57600080fd5b5061527d8d60e08e01358e01614933565b81935080925050509295989b509295989b9093969950565b600080600080606085870312156152ab57600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156152d057600080fd5b6152dc878288016147fa565b95989497509550505050565b600080600080600080600080600060e08a8c03121561530657600080fd5b893567ffffffffffffffff8082111561531e57600080fd5b61532a8d838e01614ad8565b9a5060208c013591508082111561534057600080fd5b61534c8d838e01614933565b909a50985060408c013591508082111561536557600080fd5b506153728c828d01614933565b90975095505060608a0135935060808a0135925060a08a0135915060c08a013561539b816147d5565b809150509295985092959850929598565b60008060008060008060a087890312156153c557600080fd5b86356153d0816147d5565b955060208701356153e0816147d5565b94506040870135935060608701359250608087013567ffffffffffffffff81111561540a57600080fd5b614a0589828a016147fa565b6000806000806060858703121561542c57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561545157600080fd5b6152dc87828801614933565b634e487b7160e01b600052601160045260246000fd5b8181038181111561115e5761115e61545d565b808202811582820484141761115e5761115e61545d565b8082018082111561115e5761115e61545d565b600080858511156154c057600080fd5b838611156154cd57600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b6000600182016155025761550261545d565b5060010190565b8183823760009101908152919050565b60005b8381101561553457818101518382015260200161551c565b50506000910152565b60008151808452615555816020860160208601615519565b601f01601f19169290920160200192915050565b821515815260406020820152600061137c604083018461553d565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b88815260006001600160a01b03808a1660208401528089166040840152508660608301528560808301528460a083015260e060c08301526155f260e083018486615584565b9a9950505050505050505050565b6001600160a01b0386168152846020820152836040820152608060608201526000612568608083018486615584565b60006020828403121561564157600080fd5b5051919050565b60006020828403121561565a57600080fd5b815180151581146111ce57600080fd5b6000808335601e1984360301811261568157600080fd5b83018035915067ffffffffffffffff82111561569c57600080fd5b60200191503681900382131561345f57600080fd5b60006001600160a01b038088168352861515602084015285604084015280851660608401525060a0608083015261256860a083018461553d565b600080604083850312156156fe57600080fd5b505080516020909101519092909150565b6000600160ff1b82036157245761572461545d565b5060000390565b60008261574857634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fd5b8486823790930191825260208201526040810191909152606001919050565b60008251615794818460208701615519565b919091019291505056fea264697066735822122040321861ce858a2c911db7a2e1f42f4368d23b5251b80dd661a6f2abf19c358d64736f6c63430008110033"_hex, + // 0x06450dee7fd2fb8e39061434babcfc05599a6fb8 + "0x608060405234801561001057600080fd5b50600436106102825760003560e01c80637e7aa62e116101585780637e7aa62e146104735780638979c87c1461047b5780638da7ad2314610483578063909a2ff6146104d857806395d89b41146104e0578063962ca496146104e857806399202454146104f05780639dc29fac146104f85780639ff054df1461050b578063a457c2d71461051e578063a9059cbb14610531578063b0fd1fc214610544578063b21d35f214610557578063b4800cdc14610560578063ba3ec74114610569578063bcfe394f1461035d578063c0c6525914610571578063c56f0bab14610579578063ce653d5f14610581578063dd62ed3e146105a1578063df282331146105b4578063e3af6d0a14610638578063e81917b41461065f578063ed2f236914610668578063f060482914610671578063f340faed14610679578063fed742691461068357600080fd5b80630237893214610287578063069612a5146102a357806306fdde03146102ac578063095ea7b3146102c15780630bfae56b146102e45780630f2e1228146102ec578063110d7fc2146102f457806316f9c8fd146102fc57806318160ddd146103375780631c2440821461033f5780631c560305146103485780631c6f212e1461035d57806323b872dd146103655780632a62d966146102f4578063313ce5671461037857806332870fda14610387578063395093511461038f5780633ccfd60b146103a257806345125715146103aa57806352c7f8dc146103b2578063543d36521461035d5780635bccb4c4146103ba57806361a52a36146103cd5780637010d7a1146103d757806370a082311461042f57806372475f94146104585780637b0472f014610460575b600080fd5b61029061016d81565b6040519081526020015b60405180910390f35b61029060085481565b6102b461068b565b60405161029a9190612419565b6102d46102cf366004612483565b61071d565b604051901515815260200161029a565b610290610737565b610290606381565b610290600081565b610304610748565b60405161029a91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b600254610290565b61029060055481565b61035b610356366004612483565b6107b9565b005b610290600181565b6102d46103733660046124ad565b610a08565b6040516012815260200161029a565b610290605a81565b6102d461039d366004612483565b610a2c565b61035b610a4e565b610290610ba2565b61035b610bb1565b61035b6103c83660046124e9565b610cc2565b6102906201518081565b6103df610f64565b60405161029a919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0918201519181019190915260c00190565b61029061043d36600461250b565b6001600160a01b031660009081526020819052604090205490565b610290600f81565b61035b61046e3660046124e9565b611009565b610290600281565b61029061117e565b6104b861049136600461250b565b600a6020526000908152604090208054600182015460028301546003909301549192909184565b60408051948552602085019390935291830152606082015260800161029a565b610290606481565b6102b4611188565b610290611197565b6102906111a1565b61035b610506366004612483565b6111ab565b61035b610519366004612526565b61135d565b6102d461052c366004612483565b6115d2565b6102d461053f366004612483565b61164d565b61029061055236600461253f565b61165b565b61029061138881565b61029060065481565b6102b46116ea565b610290611706565b610290600781565b61029061058f36600461250b565b600b6020526000908152604090205481565b6102906105af366004612571565b611715565b6106016105c236600461250b565b6009602052600090815260409020805460018201546002830154600384015460048501546005909501546001600160a01b039094169492939192909186565b604080516001600160a01b0390971687526020870195909552938501929092526060840152608083015260a082015260c00161029a565b6102907f000000000000000000000000000000000000000000000000000000006341b37381565b610290610bb881565b61029060075481565b610290611740565b610290620186a081565b610290601481565b60606003805461069a906125a4565b80601f01602080910402602001604051908101604052809291908181526020018280546106c6906125a4565b80156107135780601f106106e857610100808354040283529160200191610713565b820191906000526020600020905b8154815290600101906020018083116106f657829003601f168201915b5050505050905090565b60003361072b818585611759565b60019150505b92915050565b6107456201518060646125f4565b81565b6107736040518060800160405280600081526020016000815260200160008152602001600081525090565b50336000908152600a6020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b33600090815260096020908152604091829020825160c08101845281546001600160a01b03908116825260018301549382019390935260028201549381019390935260038101546060840152600481015460808401526005015460a083015283166108795760405162461bcd60e51b815260206004820152602560248201527f4352616e6b3a2043616e6e6f742073686172652077697468207a65726f206164604482015264647265737360d81b60648201526084015b60405180910390fd5b600082116108c95760405162461bcd60e51b815260206004820181905260248201527f4352616e6b3a2043616e6e6f74207368617265207a65726f2070657263656e746044820152606401610870565b606582106109195760405162461bcd60e51b815260206004820181905260248201527f4352616e6b3a2043616e6e6f74207368617265203130302b2070657263656e746044820152606401610870565b600081606001511161093d5760405162461bcd60e51b81526004016108709061260b565b806040015142116109605760405162461bcd60e51b81526004016108709061263a565b600061098382606001518360200151846040015185608001518660a0015161187e565b61099590670de0b6b3a76400006125f4565b9050600060646109a585846125f4565b6109af9190612685565b905060006109bd82846126a7565b90506109ca335b8261197c565b6109d4868361197c565b6109dc611a49565b60405183815233906000805160206127f8833981519152906020015b60405180910390a2505050505050565b600033610a16858285611a9d565b610a21858585611b17565b506001949350505050565b60003361072b818585610a3f8383611715565b610a4991906126ba565b611759565b336000908152600a6020908152604091829020825160808101845281548152600182015492810192909252600281015492820183905260030154606082015290610ad15760405162461bcd60e51b815260206004820152601460248201527358454e3a206e6f207374616b652065786973747360601b6044820152606401610870565b6000610aef8260400151836000015184602001518560600151611cd3565b600780549192506000610b01836126cd565b9190505550816040015160086000828254610b1c91906126a7565b90915550610b3b905033828460400151610b3691906126ba565b61197c565b60408083015181519081526020810183905233917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a25050336000908152600a60205260408120818155600181018290556002810182905560030155565b6000610bac611d31565b905090565b33600090815260096020908152604091829020825160c08101845281546001600160a01b031681526001820154928101929092526002810154928201929092526003820154606082018190526004830154608083015260059092015460a082015290610c2f5760405162461bcd60e51b81526004016108709061260b565b80604001514211610c525760405162461bcd60e51b81526004016108709061263a565b6000610c7582606001518360200151846040015185608001518660a0015161187e565b610c8790670de0b6b3a76400006125f4565b9050610c92336109c4565b610c9a611a49565b60405181815233906000805160206127f8833981519152906020015b60405180910390a25050565b33600090815260096020908152604091829020825160c08101845281546001600160a01b03168152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260059091015460a082015260658310610d715760405162461bcd60e51b815260206004820181905260248201527f4352616e6b3a2043616e6e6f74207368617265203e3130302070657263656e746044820152606401610870565b6000816060015111610d955760405162461bcd60e51b81526004016108709061260b565b80604001514211610db85760405162461bcd60e51b81526004016108709061263a565b6000610ddb82606001518360200151846040015185608001518660a0015161187e565b610ded90670de0b6b3a76400006125f4565b905060006064610dfd86846125f4565b610e079190612685565b90506000610e1582846126a7565b9050610e20336109c4565b610e28611a49565b60405183815233906000805160206127f88339815191529060200160405180910390a260008211610e6b5760405162461bcd60e51b8152600401610870906126e4565b6001610e7a62015180826125f4565b610e8491906126a7565b610e9162015180876125f4565b11610eae5760405162461bcd60e51b815260040161087090612712565b610ebd620151806103e86125f4565b610ec89060016126ba565b610ed562015180876125f4565b10610ef25760405162461bcd60e51b815260040161087090612745565b336000908152600a602052604090206002015415610f225760405162461bcd60e51b815260040161087090612778565b610f2c8286611e37565b604080518381526020810187905233917f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee9091016109f8565b610fa66040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b5033600090815260096020908152604091829020825160c08101845281546001600160a01b03168152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260059091015460a082015290565b816110133361043d565b101561105b5760405162461bcd60e51b815260206004820152601760248201527658454e3a206e6f7420656e6f7567682062616c616e636560481b6044820152606401610870565b6000821161107b5760405162461bcd60e51b8152600401610870906126e4565b600161108a62015180826125f4565b61109491906126a7565b6110a162015180836125f4565b116110be5760405162461bcd60e51b815260040161087090612712565b6110cd620151806103e86125f4565b6110d89060016126ba565b6110e562015180836125f4565b106111025760405162461bcd60e51b815260040161087090612745565b336000908152600a6020526040902060020154156111325760405162461bcd60e51b815260040161087090612778565b61113c3383611eda565b6111468282611e37565b604080518381526020810183905233917f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee909101610cb6565b6000610bac61200e565b60606004805461069a906125a4565b6000610bac612052565b6000610bac6120bf565b600081116111f35760405162461bcd60e51b8152602060048201526015602482015274109d5c9b8e8810995b1bddc81b5a5b881b1a5b5a5d605a1b6044820152606401610870565b336040516301ffc9a760e01b815263543746b160e01b60048201526001600160a01b0391909116906301ffc9a790602401602060405180830381865afa158015611241573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126591906127a3565b6112b15760405162461bcd60e51b815260206004820152601e60248201527f4275726e3a206e6f74206120737570706f7274656420636f6e747261637400006044820152606401610870565b6112bc823383611a9d565b6112c68282611eda565b6001600160a01b0382166000908152600b6020526040812080548392906112ee9084906126ba565b9091555033905060405163543746b160e01b81526001600160a01b03848116600483015260248201849052919091169063543746b190604401600060405180830381600087803b15801561134157600080fd5b505af1158015611355573d6000803e3d6000fd5b505050505050565b600061136c62015180836125f4565b9050600161137d62015180826125f4565b61138791906126a7565b81116113d15760405162461bcd60e51b815260206004820152601960248201527821a930b7359d102a32b936903632b9b9903a3430b71036b4b760391b6044820152606401610870565b6113d9611d31565b6113e49060016126ba565b81106114415760405162461bcd60e51b815260206004820152602660248201527f4352616e6b3a205465726d206d6f7265207468616e2063757272656e74206d6160448201526578207465726d60d01b6064820152608401610870565b33600090815260096020526040902060030154156114a15760405162461bcd60e51b815260206004820152601f60248201527f4352616e6b3a204d696e7420616c726561647920696e2070726f6772657373006044820152606401610870565b60006040518060c001604052806114b53390565b6001600160a01b03168152602081018590526040016114d484426126ba565b815260200160055481526020016114e96120bf565b81526020016114f661200e565b9052336000908152600960209081526040808320845181546001600160a01b0319166001600160a01b039091161781559184015160018301558301516002820155606083015160038201556080830151600482015560a08301516005909101556006805492935090611567836127c5565b91905055506115733390565b6001600160a01b03167fe9149e1b5059238baed02fa659dbf4bd932fbcf760a431330df4d934bc942f3784600560008154809291906115b1906127c5565b909155506040805192835260208301919091520160405180910390a2505050565b600033816115e08286611715565b9050838110156116405760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610870565b610a218286868403611759565b60003361072b818585611b17565b60008061167261166a8761219b565b600f0b6121b9565b905060006116ae6116828561219b565b6116a561168e8861219b565b6116a561169a8b61219b565b600f88900b90612293565b600f0b90612293565b90506116d46116cc6116c16103e861219b565b600f84900b906122d1565b600f0b612328565b6001600160401b0316925050505b949350505050565b6040518060600160405280602581526020016128386025913981565b610745620151806103e86125f4565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600161174f62015180826125f4565b61074591906126a7565b6001600160a01b0383166117bb5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610870565b6001600160a01b03821661181c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610870565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60008061188b85426126a7565b9050600061189882612344565b90506000734bba9b6b49f3dfa6615f079e9d66b0aa68b04a4d636d5433e68a6005546118c491906126a7565b6040516001600160e01b031960e084901b168152600481019190915260026024820152604401602060405180830381865af4158015611907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192b91906127de565b9050600061193b866103e86126ba565b9050600061194b83898c8561165b565b9050606461195985826126a7565b61196390836125f4565b61196d9190612685565b9b9a5050505050505050505050565b6001600160a01b0382166119d25760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610870565b80600260008282546119e491906126ba565b90915550506001600160a01b03821660009081526020819052604081208054839290611a119084906126ba565b90915550506040518181526001600160a01b038316906000906000805160206128188339815191529060200160405180910390a35050565b33600090815260096020526040812080546001600160a01b0319168155600181018290556002810182905560038101829055600481018290556005018190556006805491611a96836126cd565b9190505550565b6000611aa98484611715565b90506000198114611b115781811015611b045760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610870565b611b118484848403611759565b50505050565b6001600160a01b038316611b7b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610870565b6001600160a01b038216611bdd5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610870565b6001600160a01b03831660009081526020819052604090205481811015611c555760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610870565b6001600160a01b03808516600090815260208190526040808220858503905591851681529081208054849290611c8c9084906126ba565b92505081905550826001600160a01b0316846001600160a01b031660008051602061281883398151915284604051611cc691815260200190565b60405180910390a3611b11565b600082421115611d2657600061016d611cec86856125f4565b611cf990620f42406125f4565b611d039190612685565b90506305f5e100611d1482886125f4565b611d1e9190612685565b9150506116e2565b506000949350505050565b60006113886005541115611e29576000611d5f6116cc611d51600f61219b565b6116a561166a60055461219b565b6001600160401b031690506000611d7962015180836125f4565b611d876201518060646125f4565b611d9191906126ba565b9050734bba9b6b49f3dfa6615f079e9d66b0aa68b04a4d637ae2b5c782611dbd620151806103e86125f4565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865af4158015611dfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2291906127de565b9250505090565b610bac6201518060646125f4565b60405180608001604052808281526020016201518083611e5791906125f4565b611e6190426126ba565b8152602001838152602001611e74612052565b9052336000908152600a602090815260408083208451815591840151600183015583015160028201556060909201516003909201919091556007805491611eba836127c5565b91905055508160086000828254611ed191906126ba565b90915550505050565b6001600160a01b038216611f3a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610870565b6001600160a01b03821660009081526020819052604090205481811015611fae5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610870565b6001600160a01b0383166000908152602081905260408120838303905560028054849290611fdd9084906126a7565b90915550506040518281526000906001600160a01b0385169060008051602061281883398151915290602001611871565b600080620186a0600554600161202491906125f4565b61202e9190612685565b9050606481111561204157600091505090565b61204c8160646126a7565b91505090565b600080612063605a620151806125f4565b61208d7f000000000000000000000000000000000000000000000000000000006341b373426126a7565b6120979190612685565b9050806120a6600260146126a7565b10156120b457600291505090565b61204c8160146126a7565b600080620151806120f07f000000000000000000000000000000000000000000000000000000006341b373426126a7565b6120fa9190612685565b9050610bb881101561219357734bba9b6b49f3dfa6615f079e9d66b0aa68b04a4d636d5433e661212c83610bb86126a7565b6040516001600160e01b031960e084901b168152600481019190915260016024820152604401602060405180830381865af415801561216f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204c91906127de565b600191505090565b6000677fffffffffffffff8211156121b257600080fd5b5060401b90565b60008082600f0b136121ca57600080fd5b6000600f83900b600160401b81126121e4576040918201911d5b600160201b81126121f7576020918201911d5b620100008112612209576010918201911d5b610100811261221a576008918201911d5b6010811261222a576004918201911d5b6004811261223a576002918201911d5b60028112612249576001820191505b603f19820160401b600f85900b607f8490031b6001603f1b5b60008113156122885790800260ff81901c8281029390930192607f011c9060011d612262565b509095945050505050565b6000600f83810b9083900b0260401d60016001607f1b031981128015906122c1575060016001607f1b038113155b6122ca57600080fd5b9392505050565b600081600f0b6000036122e357600080fd5b600082600f0b604085600f0b901b816122fe576122fe61266f565b05905060016001607f1b031981128015906122c1575060016001607f1b038113156122ca57600080fd5b60008082600f0b121561233a57600080fd5b50600f0b60401d90565b6000806123546201518084612685565b9050612362600160076126a7565b8111156123725750606392915050565b6000600160076123838460036126ba565b6001901b6123919190612685565b61239b91906126a7565b604051637ae2b5c760e01b81526004810182905260636024820152909150734bba9b6b49f3dfa6615f079e9d66b0aa68b04a4d90637ae2b5c790604401602060405180830381865af41580156123f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e291906127de565b600060208083528351808285015260005b818110156124465785810183015185820160400152820161242a565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461247e57600080fd5b919050565b6000806040838503121561249657600080fd5b61249f83612467565b946020939093013593505050565b6000806000606084860312156124c257600080fd5b6124cb84612467565b92506124d960208501612467565b9150604084013590509250925092565b600080604083850312156124fc57600080fd5b50508035926020909101359150565b60006020828403121561251d57600080fd5b6122ca82612467565b60006020828403121561253857600080fd5b5035919050565b6000806000806080858703121561255557600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121561258457600080fd5b61258d83612467565b915061259b60208401612467565b90509250929050565b600181811c908216806125b857607f821691505b6020821081036125d857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610731576107316125de565b6020808252601590820152744352616e6b3a204e6f206d696e742065786973747360581b604082015260600190565b6020808252818101527f4352616e6b3a204d696e74206d61747572697479206e6f742072656163686564604082015260600190565b634e487b7160e01b600052601260045260246000fd5b6000826126a257634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610731576107316125de565b80820180821115610731576107316125de565b6000816126dc576126dc6125de565b506000190190565b60208082526014908201527358454e3a2042656c6f77206d696e207374616b6560601b604082015260600190565b60208082526019908201527858454e3a2042656c6f77206d696e207374616b65207465726d60381b604082015260600190565b60208082526019908201527858454e3a2041626f7665206d6178207374616b65207465726d60381b604082015260600190565b60208082526011908201527058454e3a207374616b652065786973747360781b604082015260600190565b6000602082840312156127b557600080fd5b815180151581146122ca57600080fd5b6000600182016127d7576127d76125de565b5060010190565b6000602082840312156127f057600080fd5b505191905056fed74752b13281df13701575f3a507e9b1242e0b5fb040143211c481c1fce573a6ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef404d724a61636b4c6576696e20406c62656c79616576206661697263727970746f2e6f7267a2646970667358221220c3156834d26b467f4edb2d28607a50e8cbfb9ca20cda44d2f1f27c7689a3c01464736f6c63430008110033"_hex, + // 0xdef1c0ded9bec7f1a1670819833240f027b25eff + "0x6080604052600436106100225760003560e01c8063972fdd261461013e57610029565b3661002957005b6000610075600080368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff610174169050565b90506000610082826101c0565b905073ffffffffffffffffffffffffffffffffffffffff81166100b0576100b06100ab83610219565b6102c4565b600060608273ffffffffffffffffffffffffffffffffffffffff166000366040516100dc9291906103ee565b600060405180830381855af49150503d8060008114610117576040519150601f19603f3d011682016040523d82523d6000602084013e61011c565b606091505b50915091508161012f5761012f816102c4565b610138816102cc565b50505050005b34801561014a57600080fd5b5061015e6101593660046103a7565b6101c0565b60405161016b9190610427565b60405180910390f35b60008160040183511015610195576101956100ab6003855185600401610302565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60006101ca6102d4565b7fffffffff0000000000000000000000000000000000000000000000000000000092909216600090815260209290925250604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6060604051610227906103fe565b6040518091039020826040516024016102409190610448565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b805160208201fd5b805160208201f35b6000806102e160006102e7565b92915050565b600060808260048111156102f757fe5b600101901b92915050565b6060632800659560e01b84848460405160240161032193929190610475565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290509392505050565b6000602082840312156103b8578081fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146103e7578182fd5b9392505050565b6000828483379101908152919050565b7f4e6f74496d706c656d656e7465644572726f72286279746573342900000000008152601b0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b606081016008851061048357fe5b93815260208101929092526040909101529056fea2646970667358221220266f45dcc0f640b86b617d19d2affc31f4b5547fd56bc2761d8eddc74675491564736f6c63430006080033"_hex, + + // 0x06a9ab27c7e2255df1815e6cc0168d7755feb19a + "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220f8a584f5571c1942ce287f04e503e7a62bf0c9046c8825d7d0dba2e353309c8e64736f6c63430008180033"_hex, }; -} +} // namespace evmone::test diff --git a/test/internal_benchmarks/test_bytecodes.hpp b/test/internal_benchmarks/test_bytecodes.hpp index 19ad2f1344..a0691129f9 100644 --- a/test/internal_benchmarks/test_bytecodes.hpp +++ b/test/internal_benchmarks/test_bytecodes.hpp @@ -9,5 +9,5 @@ namespace evmone::test { -extern const std::array test_bytecodes; +extern const std::array test_bytecodes; } From 138632b2b0fcd7b79bc49da2f05779ca4ca69de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 13 Oct 2024 22:10:57 +0200 Subject: [PATCH 72/74] cleanups --- test/experimental/jumpdest_analysis.cpp | 20 ++++++++++- test/experimental/jumpdest_analysis.hpp | 6 ++-- test/experimental/opcode_manip.hpp | 5 +-- test/fuzzer/jumpdest_analysis_fuzz.cpp | 2 +- test/internal_benchmarks/analysis_bench.cpp | 38 ++++++++++----------- test/internal_benchmarks/test_bytecodes.cpp | 2 +- test/unittests/jumpdest_analysis_test.cpp | 19 +++++++---- test/unittests/opcode_manip_test.cpp | 2 +- 8 files changed, 60 insertions(+), 34 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 8ef33ef6d7..0cddfa0f6f 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -9,7 +9,7 @@ #include #include -namespace evmone::experimental +namespace evmone::exp::jda { JumpdestBitset jda_reference(bytes_view code) { @@ -74,6 +74,24 @@ JumpdestBitset jda_speculate_push_data_size(bytes_view code) return m; } +JumpdestBitset jda_speculate_push_data_size2(bytes_view code) +{ + JumpdestBitset m(code.size()); + for (size_t i = 0; i < code.size(); ++i) + { + const auto op = code[i]; + if (op < OP_JUMPDEST) + continue; + + const auto potential_push_data_len = get_push_data_size(op); + if (potential_push_data_len <= 32) + i += potential_push_data_len; + else if (op == OP_JUMPDEST) [[unlikely]] + m[i] = true; + } + return m; +} + JumpdestBitset build_jumpdest_map_sttni(bytes_view code) { const auto code_size = code.size(); diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 1af19f2466..bf686b1563 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -1,13 +1,14 @@ // evmone: Fast Ethereum Virtual Machine implementation // Copyright 2020 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#pragma once #include #include #include #include -namespace evmone::experimental +namespace evmone::exp::jda { class JumpdestBitset : std::vector { @@ -65,6 +66,7 @@ class bitset32 JumpdestBitset jda_reference(bytes_view code); JumpdestBitset jda_speculate_push_data_size(bytes_view code); +JumpdestBitset jda_speculate_push_data_size2(bytes_view code); JumpdestBitset build_jumpdest_map_sttni(bytes_view code); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); std::vector build_jumpdest_map_str_avx2_mask(const uint8_t* code, size_t code_size); @@ -80,4 +82,4 @@ std::unique_ptr build_internal_code_v2(const uint8_t* code, size_t co std::unique_ptr build_internal_code_v3(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v4(const uint8_t* code, size_t code_size); std::unique_ptr build_internal_code_v8(const uint8_t* code, size_t code_size); -} // namespace evmone::experimental +} // namespace evmone::exp::jda diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp index d847986b52..20b9bde776 100644 --- a/test/experimental/opcode_manip.hpp +++ b/test/experimental/opcode_manip.hpp @@ -1,11 +1,12 @@ // evmone: Fast Ethereum Virtual Machine implementation // Copyright 2020 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#pragma once #include #include -namespace evmone::experimental +namespace evmone::exp { inline constexpr bool is_push(uint8_t op) noexcept { @@ -72,4 +73,4 @@ inline int find_first_push_opt3(const uint8_t* code) noexcept auto z2 = z / 8; return z2; } -} // namespace evmone::experimental +} // namespace evmone::exp diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index d539175155..bfc6b7012a 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -7,7 +7,7 @@ using namespace evmone; -using namespace evmone::experimental; +using namespace evmone::exp::jda; namespace { diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index aced7bafdc..d32260e397 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -29,7 +29,7 @@ enum : uint8_t [[gnu::noinline]] auto build_bitset2(const uint8_t* code, size_t code_size) { - evmone::experimental::JumpdestMap m(code_size); + evmone::exp::jda::JumpdestMap m(code_size); for (size_t i = 0; i < code_size; ++i) { const auto op = code[i]; @@ -302,7 +302,7 @@ void build_jumpdest(benchmark::State& state) } using namespace evmone; -using namespace evmone::experimental; +using namespace evmone::exp::jda; using namespace benchmark; template @@ -328,35 +328,35 @@ void jumpdest_analysis(State& state) BENCHMARK(jumpdest_analysis) ARGS; BENCHMARK(jumpdest_analysis) ARGS; BENCHMARK(jumpdest_analysis) ARGS; +BENCHMARK(jumpdest_analysis) ARGS; -BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, - evmone::experimental::build_jumpdest_map_bitset1) +BENCHMARK_TEMPLATE( + build_jumpdest, evmone::exp::jda::JumpdestMap, evmone::exp::jda::build_jumpdest_map_bitset1) ARGS; -BENCHMARK_TEMPLATE(build_jumpdest, evmone::experimental::JumpdestMap, build_bitset2) ARGS; +BENCHMARK_TEMPLATE(build_jumpdest, evmone::exp::jda::JumpdestMap, build_bitset2) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec) ARGS; -BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2) +BENCHMARK_TEMPLATE(build_jumpdest, std::vector, evmone::exp::jda::build_jumpdest_map_str_avx2) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask) + build_jumpdest, std::vector, evmone::exp::jda::build_jumpdest_map_str_avx2_mask) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask_v2) + build_jumpdest, std::vector, evmone::exp::jda::build_jumpdest_map_str_avx2_mask_v2) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::vector, evmone::experimental::build_jumpdest_map_str_avx2_mask2) + build_jumpdest, std::vector, evmone::exp::jda::build_jumpdest_map_str_avx2_mask2) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd1) + build_jumpdest, evmone::exp::jda::bitset32, evmone::exp::jda::build_jumpdest_map_simd1) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd2) + build_jumpdest, evmone::exp::jda::bitset32, evmone::exp::jda::build_jumpdest_map_simd2) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd3) + build_jumpdest, evmone::exp::jda::bitset32, evmone::exp::jda::build_jumpdest_map_simd3) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, evmone::experimental::bitset32, evmone::experimental::build_jumpdest_map_simd4) + build_jumpdest, evmone::exp::jda::bitset32, evmone::exp::jda::build_jumpdest_map_simd4) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec3) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec4) ARGS; @@ -365,19 +365,19 @@ BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec6) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_vec7) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::vector, build_bytes) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v1) + build_jumpdest, std::unique_ptr, evmone::exp::jda::build_internal_code_v1) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v2) + build_jumpdest, std::unique_ptr, evmone::exp::jda::build_internal_code_v2) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v3) + build_jumpdest, std::unique_ptr, evmone::exp::jda::build_internal_code_v3) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v4) + build_jumpdest, std::unique_ptr, evmone::exp::jda::build_internal_code_v4) ARGS; BENCHMARK_TEMPLATE( - build_jumpdest, std::unique_ptr, evmone::experimental::build_internal_code_v8) + build_jumpdest, std::unique_ptr, evmone::exp::jda::build_internal_code_v8) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code2p) ARGS; BENCHMARK_TEMPLATE(build_jumpdest, std::unique_ptr, build_shadow_code3p) ARGS; diff --git a/test/internal_benchmarks/test_bytecodes.cpp b/test/internal_benchmarks/test_bytecodes.cpp index fd06447a89..b3e9fec146 100644 --- a/test/internal_benchmarks/test_bytecodes.cpp +++ b/test/internal_benchmarks/test_bytecodes.cpp @@ -7,7 +7,7 @@ namespace evmone::test { // https://dune.com/queries/3700178 -const std::array test_bytecodes{ +const std::array test_bytecodes{ // WETH: "0x6060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014757806318160ddd146101a157806323b872dd146101ca5780632e1a7d4d14610243578063313ce5671461026657806370a082311461029557806395d89b41146102e2578063a9059cbb14610370578063d0e30db0146103ca578063dd62ed3e146103d4575b6100b7610440565b005b34156100c457600080fd5b6100cc6104dd565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010c5780820151818401526020810190506100f1565b50505050905090810190601f1680156101395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015257600080fd5b610187600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061057b565b604051808215151515815260200191505060405180910390f35b34156101ac57600080fd5b6101b461066d565b6040518082815260200191505060405180910390f35b34156101d557600080fd5b610229600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061068c565b604051808215151515815260200191505060405180910390f35b341561024e57600080fd5b61026460048080359060200190919050506109d9565b005b341561027157600080fd5b610279610b05565b604051808260ff1660ff16815260200191505060405180910390f35b34156102a057600080fd5b6102cc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b18565b6040518082815260200191505060405180910390f35b34156102ed57600080fd5b6102f5610b30565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561033557808201518184015260208101905061031a565b50505050905090810190601f1680156103625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561037b57600080fd5b6103b0600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610bce565b604051808215151515815260200191505060405180910390f35b6103d2610440565b005b34156103df57600080fd5b61042a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610be3565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105735780601f1061054857610100808354040283529160200191610573565b820191906000526020600020905b81548152906001019060200180831161055657829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156106dc57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156107b457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b156108cf5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084457600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a2757600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501515610ab457600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bc65780601f10610b9b57610100808354040283529160200191610bc6565b820191906000526020600020905b815481529060010190602001808311610ba957829003601f168201915b505050505081565b6000610bdb33848461068c565b905092915050565b60046020528160005260406000206020528060005260406000206000915091505054815600a165627a7a72305820deb4c2ccab3c2fdca32ab3f46728389c2fe2c165d5fafa07661e4e004f6c344a0029"_hex, diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 2890bae977..7d42231468 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -8,7 +8,7 @@ #include using namespace evmone; -using namespace evmone::experimental; +using namespace evmone::exp::jda; using namespace evmone::test; namespace @@ -26,12 +26,16 @@ bool is_jumpdest(const bitset32& a, size_t index) noexcept } const bytecode bytecode_test_cases[]{ - {}, + bytecode{}, push(0x5b), OP_JUMPDEST, push(0), push(0x5b) + OP_JUMPDEST, push(0x60) + OP_JUMPDEST, + bytecode{"00"} + OP_JUMPDEST, + bytecode{"80"} + OP_JUMPDEST, + bytecode{"5f"} + OP_JUMPDEST, + bytecode{"ff"} + OP_JUMPDEST, "5b000000000000000000000000000000", "005b0000000000000000000000000000", "605b00605b000000000000000000000000000000000000000000000000000000", @@ -58,20 +62,22 @@ template class jumpdest_analysis_test : public testing::Test {}; using test_types = testing::Types, - I, I>; + I, + I, I>; TYPED_TEST_SUITE(jumpdest_analysis_test, test_types); TYPED_TEST(jumpdest_analysis_test, validate) { - for (const auto& code : bytecode_test_cases) + for (size_t t = 0; t < std::size(bytecode_test_cases); ++t) { + const auto& code = bytecode_test_cases[t]; const auto expected = jda_reference(code); const auto analysis = TypeParam::analyze(code); for (size_t i = 0; i < code.size() + CODE_PADDING_CHECK_SIZE; ++i) { - SCOPED_TRACE(i); - EXPECT_EQ(analysis.check_jumpdest(i), expected.check_jumpdest(i)); + EXPECT_EQ(analysis.check_jumpdest(i), expected.check_jumpdest(i)) + << t << "[" << i << "]"; } } } @@ -85,7 +91,6 @@ TEST(jumpdest_analysis, compare_implementations) const auto data_size = t.size(); const auto a0 = jda_reference(t); - const auto v2 = jda_speculate_push_data_size(data); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto v5a = build_jumpdest_map_str_avx2_mask_v2(data, data_size); diff --git a/test/unittests/opcode_manip_test.cpp b/test/unittests/opcode_manip_test.cpp index 941ce5e36a..e9569cbb5b 100644 --- a/test/unittests/opcode_manip_test.cpp +++ b/test/unittests/opcode_manip_test.cpp @@ -6,7 +6,7 @@ #include "test/utils/bytecode.hpp" #include -using namespace evmone::experimental; +using namespace evmone::exp; using namespace evmone::test; TEST(opcode_manip, find_first_push) From 1d2b9b684d4667d600ceee69699eb1eeb5e4edb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 13 Oct 2024 22:16:17 +0200 Subject: [PATCH 73/74] cleanups --- test/experimental/jumpdest_analysis.cpp | 4 ++-- test/experimental/jumpdest_analysis.hpp | 4 ++-- test/fuzzer/jumpdest_analysis_fuzz.cpp | 4 ++-- test/internal_benchmarks/analysis_bench.cpp | 4 ++-- test/unittests/jumpdest_analysis_test.cpp | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index 0cddfa0f6f..d31889db64 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -11,7 +11,7 @@ namespace evmone::exp::jda { -JumpdestBitset jda_reference(bytes_view code) +JumpdestBitset reference(bytes_view code) { JumpdestBitset map(code.size()); for (size_t i = 0; i < code.size(); ++i) @@ -59,7 +59,7 @@ static pushdata_info build_pushdata_mask(const uint8_t* code, uint32_t push_mask return {pushdata_mask, 32}; } -JumpdestBitset jda_speculate_push_data_size(bytes_view code) +JumpdestBitset speculate_push_data_size(bytes_view code) { JumpdestBitset m(code.size()); for (size_t i = 0; i < code.size(); ++i) diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index bf686b1563..2ba50e41c2 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -64,8 +64,8 @@ class bitset32 } }; -JumpdestBitset jda_reference(bytes_view code); -JumpdestBitset jda_speculate_push_data_size(bytes_view code); +JumpdestBitset reference(bytes_view code); +JumpdestBitset speculate_push_data_size(bytes_view code); JumpdestBitset jda_speculate_push_data_size2(bytes_view code); JumpdestBitset build_jumpdest_map_sttni(bytes_view code); std::vector build_jumpdest_map_str_avx2(const uint8_t* code, size_t code_size); diff --git a/test/fuzzer/jumpdest_analysis_fuzz.cpp b/test/fuzzer/jumpdest_analysis_fuzz.cpp index bfc6b7012a..f93bac2601 100644 --- a/test/fuzzer/jumpdest_analysis_fuzz.cpp +++ b/test/fuzzer/jumpdest_analysis_fuzz.cpp @@ -29,8 +29,8 @@ inline bool is_jumpdest(const bitset32& a, size_t index) noexcept extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noexcept { const bytes_view code{data, data_size}; - const auto a0 = jda_reference(code); - const auto v2 = jda_speculate_push_data_size(data); + const auto a0 = reference(code); + const auto v2 = speculate_push_data_size(data); const auto v3 = build_jumpdest_map_sttni(code); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index d32260e397..fd1f6e693b 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -325,9 +325,9 @@ void jumpdest_analysis(State& state) #define ARGS ->DenseRange(0, test_bytecodes.size() - 1) -BENCHMARK(jumpdest_analysis) ARGS; +BENCHMARK(jumpdest_analysis) ARGS; BENCHMARK(jumpdest_analysis) ARGS; -BENCHMARK(jumpdest_analysis) ARGS; +BENCHMARK(jumpdest_analysis) ARGS; BENCHMARK(jumpdest_analysis) ARGS; BENCHMARK_TEMPLATE( diff --git a/test/unittests/jumpdest_analysis_test.cpp b/test/unittests/jumpdest_analysis_test.cpp index 7d42231468..90b53d77a9 100644 --- a/test/unittests/jumpdest_analysis_test.cpp +++ b/test/unittests/jumpdest_analysis_test.cpp @@ -62,7 +62,7 @@ template class jumpdest_analysis_test : public testing::Test {}; using test_types = testing::Types, - I, + I, I, I>; TYPED_TEST_SUITE(jumpdest_analysis_test, test_types); @@ -71,7 +71,7 @@ TYPED_TEST(jumpdest_analysis_test, validate) for (size_t t = 0; t < std::size(bytecode_test_cases); ++t) { const auto& code = bytecode_test_cases[t]; - const auto expected = jda_reference(code); + const auto expected = reference(code); const auto analysis = TypeParam::analyze(code); for (size_t i = 0; i < code.size() + CODE_PADDING_CHECK_SIZE; ++i) @@ -90,7 +90,7 @@ TEST(jumpdest_analysis, compare_implementations) const auto data = t.data(); const auto data_size = t.size(); - const auto a0 = jda_reference(t); + const auto a0 = reference(t); const auto v4 = build_jumpdest_map_str_avx2(data, data_size); const auto v5 = build_jumpdest_map_str_avx2_mask(data, data_size); const auto v5a = build_jumpdest_map_str_avx2_mask_v2(data, data_size); From d506834034282c04ac905970e1d11619a7d9472e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 14 Oct 2024 18:59:32 +0200 Subject: [PATCH 74/74] remove opcode manip --- test/experimental/CMakeLists.txt | 2 +- test/experimental/jumpdest_analysis.cpp | 6 +- test/experimental/jumpdest_analysis.hpp | 66 ++++++++++++++++++ test/experimental/opcode_manip.hpp | 76 --------------------- test/internal_benchmarks/analysis_bench.cpp | 1 + 5 files changed, 70 insertions(+), 81 deletions(-) delete mode 100644 test/experimental/opcode_manip.hpp diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt index 0dae07fb1b..6cf5ecbeda 100644 --- a/test/experimental/CMakeLists.txt +++ b/test/experimental/CMakeLists.txt @@ -10,6 +10,6 @@ target_link_libraries(evmone-experimental PRIVATE evmone evmc::instructions) target_compile_options(evmone-experimental PUBLIC -mavx -mavx2 -msse4) target_sources( evmone-experimental PRIVATE + jumpdest_analysis.hpp jumpdest_analysis.cpp - opcode_manip.hpp ) diff --git a/test/experimental/jumpdest_analysis.cpp b/test/experimental/jumpdest_analysis.cpp index d31889db64..fd626b5e59 100644 --- a/test/experimental/jumpdest_analysis.cpp +++ b/test/experimental/jumpdest_analysis.cpp @@ -3,11 +3,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "jumpdest_analysis.hpp" -#include "opcode_manip.hpp" -#include +#include #include #include -#include namespace evmone::exp::jda { @@ -752,4 +750,4 @@ std::unique_ptr build_internal_code_v8(const uint8_t* code, size_t co return m; } -} // namespace evmone::experimental +} // namespace evmone::exp::jda diff --git a/test/experimental/jumpdest_analysis.hpp b/test/experimental/jumpdest_analysis.hpp index 2ba50e41c2..0cf96236b7 100644 --- a/test/experimental/jumpdest_analysis.hpp +++ b/test/experimental/jumpdest_analysis.hpp @@ -10,6 +10,72 @@ namespace evmone::exp::jda { +inline constexpr bool is_push(uint8_t op) noexcept +{ + return static_cast(op) >= OP_PUSH1; +} + +inline constexpr int find_first_push(const uint8_t* code) noexcept +{ + for (int i = 0; i < 8; ++i) + { + if (is_push(code[i])) + return i; + } + return -1; +} + +inline int find_first_push_opt1(const uint8_t* code) noexcept +{ + uint64_t b; + __builtin_memcpy(&b, code, sizeof(b)); + b = __builtin_bswap64(b); + + const auto d = (~b) & (b << 1) & (b << 2) & 0x8080808080808080; + + if (d == 0) + return -1; + + auto z = __builtin_clzll(d); + auto z2 = z / 8; + return z2; +} + +inline int find_first_push_opt2(const uint8_t* code) noexcept +{ + uint64_t b; + __builtin_memcpy(&b, code, sizeof(b)); + b = __builtin_bswap64(b); + uint64_t mask = 0x8080808080808080; + + auto e2 = b << 2; + auto f2 = b << 1; + auto g2 = ~b; + auto d1 = e2 & f2 & g2 & mask; + + if (d1 == 0) + return -1; + + auto z = __builtin_clzll(d1); + auto z2 = z / 8; + return z2; +} + +inline int find_first_push_opt3(const uint8_t* code) noexcept +{ + uint64_t b; + __builtin_memcpy(&b, code, sizeof(b)); + + const auto d = (b >> 5) & (b >> 6) & (~b >> 7) & 0x0101010101010101; + + if (d == 0) + return -1; + + auto z = __builtin_ctzll(d); + auto z2 = z / 8; + return z2; +} + class JumpdestBitset : std::vector { public: diff --git a/test/experimental/opcode_manip.hpp b/test/experimental/opcode_manip.hpp deleted file mode 100644 index 20b9bde776..0000000000 --- a/test/experimental/opcode_manip.hpp +++ /dev/null @@ -1,76 +0,0 @@ -// evmone: Fast Ethereum Virtual Machine implementation -// Copyright 2020 The evmone Authors. -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include -#include - -namespace evmone::exp -{ -inline constexpr bool is_push(uint8_t op) noexcept -{ - return static_cast(op) >= OP_PUSH1; -} - -inline constexpr int find_first_push(const uint8_t* code) noexcept -{ - for (int i = 0; i < 8; ++i) - { - if (is_push(code[i])) - return i; - } - return -1; -} - -inline int find_first_push_opt1(const uint8_t* code) noexcept -{ - uint64_t b; - __builtin_memcpy(&b, code, sizeof(b)); - b = __builtin_bswap64(b); - - const auto d = (~b) & (b << 1) & (b << 2) & 0x8080808080808080; - - if (d == 0) - return -1; - - auto z = __builtin_clzll(d); - auto z2 = z / 8; - return z2; -} - -inline int find_first_push_opt2(const uint8_t* code) noexcept -{ - uint64_t b; - __builtin_memcpy(&b, code, sizeof(b)); - b = __builtin_bswap64(b); - uint64_t mask = 0x8080808080808080; - - auto e2 = b << 2; - auto f2 = b << 1; - auto g2 = ~b; - auto d1 = e2 & f2 & g2 & mask; - - if (d1 == 0) - return -1; - - auto z = __builtin_clzll(d1); - auto z2 = z / 8; - return z2; -} - -inline int find_first_push_opt3(const uint8_t* code) noexcept -{ - uint64_t b; - __builtin_memcpy(&b, code, sizeof(b)); - - const auto d = (b >> 5) & (b >> 6) & (~b >> 7) & 0x0101010101010101; - - if (d == 0) - return -1; - - auto z = __builtin_ctzll(d); - auto z2 = z / 8; - return z2; -} -} // namespace evmone::exp diff --git a/test/internal_benchmarks/analysis_bench.cpp b/test/internal_benchmarks/analysis_bench.cpp index fd1f6e693b..e260df5f7e 100644 --- a/test/internal_benchmarks/analysis_bench.cpp +++ b/test/internal_benchmarks/analysis_bench.cpp @@ -14,6 +14,7 @@ #include using namespace evmone::test; +using namespace evmone::exp::jda; namespace