-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adding a doc to describe pp upgrade test procedure
- Loading branch information
1 parent
fc470ed
commit bdaf5d1
Showing
5 changed files
with
349 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,348 @@ | ||
* Initial Setup | ||
|
||
In order to test the rollup manager upgrade to pessimistic, first | ||
deploy a full stack with fork 12. | ||
|
||
#+begin_src bash | ||
kurtosis run --enclave cdk . | ||
#+end_src | ||
|
||
This will setup a rollup based on erigon. Once that's done, we'll | ||
setup a second CDK using legacy stack in the same enclave. Save this | ||
content in a file named ~second.network.yml~ | ||
|
||
#+begin_src yaml | ||
deployment_stages: | ||
deploy_l1: false | ||
deploy_agglayer: false | ||
deploy_cdk_erigon_node: false | ||
|
||
args: | ||
deployment_suffix: "-002" | ||
zkevm_rollup_chain_id: 20202 | ||
zkevm_rollup_id: 2 | ||
|
||
zkevm_l2_sequencer_address: "0xA670342930242407b9984e467353044f8472055e" | ||
zkevm_l2_sequencer_private_key: "0x902ed4ce26b536617a4f26da5e0cd0ef61b514a076b4bd766d6ab8b97efbb8c1" | ||
zkevm_l2_aggregator_address: "0xfC419a9d9Fe0DfA4Cf9971AcD1Fbcd356DD768FD" | ||
zkevm_l2_aggregator_private_key: "0xa70db9fb4b84a6ba18c03cd2266116dd110538d6c4c88e67ca35a29b910da25d" | ||
zkevm_l2_claimtxmanager_address: "0x93F63c24735f45Cd0266E87353071B64dd86bc05" | ||
zkevm_l2_claimtxmanager_private_key: "0x38718f22097afba13be48d818964326c9c5c48133f51e3c3bfd6faf05f813b34" | ||
zkevm_l2_timelock_address: "0xDB22C6f61A82d6AA6d3607289fC93774AC09413a" | ||
zkevm_l2_timelock_private_key: "0xae4a69010583a09709baa563fa66f9e6f2dacf9e9c84b89932406b9a0521b561" | ||
zkevm_l2_loadtest_address: "0xD5278fC3Dc72A226d5C04c3d2C85fd397A46fA08" | ||
zkevm_l2_loadtest_private_key: "0xef4db4f97684b8307adc332ed6c1bc82d66d160f08e7427d082d66a23889625e" | ||
zkevm_l2_dac_address: "0xDa07AAD7226B136bc24157Dc4Ff5A813490E20D0" | ||
zkevm_l2_dac_private_key: "0x992c9ab11d5eab6b6c2634b8bb0b85f3d8d1acf25024dc99c359cb2afd9b40a7" | ||
zkevm_l2_proofsigner_address: "0xf1a661D7b601Ec46a040f57193cC99aB8c4132FA" | ||
zkevm_l2_proofsigner_private_key: "0xc7fe3a006d75ba9326d9792523385abb49057c66aee0b8b4248821a89713f975" | ||
|
||
zkevm_contracts_image: leovct/zkevm-contracts:v6.0.0-rc.1-fork.9 | ||
zkevm_prover_image: hermeznetwork/zkevm-prover:v6.0.8 | ||
cdk_erigon_node_image: hermeznetwork/cdk-erigon:v2.1.2 | ||
zkevm_node_image: hermeznetwork/zkevm-node:v0.7.3 | ||
cdk_validium_node_image: 0xpolygon/cdk-validium-node:0.7.0-cdk | ||
zkevm_da_image: 0xpolygon/cdk-data-availability:0.0.10 | ||
zkevm_bridge_service_image: hermeznetwork/zkevm-bridge-service:v0.6.0-RC1 | ||
deploy_l2_contracts: true | ||
consensus_contract_type: cdk-validium | ||
sequencer_type: zkevm | ||
|
||
#+end_src | ||
|
||
Now we can run the deployment of the second network with this command | ||
|
||
#+begin_src bash | ||
kurtosis run --enclave cdk --args-file second.network.yml . | ||
#+end_src | ||
|
||
|
||
At this point, we should have two rollups attached to the same rollup | ||
manager. By default only one of them will be able to send proofs to | ||
the agglayer, we'll need to update the config. | ||
|
||
#+begin_src bash | ||
kurtosis service shell cdk agglayer | ||
sed -i 's/\(\[proof-signers\]\)/2 = "http:\/\/zkevm-node-rpc-002:8123"\n\n\1/' /etc/zkevm/agglayer-config.toml | ||
exit | ||
kurtosis service stop cdk agglayer | ||
kurtosis service start cdk agglayer | ||
#+end_src | ||
|
||
Let's confirm they're both working properly separately. | ||
|
||
#+begin_src bash | ||
# let's confirm that we're seeing verified batches in the new f12 node | ||
polycli monitor --rpc-url $(kurtosis port print cdk cdk-erigon-rpc-001 rpc) | ||
|
||
# let's also confirm that we're seeing verified batches in the legacy node | ||
polycli monitor --rpc-url $(kurtosis port print cdk zkevm-node-rpc-002 rpc) | ||
#+end_src | ||
|
||
[[/home/john/code/kurtosis-cdk/docs/upgrade-pp/README.org_20241107_183354_RUgJa3.png]] | ||
|
||
* Rollup Manager Upgrade | ||
|
||
Now, we need to grab the full ~combined.json~ file for reference | ||
in other commands: | ||
|
||
#+begin_src bash | ||
kurtosis service exec cdk contracts-001 "cat /opt/zkevm/combined.json" | ||
#+end_src | ||
|
||
#+begin_src javascript | ||
{ | ||
"polygonRollupManagerAddress": "0x2F50ef6b8e8Ee4E579B17619A92dE3E2ffbD8AD2", | ||
"polygonZkEVMBridgeAddress": "0xD71f8F956AD979Cc2988381B8A743a2fE280537D", | ||
"polygonZkEVMGlobalExitRootAddress": "0x1f7ad7caA53e35b4f0D138dC5CBF91aC108a2674", | ||
"polTokenAddress": "0xEdE9cf798E0fE25D35469493f43E88FeA4a5da0E", | ||
"zkEVMDeployerContract": "0xe5CF69183CFCF0571E733D59a1a53d4E6ceD6E85", | ||
"deployerAddress": "0xE34aaF64b29273B7D567FCFc40544c014EEe9970", | ||
"timelockContractAddress": "0x07783C37CAAFe0f05C4105250C032062A83F7AC2", | ||
"deploymentRollupManagerBlockNumber": 62, | ||
"upgradeToULxLyBlockNumber": 62, | ||
"admin": "0xE34aaF64b29273B7D567FCFc40544c014EEe9970", | ||
"trustedAggregator": "0xCae5b68Ff783594bDe1b93cdE627c741722c4D4d", | ||
"proxyAdminAddress": "0xB93b2fD69CE28f0DB91842aBFa40720d7e2B8fd7", | ||
"salt": "0x0000000000000000000000000000000000000000000000000000000000000001", | ||
"polygonDataCommitteeAddress": "0xAC77A07dD1683DeA96c08F286b67783fB1e4B583", | ||
"firstBatchData": { | ||
"transactions": "0xf9010380808401c9c38094d71f8f956ad979cc2988381b8a743a2fe280537d80b8e4f811bff7000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a40d5f56745a118d0906a34e69aec8c0db1cb8fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005ca1ab1e0000000000000000000000000000000000000000000000000000000005ca1ab1e1bff", | ||
"globalExitRoot": "0xbdf2dfec6a652651e2e3aba0364c0f68d524583aa62a48fd1b03a43df2793952", | ||
"timestamp": 1731027895, | ||
"sequencer": "0xA670342930242407b9984e467353044f8472055e" | ||
}, | ||
"genesis": "0xf1d66e5ff5698e947c39a5e15f31f05de487e37b88ac1a2493ddc6f3911e28e0", | ||
"createRollupBlockNumber": 390, | ||
"rollupAddress": "0xcC626369bD1ff281b22B2dfA71ce0B4776A16568", | ||
"verifierAddress": "0x35B83D5C0fD081DA9133C590Ac9515D8BF917c03", | ||
"consensusContract": "PolygonValidiumEtrog", | ||
"polygonZkEVML2BridgeAddress": "0xD71f8F956AD979Cc2988381B8A743a2fE280537D", | ||
"polygonZkEVMGlobalExitRootL2Address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa", | ||
"bridgeGenBlockNumber": 390 | ||
} | ||
#+end_src | ||
|
||
Now we need to attempt the upgrade from the current rollup manager to | ||
the pessimistic edition. This could be run from your operating | ||
system, but I find it easier to run this directly from from the | ||
contracts container since it's already configured with the correct | ||
tooling. Because we're going to be in the shell for a bit, I prefer to | ||
use ~docker exec~ rather than ~kurtosis service shell~. | ||
|
||
#+begin_src bash | ||
# just type "contracts-001" then hit <TAB> to auto complete the UUID | ||
docker exec -it --user root contracts-001--54a495d290fb4b0caaab9dd36b8a1e69 /bin/bash | ||
#+end_src | ||
|
||
|
||
Now we should be in the shell for the contracts container. | ||
|
||
#+begin_src bash | ||
cd zkevm-contracts/ | ||
git stash # there are some local modifcations to set the localhost network | ||
git pull | ||
git checkout v9.0.0-rc.3-pp | ||
git stash apply | ||
rm -rf artifacts cache node_modules | ||
npm i | ||
|
||
# If your rollup manager address from the combined.json is different, replace it here. | ||
# The sk value is the admin private key | ||
cat upgrade/upgradePessimistic/upgrade_parameters.json.example | | ||
jq --arg rum 0x2F50ef6b8e8Ee4E579B17619A92dE3E2ffbD8AD2 \ | ||
--arg sk 0x12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ | ||
--arg tld 60 '.rollupManagerAddress = $rum | .timelockDelay = $tld | .deployerPvtKey = $sk' > upgrade/upgradePessimistic/upgrade_parameters.json | ||
|
||
|
||
npx hardhat run ./upgrade/upgradePessimistic/upgradePessimistic.ts --network localhost | ||
#+end_src | ||
|
||
Running this command will print some data that looks like this: | ||
|
||
#+begin_example | ||
[ | ||
'0x1f7ad7caA53e35b4f0D138dC5CBF91aC108a2674', | ||
'0xEdE9cf798E0fE25D35469493f43E88FeA4a5da0E', | ||
'0xD71f8F956AD979Cc2988381B8A743a2fE280537D' | ||
] | ||
{ | ||
scheduleData: '0x01d5062a000000000000000000000000b93b2fd69ce28f0db91842abfa40720d7e2b8fd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000a49623609d0000000000000000000000002f50ef6b8e8ee4e579b17619a92de3e2ffbd8ad2000000000000000000000000ac5a923eeb235710d2ba55c352992b8d62ef0859000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000048129fc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | ||
} | ||
{ | ||
executeData: '0x134008d3000000000000000000000000b93b2fd69ce28f0db91842abfa40720d7e2b8fd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a49623609d0000000000000000000000002f50ef6b8e8ee4e579b17619a92de3e2ffbd8ad2000000000000000000000000ac5a923eeb235710d2ba55c352992b8d62ef0859000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000048129fc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | ||
} | ||
#+end_example | ||
|
||
These is call data that needs to be sent to the timelock contract in | ||
two steps. First we schedule, then we execute. You can run this | ||
command from within the contracts container in order to schedule the | ||
upgrade. | ||
|
||
|
||
#+begin_src bash | ||
time_lock_address="0x07783C37CAAFe0f05C4105250C032062A83F7AC2" | ||
private_key="0x12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625" | ||
rpc_url="http://el-1-geth-lighthouse:8545" | ||
schedule_data="0x01d5062a000000000000000000000000b93b2fd69ce28f0db91842abfa40720d7e2b8fd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000a49623609d0000000000000000000000002f50ef6b8e8ee4e579b17619a92de3e2ffbd8ad2000000000000000000000000ac5a923eeb235710d2ba55c352992b8d62ef0859000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000048129fc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | ||
|
||
cast send --rpc-url "$rpc_url" --private-key "$private_key" "$time_lock_address" "$schedule_data" | ||
#+end_src | ||
|
||
|
||
Based on the timelock delay that we set, you'll need to wait sixty | ||
seconds. Then you can execute the transaction. This will actually | ||
upgrade the rollup manager. | ||
|
||
#+begin_src bash | ||
time_lock_address="0x07783C37CAAFe0f05C4105250C032062A83F7AC2" | ||
private_key="0x12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625" | ||
rpc_url="http://el-1-geth-lighthouse:8545" | ||
execute_data="0x134008d3000000000000000000000000b93b2fd69ce28f0db91842abfa40720d7e2b8fd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a49623609d0000000000000000000000002f50ef6b8e8ee4e579b17619a92de3e2ffbd8ad2000000000000000000000000ac5a923eeb235710d2ba55c352992b8d62ef0859000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000048129fc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | ||
|
||
cast send --rpc-url "$rpc_url" --private-key "$private_key" "$time_lock_address" "$execute_data" | ||
#+end_src | ||
|
||
In order to check that this actually worked, you can run this command | ||
from the contracts image as well: | ||
|
||
#+begin_src bash | ||
cast call --rpc-url "$rpc_url" 0x2F50ef6b8e8Ee4E579B17619A92dE3E2ffbD8AD2 'ROLLUP_MANAGER_VERSION()(string)' | ||
#+end_src | ||
|
||
If this returns ~"pessimistic"~ you're good and it worked. We can | ||
probably exit from the contracts image at this point. | ||
|
||
* Testing | ||
|
||
The simplest test we can do is first to use polycli monitor to make | ||
sure that batches are still being verified. In both cases, I would | ||
send some transactions and make sure that both the virtual and | ||
verified batch numbers are increasing. | ||
|
||
#+begin_src bash | ||
polycli monitor --rpc-url $(kurtosis port print cdk cdk-erigon-rpc-001 rpc) | ||
polycli monitor --rpc-url $(kurtosis port print cdk zkevm-node-rpc-002 rpc) | ||
#+end_src | ||
|
||
When you open polycli, make note of the trusted batch number. And wait | ||
for that batch number to get verified. That would mean the full | ||
process has worked. Generally, we should also make sure that none of | ||
the containers have stopped. There are going to be a lot of containers | ||
because we're running two separate devnets at this point. | ||
|
||
[[/home/john/code/kurtosis-cdk/docs/upgrade-pp/README.org_20241107_174356_V3QbFI.png]] | ||
|
||
Okay, to wrap this up, let's try to attach one more rollup that's | ||
using pessimsitic consensus. We'll create a new params file that | ||
setups a new third network with PP consensus. We'll save it in a file | ||
called ~third.network.yml~. | ||
|
||
|
||
#+begin_src yaml | ||
deployment_stages: | ||
deploy_l1: false | ||
deploy_agglayer: false | ||
|
||
args: | ||
deployment_suffix: "-003" | ||
zkevm_rollup_chain_id: 30303 | ||
zkevm_rollup_id: 3 | ||
|
||
# polycli wallet inspect --mnemonic 'holiday crunch rule artefact cinnamon suit uphold evil shrimp topic core abstract' --addresses 11 | tee keys.txt | jq -r '.Addresses[] | [.ETHAddress, .HexPrivateKey] | @tsv' | awk 'BEGIN{split("sequencer,aggregator,claimtxmanager,timelock,admin,loadtest,agglayer,dac,proofsigner,l1testing,claimsponsor",roles,",")} {print "# " roles[NR] "\nzkevm_l2_" roles[NR] "_address: " $1 ""; print "zkevm_l2_" roles[NR] "_private_key: 0x" $2 "\n"}' | ||
|
||
# sequencer | ||
zkevm_l2_sequencer_address: 0x0d59BC8C02A089D48d9Cd465b74Cb6E23dEB950D | ||
zkevm_l2_sequencer_private_key: 0xf6385a27e7710349617340c6f9310e88f0aad10d01646a9bb204177431babcd8 | ||
|
||
# aggregator | ||
zkevm_l2_aggregator_address: 0x2D20D9081fb403E856355F2cddd1C4863D0109cb | ||
zkevm_l2_aggregator_private_key: 0x2cb77c2cca48d3fee64c14d73564fd6e90676a4f6da6545681e10c8b9b22fce2 | ||
|
||
# claimtxmanager | ||
zkevm_l2_claimtxmanager_address: 0x1359D1eAf25aADaA04304Ee7EFC5b94C43e0e1D5 | ||
zkevm_l2_claimtxmanager_private_key: 0xb0244fcbf83d7aaa2d51dc78a55233058af31797a974d25f724de041f3484418 | ||
|
||
# timelock | ||
zkevm_l2_timelock_address: 0x7803E33388C695E7cbd85eD55f4abe6455E9ce2e | ||
zkevm_l2_timelock_private_key: 0xe12e739b58489a2c2f49c472169ba20eb89d039e71f04d5342ab645dc3fb6540 | ||
|
||
# admin | ||
# zkevm_l2_admin_address: 0x5666Cc6B46ad32b469D9Aec7C1eE6d02f7312759 | ||
# zkevm_l2_admin_private_key: 0xd2ee309113fc97bed6030201fea0d1234d6b4acbc47b9a4fe12a8fa5270052aa | ||
|
||
# loadtest | ||
zkevm_l2_loadtest_address: 0x5198d92d278Fd36e5745C308F728d256198A0e3d | ||
zkevm_l2_loadtest_private_key: 0xcc594c53eca19f9e56200cadf60c94757b0bdee1fc4bc73552ba879d51fd82b3 | ||
|
||
# agglayer | ||
zkevm_l2_agglayer_address: 0x9b5A1f2bC7bb48419d9f6407CFcA454F87884072 | ||
zkevm_l2_agglayer_private_key: 0x7b1164f53f633e940089031a3c265c308d2bcf4756bc8dcf9046bf00e21ec3b1 | ||
|
||
# dac | ||
zkevm_l2_dac_address: 0xA9875E9B9FE3BD46da758ba69a5d4B9dFCA6F133 | ||
zkevm_l2_dac_private_key: 0x5d1a923f60e2423932f782dab9510e1c2fd64b0f29b0893978864191ecdd6f4f | ||
|
||
# proofsigner | ||
zkevm_l2_proofsigner_address: 0x3AA075513578d86dC63f9344cD9489b948d7686a | ||
zkevm_l2_proofsigner_private_key: 0xfd402dcc8c7fc7ce0df59fe12f33da7ac2ed760a619188ff16974fde16f9b00e | ||
|
||
# l1testing | ||
zkevm_l2_l1testing_address: 0x943413d3b2E1B6aF09a758c35b6F5d23a4d6d262 | ||
zkevm_l2_l1testing_private_key: 0x27d8ab2d65296d0da072b172ca9ca874583f9930adb6ac3222fd9494ae7c7f0d | ||
|
||
# claimsponsor | ||
zkevm_l2_claimsponsor_address: 0xeA06890A8A547aDd71f98A6845542eb3B63C2862 | ||
zkevm_l2_claimsponsor_private_key: 0xb97112e36cfcde131faa110430eed6593b75406e5d6991d8db3ed0f492a73b6f | ||
|
||
agglayer_image: ghcr.io/agglayer/agglayer:0.2.0-rc.5 | ||
cdk_erigon_node_image: hermeznetwork/cdk-erigon:v2.60.0-beta4 | ||
cdk_node_image: nulyjkdhthz/cdk:6d775da5dad55990f534e0190a89613ae64f5ccf | ||
zkevm_bridge_proxy_image: haproxy:3.0-bookworm | ||
zkevm_bridge_service_image: hermeznetwork/zkevm-bridge-service:v0.6.0-RC1 | ||
zkevm_contracts_image: nulyjkdhthz/zkevm-contracts:v9.0.0-rc.3-pp-fork.12 | ||
additional_services: [] | ||
consensus_contract_type: pessimistic | ||
sequencer_type: erigon | ||
erigon_strict_mode: false | ||
zkevm_use_gas_token_contract: false | ||
enable_normalcy: true | ||
#+end_src | ||
|
||
Okay let's try to fire up the third network: | ||
#+begin_src bash | ||
kurtosis run --enclave cdk --args-file third.network.yml . | ||
#+end_src | ||
|
||
Just like when we added the other rollup, we also need to make sure | ||
the agglayer is updated to have the information for the new rollup. | ||
|
||
#+begin_src bash | ||
kurtosis service shell cdk agglayer | ||
sed -i 's/\(\[proof-signers\]\)/3 = "http:\/\/cdk-erigon-rpc-003:8123"\n\n\1/' /etc/zkevm/agglayer-config.toml | ||
exit | ||
kurtosis service stop cdk agglayer | ||
kurtosis service start cdk agglayer | ||
#+end_src | ||
|
||
Once that's deployed we should make sure that the network is running | ||
as expected. | ||
|
||
#+begin_src bash | ||
polycli monitor --rpc-url $(kurtosis port print cdk cdk-erigon-rpc-001 rpc) | ||
polycli monitor --rpc-url $(kurtosis port print cdk zkevm-node-rpc-002 rpc) | ||
polycli monitor --rpc-url $(kurtosis port print cdk cdk-erigon-rpc-003 rpc) | ||
#+end_src | ||
|
||
|
||
[[/home/john/code/kurtosis-cdk/docs/upgrade-pp/README.org_20241107_202120_6X33db.png]] | ||
|
||
|
||
* Future Test Cases | ||
|
||
- Bridge from L1 to each of the L2 | ||
- Bridge from each L2 to L1 | ||
- Bridge from each L2 to each other L2 | ||
- Attempt a rollback with bridges in the unverified state | ||
|
||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters