diff --git a/schemas/database/004_identities.up.sql b/schemas/database/004_identities.up.sql new file mode 100644 index 00000000..ef302c7f --- /dev/null +++ b/schemas/database/004_identities.up.sql @@ -0,0 +1,17 @@ +-- Add the new 'id' column +ALTER TABLE identities ADD COLUMN id BIGSERIAL; + +-- Set the new 'id' column as NOT NULL +ALTER TABLE identities ALTER COLUMN id SET NOT NULL; + +-- Drop the unique commitment constraint to allow for 0x00 to be inserted for deletions +ALTER TABLE identities DROP CONSTRAINT identities_commitment_key; + +-- Set the id to be unique +ALTER TABLE identities ADD CONSTRAINT id_unique UNIQUE(id); + +-- Drop the existing primary key +ALTER TABLE identities DROP CONSTRAINT identities_pkey; + +-- Set the new 'id' column as the primary key +ALTER TABLE identities ADD PRIMARY KEY (id); \ No newline at end of file diff --git a/schemas/database/005_add_eligibility_timestamp.sql b/schemas/database/005_add_eligibility_timestamp.sql new file mode 100644 index 00000000..7473fe86 --- /dev/null +++ b/schemas/database/005_add_eligibility_timestamp.sql @@ -0,0 +1 @@ +ALTER TABLE unprocessed_identities ADD COLUMN eligibility TIMESTAMPTZ; diff --git a/schemas/database/006_deletions.sql b/schemas/database/006_deletions.sql new file mode 100644 index 00000000..c5ec8ef6 --- /dev/null +++ b/schemas/database/006_deletions.sql @@ -0,0 +1,4 @@ +CREATE TABLE deletions ( + leaf_index BIGINT NOT NULL PRIMARY KEY, + commitment BYTEA NOT NULL UNIQUE +) \ No newline at end of file diff --git a/schemas/database/007_recoveries.sql b/schemas/database/007_recoveries.sql new file mode 100644 index 00000000..bc731507 --- /dev/null +++ b/schemas/database/007_recoveries.sql @@ -0,0 +1,4 @@ +CREATE TABLE recoveries ( + existing_commitment BYTEA NOT NULL UNIQUE, + new_commitment BYTEA NOT NULL UNIQUE +) diff --git a/schemas/database/008_prover_type.sql b/schemas/database/008_prover_type.sql new file mode 100644 index 00000000..eacc11df --- /dev/null +++ b/schemas/database/008_prover_type.sql @@ -0,0 +1,17 @@ +-- Create ENUM for prover type +CREATE TYPE prover_enum AS ENUM('Insertion', 'Deletion'); + +-- Add new column with the enum +ALTER TABLE provers ADD COLUMN prover_type prover_enum; + +-- Update the new column, setting all existing provers as insertions +UPDATE provers SET prover_type = 'Insertion' WHERE prover_type IS NULL; + +-- Make the column NOT NULL +ALTER TABLE provers ALTER COLUMN prover_type SET NOT NULL; + +-- Drop batch size as the primary key +ALTER TABLE provers DROP CONSTRAINT provers_pkey; + +-- Drop the url uniqueness constraint +ALTER TABLE provers DROP CONSTRAINT IF EXISTS provers_url_key; \ No newline at end of file diff --git a/schemas/database/009_latest_deletion_root.sql b/schemas/database/009_latest_deletion_root.sql new file mode 100644 index 00000000..a3a1c146 --- /dev/null +++ b/schemas/database/009_latest_deletion_root.sql @@ -0,0 +1,6 @@ +CREATE TABLE latest_deletion_root ( + Lock char(1) NOT NULL DEFAULT 'X', + deletion_timestamp TIMESTAMPTZ, + constraint PK_T1 PRIMARY KEY (Lock), + constraint CK_T1_Locked CHECK (Lock='X') +) \ No newline at end of file diff --git a/sol/SimpleStateBridge.json b/sol/SimpleStateBridge.json deleted file mode 100644 index c52090c4..00000000 --- a/sol/SimpleStateBridge.json +++ /dev/null @@ -1,414 +0,0 @@ -{ - "abi": [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "root", - "type": "uint256" - } - ], - "name": "StateRootSentMultichain", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "root", - "type": "uint256" - } - ], - "name": "sendRootMultichain", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": { - "object": "0x608060405234801561001057600080fd5b5060ba8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063393170cf14602d575b600080fd5b603c6038366004606c565b603e565b005b60405181907f118a5978e509351fb120eb558e2dc9bd6db3cf57cf66ec9744ef8acabf3b0aec90600090a250565b600060208284031215607d57600080fd5b503591905056fea264697066735822122009366b28a1bae882fe05cdba91a291fdd9387e34205b1448e93122db6c68797264736f6c63430008130033", - "sourceMap": "337:223:57:-:0;;;;;;;;;;;;;;;;;;;", - "linkReferences": {} - }, - "deployedBytecode": { - "object": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063393170cf14602d575b600080fd5b603c6038366004606c565b603e565b005b60405181907f118a5978e509351fb120eb558e2dc9bd6db3cf57cf66ec9744ef8acabf3b0aec90600090a250565b600060208284031215607d57600080fd5b503591905056fea264697066735822122009366b28a1bae882fe05cdba91a291fdd9387e34205b1448e93122db6c68797264736f6c63430008130033", - "sourceMap": "337:223:57:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;439:119;;;;;;:::i;:::-;;:::i;:::-;;;522:29;;546:4;;522:29;;;;;439:119;:::o;14:180:78:-;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;-1:-1:-1;165:23:78;;14:180;-1:-1:-1;14:180:78:o", - "linkReferences": {} - }, - "methodIdentifiers": { - "sendRootMultichain(uint256)": "393170cf" - }, - "rawMetadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"}],\"name\":\"StateRootSentMultichain\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"}],\"name\":\"sendRootMultichain\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Worldcoin\",\"kind\":\"dev\",\"methods\":{\"sendRootMultichain(uint256)\":{\"details\":\"Calls this method on the L1 Proxy contract to relay the latest root to all supported networks\",\"params\":{\"root\":\"The latest Semaphore root.\"}}},\"title\":\"State Bridge Mock\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"sendRootMultichain(uint256)\":{\"notice\":\"Sends the latest Semaphore root to Optimism.\"}},\"notice\":\"This purely exists to allow tests to compile and does not have any functionality.A dumb bridge to make it easy to fuzz test successes and failures.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/test/mock/SimpleStateBridge.sol\":\"SimpleStateBridge\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@zk-kit/=lib/zk-kit/packages/\",\":contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":ds-test/=lib/ds-test/src/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\",\":semaphore/=lib/semaphore/packages/contracts/contracts/\",\":solmate/=lib/solmate/src/\",\":zk-kit/=lib/zk-kit/\"]},\"sources\":{\"src/interfaces/IBridge.sol\":{\"keccak256\":\"0xaa64f67fb28b78d9c270cdbebe00f19611e0eadb67c4287172c805cc2380d8d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b79e327de5168c65e7d55009533f5d5c2b4262c4c0c86dccd8f8f495e5a7c37d\",\"dweb:/ipfs/QmYCeKYuT84QjdFaVh4vuJYV9aCjB9KyLvcpc73mzc3qXH\"]},\"src/test/mock/SimpleStateBridge.sol\":{\"keccak256\":\"0x70606221ef1952ff696af15db7881b0005b7c10b4934cc4b4f4f61a035792825\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0b451b400c0cb68338d9a09a800f8e259718f19e207a69e159f7117d3a551a10\",\"dweb:/ipfs/QmSgZWVfbnNttEzw8JSbLM2id8uacy7mztwP9EmD59BboC\"]}},\"version\":1}", - "metadata": { - "compiler": { - "version": "0.8.19+commit.7dd6d404" - }, - "language": "Solidity", - "output": { - "abi": [ - { - "inputs": [ - { - "internalType": "uint256", - "name": "root", - "type": "uint256", - "indexed": true - } - ], - "type": "event", - "name": "StateRootSentMultichain", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "root", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "sendRootMultichain" - } - ], - "devdoc": { - "kind": "dev", - "methods": { - "sendRootMultichain(uint256)": { - "details": "Calls this method on the L1 Proxy contract to relay the latest root to all supported networks", - "params": { - "root": "The latest Semaphore root." - } - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": { - "sendRootMultichain(uint256)": { - "notice": "Sends the latest Semaphore root to Optimism." - } - }, - "version": 1 - } - }, - "settings": { - "remappings": [ - ":@zk-kit/=lib/zk-kit/packages/", - ":contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", - ":ds-test/=lib/ds-test/src/", - ":forge-std/=lib/forge-std/src/", - ":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", - ":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", - ":semaphore/=lib/semaphore/packages/contracts/contracts/", - ":solmate/=lib/solmate/src/", - ":zk-kit/=lib/zk-kit/" - ], - "optimizer": { - "enabled": true, - "runs": 200 - }, - "metadata": { - "bytecodeHash": "ipfs" - }, - "compilationTarget": { - "src/test/mock/SimpleStateBridge.sol": "SimpleStateBridge" - }, - "libraries": {} - }, - "sources": { - "src/interfaces/IBridge.sol": { - "keccak256": "0xaa64f67fb28b78d9c270cdbebe00f19611e0eadb67c4287172c805cc2380d8d6", - "urls": [ - "bzz-raw://b79e327de5168c65e7d55009533f5d5c2b4262c4c0c86dccd8f8f495e5a7c37d", - "dweb:/ipfs/QmYCeKYuT84QjdFaVh4vuJYV9aCjB9KyLvcpc73mzc3qXH" - ], - "license": "MIT" - }, - "src/test/mock/SimpleStateBridge.sol": { - "keccak256": "0x70606221ef1952ff696af15db7881b0005b7c10b4934cc4b4f4f61a035792825", - "urls": [ - "bzz-raw://0b451b400c0cb68338d9a09a800f8e259718f19e207a69e159f7117d3a551a10", - "dweb:/ipfs/QmSgZWVfbnNttEzw8JSbLM2id8uacy7mztwP9EmD59BboC" - ], - "license": "MIT" - } - }, - "version": 1 - }, - "ast": { - "absolutePath": "src/test/mock/SimpleStateBridge.sol", - "id": 35680, - "exportedSymbols": { - "IBridge": [ - 26700 - ], - "SimpleStateBridge": [ - 35679 - ] - }, - "nodeType": "SourceUnit", - "src": "32:529:57", - "nodes": [ - { - "id": 35658, - "nodeType": "PragmaDirective", - "src": "32:24:57", - "nodes": [], - "literals": [ - "solidity", - "^", - "0.8", - ".19" - ] - }, - { - "id": 35660, - "nodeType": "ImportDirective", - "src": "58:53:57", - "nodes": [], - "absolutePath": "src/interfaces/IBridge.sol", - "file": "../../interfaces/IBridge.sol", - "nameLocation": "-1:-1:-1", - "scope": 35680, - "sourceUnit": 26701, - "symbolAliases": [ - { - "foreign": { - "id": 35659, - "name": "IBridge", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 26700, - "src": "66:7:57", - "typeDescriptions": {} - }, - "nameLocation": "-1:-1:-1" - } - ], - "unitAlias": "" - }, - { - "id": 35679, - "nodeType": "ContractDefinition", - "src": "337:223:57", - "nodes": [ - { - "id": 35667, - "nodeType": "EventDefinition", - "src": "381:52:57", - "nodes": [], - "anonymous": false, - "eventSelector": "118a5978e509351fb120eb558e2dc9bd6db3cf57cf66ec9744ef8acabf3b0aec", - "name": "StateRootSentMultichain", - "nameLocation": "387:23:57", - "parameters": { - "id": 35666, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 35665, - "indexed": true, - "mutability": "mutable", - "name": "root", - "nameLocation": "427:4:57", - "nodeType": "VariableDeclaration", - "scope": 35667, - "src": "411:20:57", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 35664, - "name": "uint256", - "nodeType": "ElementaryTypeName", - "src": "411:7:57", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "visibility": "internal" - } - ], - "src": "410:22:57" - } - }, - { - "id": 35678, - "nodeType": "FunctionDefinition", - "src": "439:119:57", - "nodes": [], - "body": { - "id": 35677, - "nodeType": "Block", - "src": "507:51:57", - "nodes": [], - "statements": [ - { - "eventCall": { - "arguments": [ - { - "id": 35674, - "name": "root", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 35669, - "src": "546:4:57", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 35673, - "name": "StateRootSentMultichain", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 35667, - "src": "522:23:57", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_uint256_$returns$__$", - "typeString": "function (uint256)" - } - }, - "id": 35675, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "nameLocations": [], - "names": [], - "nodeType": "FunctionCall", - "src": "522:29:57", - "tryCall": false, - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 35676, - "nodeType": "EmitStatement", - "src": "517:34:57" - } - ] - }, - "baseFunctions": [ - 26699 - ], - "functionSelector": "393170cf", - "implemented": true, - "kind": "function", - "modifiers": [], - "name": "sendRootMultichain", - "nameLocation": "448:18:57", - "overrides": { - "id": 35671, - "nodeType": "OverrideSpecifier", - "overrides": [], - "src": "498:8:57" - }, - "parameters": { - "id": 35670, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 35669, - "mutability": "mutable", - "name": "root", - "nameLocation": "475:4:57", - "nodeType": "VariableDeclaration", - "scope": 35678, - "src": "467:12:57", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 35668, - "name": "uint256", - "nodeType": "ElementaryTypeName", - "src": "467:7:57", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "visibility": "internal" - } - ], - "src": "466:14:57" - }, - "returnParameters": { - "id": 35672, - "nodeType": "ParameterList", - "parameters": [], - "src": "507:0:57" - }, - "scope": 35679, - "stateMutability": "nonpayable", - "virtual": true, - "visibility": "external" - } - ], - "abstract": false, - "baseContracts": [ - { - "baseName": { - "id": 35662, - "name": "IBridge", - "nameLocations": [ - "367:7:57" - ], - "nodeType": "IdentifierPath", - "referencedDeclaration": 26700, - "src": "367:7:57" - }, - "id": 35663, - "nodeType": "InheritanceSpecifier", - "src": "367:7:57" - } - ], - "canonicalName": "SimpleStateBridge", - "contractDependencies": [], - "contractKind": "contract", - "documentation": { - "id": 35661, - "nodeType": "StructuredDocumentation", - "src": "113:224:57", - "text": "@title State Bridge Mock\n @notice This purely exists to allow tests to compile and does not have any functionality.\n @author Worldcoin\n @notice A dumb bridge to make it easy to fuzz test successes and failures." - }, - "fullyImplemented": true, - "linearizedBaseContracts": [ - 35679, - 26700 - ], - "name": "SimpleStateBridge", - "nameLocation": "346:17:57", - "scope": 35680, - "usedErrors": [] - } - ], - "license": "MIT" - }, - "id": 57 -} \ No newline at end of file diff --git a/sol/WorldIDIdentityManagerImplV2.json b/sol/WorldIDIdentityManagerImplV2.json new file mode 100644 index 00000000..e8eaf181 --- /dev/null +++ b/sol/WorldIDIdentityManagerImplV2.json @@ -0,0 +1,6052 @@ +{ + "abi": [ + { + "inputs": [], + "name": "CannotRenounceOwnership", + "type": "error" + }, + { + "inputs": [], + "name": "ExpiredRoot", + "type": "error" + }, + { + "inputs": [], + "name": "ImplementationNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "InvalidCommitment", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidStateBridgeAddress", + "type": "error" + }, + { + "inputs": [], + "name": "MismatchedInputLengths", + "type": "error" + }, + { + "inputs": [], + "name": "NonExistentRoot", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "providedRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "latestRoot", + "type": "uint256" + } + ], + "name": "NotLatestRoot", + "type": "error" + }, + { + "inputs": [], + "name": "ProofValidationFailure", + "type": "error" + }, + { + "inputs": [], + "name": "StateBridgeAlreadyDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "StateBridgeAlreadyEnabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum WorldIDIdentityManagerImplV1.UnreducedElementType", + "name": "elementType", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "element", + "type": "uint256" + } + ], + "name": "UnreducedElement", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "depth", + "type": "uint8" + } + ], + "name": "UnsupportedTreeDepth", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "enum WorldIDIdentityManagerImplV1.Dependency", + "name": "kind", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "address", + "name": "oldAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddress", + "type": "address" + } + ], + "name": "DependencyUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldOperator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "IdentityOperatorChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "oldExpiryTime", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "newExpiryTime", + "type": "uint256" + } + ], + "name": "RootHistoryExpirySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + } + ], + "name": "StateBridgeStateChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "enum WorldIDIdentityManagerImplV1.TreeChange", + "name": "kind", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "name": "TreeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "_treeDepth", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "initialRoot", + "type": "uint256" + } + ], + "name": "WorldIDIdentityManagerImplInitialized", + "type": "event" + }, + { + "inputs": [], + "name": "NO_SUCH_ROOT", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "supersededTimestamp", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "internalType": "struct WorldIDIdentityManagerImplV1.RootInfo", + "name": "rootInfo", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "packedDeletionIndices", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "batchSize", + "type": "uint32" + } + ], + "name": "calculateIdentityDeletionInputHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "startIndex", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "identityCommitments", + "type": "uint256[]" + } + ], + "name": "calculateIdentityRegistrationInputHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "leafIndices", + "type": "uint32[]" + }, + { + "internalType": "uint256[]", + "name": "oldIdentities", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "newIdentities", + "type": "uint256[]" + } + ], + "name": "calculateIdentityUpdateInputHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[8]", + "name": "deletionProof", + "type": "uint256[8]" + }, + { + "internalType": "uint32", + "name": "batchSize", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "packedDeletionIndices", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "name": "deleteIdentities", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getDeleteIdentitiesVerifierLookupTableAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getIdentityUpdateVerifierLookupTableAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRegisterIdentitiesVerifierLookupTableAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRootHistoryExpiry", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getSemaphoreVerifierAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTreeDepth", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "identityOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_treeDepth", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "initialRoot", + "type": "uint256" + }, + { + "internalType": "contract VerifierLookupTable", + "name": "_batchInsertionVerifiers", + "type": "address" + }, + { + "internalType": "contract VerifierLookupTable", + "name": "_batchUpdateVerifiers", + "type": "address" + }, + { + "internalType": "contract ISemaphoreVerifier", + "name": "_semaphoreVerifier", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "_batchUpdateVerifiers", + "type": "address" + } + ], + "name": "initializeV2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "latestRoot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + } + ], + "name": "queryRoot", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "supersededTimestamp", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "internalType": "struct WorldIDIdentityManagerImplV1.RootInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[8]", + "name": "insertionProof", + "type": "uint256[8]" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "startIndex", + "type": "uint32" + }, + { + "internalType": "uint256[]", + "name": "identityCommitments", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "name": "registerIdentities", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + } + ], + "name": "requireValidRoot", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "newTable", + "type": "address" + } + ], + "name": "setDeleteIdentitiesVerifierLookupTable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newIdentityOperator", + "type": "address" + } + ], + "name": "setIdentityOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "newTable", + "type": "address" + } + ], + "name": "setIdentityUpdateVerifierLookupTable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "newTable", + "type": "address" + } + ], + "name": "setRegisterIdentitiesVerifierLookupTable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newExpiryTime", + "type": "uint256" + } + ], + "name": "setRootHistoryExpiry", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ISemaphoreVerifier", + "name": "newVerifier", + "type": "address" + } + ], + "name": "setSemaphoreVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[8]", + "name": "updateProof", + "type": "uint256[8]" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "leafIndices", + "type": "uint32[]" + }, + { + "internalType": "uint256[]", + "name": "oldIdentities", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "newIdentities", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "name": "updateIdentities", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signalHash", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nullifierHash", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "externalNullifierHash", + "type": "uint256" + }, + { + "internalType": "uint256[8]", + "name": "proof", + "type": "uint256[8]" + } + ], + "name": "verifyProof", + "outputs": [], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000e8565b600054610100900460ff1615620000935760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e6576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b608051613e706200027e6000396000818161064e0152818161069701528181610775015281816107b501528181610b8d01528181610bcd0152818161100401528181611044015281816110fb0152818161113b015281816111e701528181611227015281816113270152818161136701528181611577015281816115b701528181611669015281816116a9015281816117ff0152818161183f015281816118ca0152818161190a01528181611985015281816119c501528181611a5c01528181611b0c01528181611b4c01528181611c9b01528181611cdb01528181611da701528181611de701528181611eaa01528181611eea01528181611f8101528181611fc1015281816120570152818161209701528181612177015281816121b70152818161226c015281816122ac0152818161248d015281816124cd015281816125e401528181612624015281816126b1015281816126f101528181612787015281816127c70152818161285b0152818161289b01528181612a8101528181612ac101528181612d3e0152612d7e0152613e706000f3fe6080604052600436106101f95760003560e01c8063715018a61161010d578063aa4a729e116100a0578063e30c39781161006f578063e30c3978146105bc578063f134b6ca146105da578063f2038f95146105ef578063f2358e1d14610604578063f2fde38b1461062457600080fd5b8063aa4a729e14610547578063b843b4e514610567578063c70aa72714610587578063d7b0fef1146105a757600080fd5b80638da5cb5b116100dc5780638da5cb5b146104cd5780638e5cdd50146104eb5780638fc22e9f14610512578063a7bba5821461052757600080fd5b8063715018a61461046357806379ba50971461047857806386ec599a1461048d5780638c76a909146104ad57600080fd5b806338c87065116101905780634f1ef2861161015f5780634f1ef286146103c25780634ffbdde5146103d557806352d1902d146103ea578063561f204b146103ff5780636b0566001461044357600080fd5b806338c87065146103135780633e8919b6146103335780633f7c178d1461036057806343f974cb146103ad57600080fd5b80632f059fca116101cc5780632f059fca1461028057806331e4e992146102a0578063354ca120146102d35780633659cfe6146102f357600080fd5b80630e3a12f3146101fe5780632217b2111461022057806323cfdba51461024057806329b6eca914610260575b600080fd5b34801561020a57600080fd5b5061021e610219366004613375565b610644565b005b34801561022c57600080fd5b5061021e61023b366004613404565b61076b565b34801561024c57600080fd5b5061021e61025b3660046134c3565b610b83565b34801561026c57600080fd5b5061021e61027b366004613375565b610f4c565b34801561028c57600080fd5b5061021e61029b366004613375565b610ffa565b3480156102ac57600080fd5b506102c06102bb36600461353c565b6110ef565b6040519081526020015b60405180910390f35b3480156102df57600080fd5b5061021e6102ee3660046135a3565b6111dd565b3480156102ff57600080fd5b5061021e61030e366004613375565b61131d565b34801561031f57600080fd5b5061021e61032e3660046135e2565b6113e5565b34801561033f57600080fd5b5061034861156b565b6040516001600160a01b0390911681526020016102ca565b34801561036c57600080fd5b5061038061037b366004613650565b611642565b60408051825181526020808401516001600160801b031690820152918101511515908201526060016102ca565b3480156103b957600080fd5b506102c06117f3565b61021e6103d03660046136ac565b6118c0565b3480156103e157600080fd5b50610348611979565b3480156103f657600080fd5b506102c0611a4f565b34801561040b57600080fd5b506040805160608082018352600080835260208084018290529284018190528351918201845280825291810182905291820152610380565b34801561044f57600080fd5b5061021e61045e366004613375565b611b02565b34801561046f57600080fd5b5061021e611bf7565b34801561048457600080fd5b5061021e611c18565b34801561049957600080fd5b506102c06104a8366004613758565b611c8f565b3480156104b957600080fd5b506102c06104c8366004613805565b611d9b565b3480156104d957600080fd5b506033546001600160a01b0316610348565b3480156104f757600080fd5b50610500611e9e565b60405160ff90911681526020016102ca565b34801561051e57600080fd5b50610348611f75565b34801561053357600080fd5b50610348610542366004613375565b61204b565b34801561055357600080fd5b5061021e610562366004613375565b61216d565b34801561057357600080fd5b5061021e61058236600461386d565b612262565b34801561059357600080fd5b5061021e6105a2366004613650565b612483565b3480156105b357600080fd5b506102c06125d8565b3480156105c857600080fd5b506065546001600160a01b0316610348565b3480156105e657600080fd5b506103486126a5565b3480156105fb57600080fd5b5061034861277b565b34801561061057600080fd5b5061021e61061f366004613650565b612851565b34801561063057600080fd5b5061021e61063f366004613375565b61298e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036106955760405162461bcd60e51b815260040161068c90613930565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166106c76129ff565b6001600160a01b0316146106ed5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661071057604051630103019560e11b815260040160405180910390fd5b610718612a1b565b61013380546001600160a01b038381166001600160a01b03198316811790935516908160045b6040517fd194b8423e9cb3c7cbebbbc3fe7f79dc2cbe0b40e03270d975abff491504c7b190600090a45050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036107b35760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166107e56129ff565b6001600160a01b03161461080b5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661082e57604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b0316331461085c5760405163472511eb60e11b815233600482015260240161068c565b61012e54851461088e5761012e5460405163542fced960e11b815261068c918791600401918252602082015260400190565b600061089d8587848787611d9b565b905060006108cb7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836139c8565b61013154604051638a283fc360e01b8152600481018790529192506000916001600160a01b0390911690638a283fc390602401602060405180830381865afa15801561091b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093f91906139ea565b9050806001600160a01b03166343753b4d60405180604001604052808c60006008811061096e5761096e613a07565b602002013581526020018c60016008811061098b5761098b613a07565b60200201359052604080516080810182528d820135918101918252908190606082018f60036020020135815250815260200160405180604001604052808f6004600881106109db576109db613a07565b602002013581526020018f6005600881106109f8576109f8613a07565b60200201359052905260408051808201909152808e6006602002013581526020018e600760088110610a2c57610a2c613a07565b60200201358152506040518060200160405280888152506040518563ffffffff1660e01b8152600401610a629493929190613a40565b6020604051808303816000875af1925050508015610a9d575060408051601f3d908101601f19168201909252610a9a91810190613ae7565b60015b610afd57610aa9613b09565b806308c379a003610ae25750610abd613b24565b80610ac85750610ae4565b8060405162461bcd60e51b815260040161068c9190613bd2565b505b604051631e716a8b60e01b815260040160405180910390fd5b80610b1b57604051631e716a8b60e01b815260040160405180910390fd5b61012e859055600089815261012f6020526040812080546001600160801b031916426001600160801b031617905585906040518b907f25f6d5cc356ee0b49cf708c13c68197947f5740a878a298765e4b18e4afdaf0490600090a4505b505050505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610bcb5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610bfd6129ff565b6001600160a01b031614610c235760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16610c4657604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b03163314610c745760405163472511eb60e11b815233600482015260240161068c565b61012e548214610ca65761012e5460405163542fced960e11b815261068c918491600401918252602082015260400190565b6000610cb5858585858a6110ef565b90506000610ce37f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836139c8565b61013554604051638a283fc360e01b815263ffffffff8a1660048201529192506000916001600160a01b0390911690638a283fc390602401602060405180830381865afa158015610d38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5c91906139ea565b9050806001600160a01b03166343753b4d60405180604001604052808c600060088110610d8b57610d8b613a07565b602002013581526020018c600160088110610da857610da8613a07565b60200201359052604080516080810182528d820135918101918252908190606082018f60036020020135815250815260200160405180604001604052808f600460088110610df857610df8613a07565b602002013581526020018f600560088110610e1557610e15613a07565b60200201359052905260408051808201909152808e6006602002013581526020018e600760088110610e4957610e49613a07565b60200201358152506040518060200160405280888152506040518563ffffffff1660e01b8152600401610e7f9493929190613a40565b6020604051808303816000875af1925050508015610eba575060408051601f3d908101601f19168201909252610eb791810190613ae7565b60015b610ec657610aa9613b09565b80610ee457604051631e716a8b60e01b815260040160405180910390fd5b61012e859055600086815261012f6020526040902080546001600160801b031916426001600160801b031617905584600160405188907f25f6d5cc356ee0b49cf708c13c68197947f5740a878a298765e4b18e4afdaf0490600090a450505050505050505050565b600054600290610100900460ff16158015610f6e575060005460ff8083169116105b610f8a5760405162461bcd60e51b815260040161068c90613c05565b6000805461013580546001600160a01b0319166001600160a01b03861617905561ff001961010060ff851661ffff19909316831717169091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036110425760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166110746129ff565b6001600160a01b03161461109a5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166110bd57604051630103019560e11b815260040160405180910390fd5b6110c5612a1b565b61013180546001600160a01b038381166001600160a01b031983168117909355169081600161073e565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036111395760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661116b6129ff565b6001600160a01b0316146111915760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166111b457604051630103019560e11b815260040160405180910390fd5b604051600483028088833781810195865260209095019390935250506040909101902092915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036112255760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166112576129ff565b6001600160a01b03161461127d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166112a057604051630103019560e11b815260040160405180910390fd5b6112a985612851565b6101335461013454604051634d65479560e11b81526001600160a01b0390921691639aca8f2a916112f191899188918a9189918991600160a81b900460ff1690600401613c53565b60006040518083038186803b15801561130957600080fd5b505afa158015610b78573d6000803e3d6000fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113655760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166113976129ff565b6001600160a01b0316146113bd5760405162461bcd60e51b815260040161068c9061397c565b6113c681612a77565b604080516000808252602082019092526113e291839190612b1f565b50565b600054600190610100900460ff16158015611407575060005460ff8083169116105b6114235760405162461bcd60e51b815260040161068c90613c05565b6000805461ffff191660ff83161761010017905561143f612c8f565b61144886612cbe565b61146a57604051630220cee360e61b815260ff8716600482015260240161068c565b610134805460ff60a81b1916600160a81b60ff891602179055610e106101305561012e85905561013180546001600160a01b03199081166001600160a01b0387811691909117909255610132805482168684161790556101338054821685841617905560335461012d80549190931691161790556114e6612ce5565b6040805160ff88168152602081018790527fd1bcc66c061c32a21f569d138c2dadef4a38a0636309881954af5f44010ec1d8910160405180910390a16000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036115b55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166115e76129ff565b6001600160a01b03161461160d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661163057604051630103019560e11b815260040160405180910390fd5b50610135546001600160a01b03165b90565b60408051606081018252600080825260208201819052918101919091526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036116a75760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166116d96129ff565b6001600160a01b0316146116ff5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661172257604051630103019560e11b815260040160405180910390fd5b61012e5482036117515750506040805160608101825261012e5481526000602082015260019181019190915290565b600082815261012f60205260408120546001600160801b0316908190036117ac5760408051606080820183526000808352602080840182905292840181905283519182018452808252918101829052918201525b9392505050565b610130546000906117c66001600160801b03841642613c8f565b604080516060810182528781526001600160801b039095166020860152911015908301525090505b919050565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361183d5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661186f6129ff565b6001600160a01b0316146118955760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166118b857604051630103019560e11b815260040160405180910390fd5b506101305490565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036119085760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661193a6129ff565b6001600160a01b0316146119605760405162461bcd60e51b815260040161068c9061397c565b61196982612a77565b61197582826001612b1f565b5050565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036119c35760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166119f56129ff565b6001600160a01b031614611a1b5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611a3e57604051630103019560e11b815260040160405180910390fd5b50610132546001600160a01b031690565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611aef5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161068c565b50600080516020613df483398151915290565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611b4a5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611b7c6129ff565b6001600160a01b031614611ba25760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611bc557604051630103019560e11b815260040160405180910390fd5b611bcd612a1b565b61013280546001600160a01b038381166001600160a01b031983168117909355169081600361073e565b611bff612a1b565b6040516377aeb0ad60e01b815260040160405180910390fd5b60655433906001600160a01b03168114611c865760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840161068c565b6113e281612d1b565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611cd95760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611d0b6129ff565b6001600160a01b031614611d315760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611d5457604051630103019560e11b815260040160405180910390fd5b60008989898989898989604051602001611d75989796959493929190613cd9565b60408051601f1981840301815291905280516020909101209a9950505050505050505050565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611de55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611e176129ff565b6001600160a01b031614611e3d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611e6057604051630103019560e11b815260040160405180910390fd5b60008686868686604051602001611e7b959493929190613d3d565b60408051601f198184030181529190528051602090910120979650505050505050565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611ee85760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611f1a6129ff565b6001600160a01b031614611f405760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611f6357604051630103019560e11b815260040160405180910390fd5b5061013454600160a81b900460ff1690565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611fbf5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611ff16129ff565b6001600160a01b0316146120175760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661203a57604051630103019560e11b815260040160405180910390fd5b50610131546001600160a01b031690565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036120955760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166120c76129ff565b6001600160a01b0316146120ed5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661211057604051630103019560e11b815260040160405180910390fd5b612118612a1b565b61012d80546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f5a674c516c196404869e5f502b5634ce442416bb016dde54b5de4c812cc019e690600090a392915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036121b55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166121e76129ff565b6001600160a01b03161461220d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661223057604051630103019560e11b815260040160405180910390fd5b612238612a1b565b61013580546001600160a01b038381166001600160a01b031983168117909355169081600261073e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036122aa5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166122dc6129ff565b6001600160a01b0316146123025760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661232557604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b031633146123535760405163472511eb60e11b815233600482015260240161068c565b61012e5488146123855761012e5460405163542fced960e11b815261068c918a91600401918252602082015260400190565b85841415806123945750858214155b156123b25760405163a0b1d72d60e01b815260040160405180910390fd5b60006123c489838a8a8a8a8a8a611c8f565b905060006123f27f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836139c8565b61013254604051638a283fc360e01b8152600481018b90529192506000916001600160a01b0390911690638a283fc390602401602060405180830381865afa158015612442573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246691906139ea565b9050612475818d848e88612d34565b505050505050505050505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036124cb5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166124fd6129ff565b6001600160a01b0316146125235760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661254657604051630103019560e11b815260040160405180910390fd5b61254e612a1b565b8060000361259e5760405162461bcd60e51b815260206004820152601b60248201527f4578706972792074696d652063616e6e6f74206265207a65726f2e0000000000604482015260640161068c565b610130805490829055604051829082907ff62a6f06fde00a303cd5939e6b53762854412c96a196cda26720cedd28af9e7090600090a35050565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036126225760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166126546129ff565b6001600160a01b03161461267a5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661269d57604051630103019560e11b815260040160405180910390fd5b5061012e5490565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036126ef5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166127216129ff565b6001600160a01b0316146127475760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661276a57604051630103019560e11b815260040160405180910390fd5b5061012d546001600160a01b031690565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036127c55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166127f76129ff565b6001600160a01b03161461281d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661284057604051630103019560e11b815260040160405180910390fd5b50610133546001600160a01b031690565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036128995760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166128cb6129ff565b6001600160a01b0316146128f15760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661291457604051630103019560e11b815260040160405180910390fd5b61012e5481146113e257600081815261012f60205260408120546001600160801b0316908190036129585760405163ddae3b7160e01b815260040160405180910390fd5b6101305461296f6001600160801b03831642613c8f565b111561197557604051631d739acf60e11b815260040160405180910390fd5b612996612a1b565b606580546001600160a01b0383166001600160a01b031990911681179091556129c76033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b600080516020613df4833981519152546001600160a01b031690565b6033546001600160a01b03163314612a755760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161068c565b565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003612abf5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612af16129ff565b6001600160a01b031614612b175760405162461bcd60e51b815260040161068c9061397c565b6113e2612a1b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612b5757612b528361302b565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612bb1575060408051601f3d908101601f19168201909252612bae91810190613d73565b60015b612c145760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840161068c565b600080516020613df48339815191528114612c835760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840161068c565b50612b528383836130c7565b600054610100900460ff16612cb65760405162461bcd60e51b815260040161068c90613d8c565b612a756130f2565b60006010602060ff84168211801590612cdd57508060ff168460ff1611155b949350505050565b600054610100900460ff16612d0c5760405162461bcd60e51b815260040161068c90613d8c565b60fb805460ff19166001179055565b606580546001600160a01b03191690556113e281613129565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003612d7c5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612dae6129ff565b6001600160a01b031614612dd45760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16612df757604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b03163314612e255760405163472511eb60e11b815233600482015260240161068c565b6000604051806040016040528086600060088110612e4557612e45613a07565b6020020135815260200186600160088110612e6257612e62613a07565b6020020135905260408051608081018252878201359181019182529192506000919081906060820189600360200201358152508152602001604051806040016040528089600460088110612eb857612eb8613a07565b6020020135815260200189600560088110612ed557612ed5613a07565b60200201359052905260408051808201909152909150600090808860066020020135815260200188600760088110612f0f57612f0f613a07565b6020020135815250905060006040518060200160405280888152509050886001600160a01b03166343753b4d858585856040518563ffffffff1660e01b8152600401612f5e9493929190613a40565b6020604051808303816000875af1925050508015612f99575060408051601f3d908101601f19168201909252612f9691810190613ae7565b60015b612fa557610aa9613b09565b80612fc357604051631e716a8b60e01b815260040160405180910390fd5b61012e869055600087815261012f6020526040902080546001600160801b031916426001600160801b031617905585600260405189907f25f6d5cc356ee0b49cf708c13c68197947f5740a878a298765e4b18e4afdaf0490600090a450505050505050505050565b6001600160a01b0381163b6130985760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161068c565b600080516020613df483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6130d08361317b565b6000825111806130dd5750805b15612b52576130ec83836131bb565b50505050565b600054610100900460ff166131195760405162461bcd60e51b815260040161068c90613d8c565b6131216132b1565b612a756132e0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6131848161302b565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6132235760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161068c565b600080846001600160a01b03168460405161323e9190613dd7565b600060405180830381855af49150503d8060008114613279576040519150601f19603f3d011682016040523d82523d6000602084013e61327e565b606091505b50915091506132a68282604051806060016040528060278152602001613e1460279139613307565b925050505b92915050565b600054610100900460ff166132d85760405162461bcd60e51b815260040161068c90613d8c565b612a75613320565b600054610100900460ff16612a755760405162461bcd60e51b815260040161068c90613d8c565b606083156133165750816117a5565b6117a58383613350565b600054610100900460ff166133475760405162461bcd60e51b815260040161068c90613d8c565b612a7533612d1b565b815115610ac85781518083602001fd5b6001600160a01b03811681146113e257600080fd5b60006020828403121561338757600080fd5b81356117a581613360565b8061010081018310156132ab57600080fd5b803563ffffffff811681146117ee57600080fd5b60008083601f8401126133ca57600080fd5b50813567ffffffffffffffff8111156133e257600080fd5b6020830191508360208260051b85010111156133fd57600080fd5b9250929050565b600080600080600080610180878903121561341e57600080fd5b6134288888613392565b9550610100870135945061343f61012088016133a4565b935061014087013567ffffffffffffffff81111561345c57600080fd5b61346889828a016133b8565b979a969950949794969561016090950135949350505050565b60008083601f84011261349357600080fd5b50813567ffffffffffffffff8111156134ab57600080fd5b6020830191508360208285010111156133fd57600080fd5b60008060008060008061018087890312156134dd57600080fd5b6134e78888613392565b95506134f661010088016133a4565b945061012087013567ffffffffffffffff81111561351357600080fd5b61351f89828a01613481565b979a96995097610140810135966101609091013595509350505050565b60008060008060006080868803121561355457600080fd5b853567ffffffffffffffff81111561356b57600080fd5b61357788828901613481565b9096509450506020860135925060408601359150613597606087016133a4565b90509295509295909350565b600080600080600061018086880312156135bc57600080fd5b853594506020860135935060408601359250606086013591506135978760808801613392565b600080600080600060a086880312156135fa57600080fd5b853560ff8116811461360b57600080fd5b945060208601359350604086013561362281613360565b9250606086013561363281613360565b9150608086013561364281613360565b809150509295509295909350565b60006020828403121561366257600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff811182821017156136a5576136a5613669565b6040525050565b600080604083850312156136bf57600080fd5b82356136ca81613360565b915060208381013567ffffffffffffffff808211156136e857600080fd5b818601915086601f8301126136fc57600080fd5b81358181111561370e5761370e613669565b6040519150613726601f8201601f191685018361367f565b808252878482850101111561373a57600080fd5b80848401858401376000848284010152508093505050509250929050565b60008060008060008060008060a0898b03121561377457600080fd5b8835975060208901359650604089013567ffffffffffffffff8082111561379a57600080fd5b6137a68c838d016133b8565b909850965060608b01359150808211156137bf57600080fd5b6137cb8c838d016133b8565b909650945060808b01359150808211156137e457600080fd5b506137f18b828c016133b8565b999c989b5096995094979396929594505050565b60008060008060006080868803121561381d57600080fd5b613826866133a4565b94506020860135935060408601359250606086013567ffffffffffffffff81111561385057600080fd5b61385c888289016133b8565b969995985093965092949392505050565b60008060008060008060008060006101a08a8c03121561388c57600080fd5b6138968b8b613392565b98506101008a013597506101208a013567ffffffffffffffff808211156138bc57600080fd5b6138c88d838e016133b8565b90995097506101408c01359150808211156138e257600080fd5b6138ee8d838e016133b8565b90975095506101608c013591508082111561390857600080fd5b506139158c828d016133b8565b9a9d999c50979a969995989497966101800135949350505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000826139e557634e487b7160e01b600052601260045260246000fd5b500690565b6000602082840312156139fc57600080fd5b81516117a581613360565b634e487b7160e01b600052603260045260246000fd5b8060005b60028110156130ec578151845260209384019390910190600101613a21565b6101208101613a4f8287613a1d565b60408083018660005b6002808210613a675750613aa2565b82518460005b83811015613a8b578251825260209283019290910190600101613a6d565b505050928401925060209190910190600101613a58565b50505050613ab360c0830185613a1d565b61010082018360005b6001811015613adb578151835260209283019290910190600101613abc565b50505095945050505050565b600060208284031215613af957600080fd5b815180151581146117a557600080fd5b600060033d111561163f5760046000803e5060005160e01c90565b600060443d1015613b325790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715613b6257505050505090565b8285019150815181811115613b7a5750505050505090565b843d8701016020828501011115613b945750505050505090565b613ba36020828601018761367f565b509095945050505050565b60005b83811015613bc9578181015183820152602001613bb1565b50506000910152565b6020815260008251806020840152613bf1816040850160208701613bae565b601f01601f19169190910160400192915050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006101a08201905087825286602083015285604083015284606083015261010084608084013760ff8316610180830152979650505050505050565b818103818111156132ab57634e487b7160e01b600052601160045260246000fd5b60006001600160fb1b03831115613cc657600080fd5b8260051b80838637939093019392505050565b888152600060208981840152604083018960005b8a811015613d165763ffffffff613d03836133a4565b1683529183019190830190600101613ced565b5050613d2d613d2682898b613cb0565b8688613cb0565b9c9b505050505050505050505050565b63ffffffff60e01b8660e01b1681528460048201528360248201526000613d68604483018486613cb0565b979650505050505050565b600060208284031215613d8557600080fd5b5051919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251613de9818460208701613bae565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202258b63db6550ae18ade93a6816c682fce5f6960e9619c49b1085dddff743c4364736f6c63430008150033", + "sourceMap": "443:11607:43:-:0;;;1332:4:23;1289:48;;443:11607:43;;;;;;;;;-1:-1:-1;12497:22:42;:20;:22::i;:::-;443:11607:43;;5928:279:22;5996:13;;;;;;;5995:14;5987:66;;;;-1:-1:-1;;;5987:66:22;;216:2:80;5987:66:22;;;198:21:80;255:2;235:18;;;228:30;294:34;274:18;;;267:62;-1:-1:-1;;;345:18:80;;;338:37;392:19;;5987:66:22;;;;;;;;6067:12;;6082:15;6067:12;;;:30;6063:138;;;6113:12;:30;;-1:-1:-1;;6113:30:22;6128:15;6113:30;;;;;;6162:28;;564:36:80;;;6162:28:22;;552:2:80;537:18;6162:28:22;;;;;;;6063:138;5928:279::o;422:184:80:-;443:11607:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x6080604052600436106101f95760003560e01c8063715018a61161010d578063aa4a729e116100a0578063e30c39781161006f578063e30c3978146105bc578063f134b6ca146105da578063f2038f95146105ef578063f2358e1d14610604578063f2fde38b1461062457600080fd5b8063aa4a729e14610547578063b843b4e514610567578063c70aa72714610587578063d7b0fef1146105a757600080fd5b80638da5cb5b116100dc5780638da5cb5b146104cd5780638e5cdd50146104eb5780638fc22e9f14610512578063a7bba5821461052757600080fd5b8063715018a61461046357806379ba50971461047857806386ec599a1461048d5780638c76a909146104ad57600080fd5b806338c87065116101905780634f1ef2861161015f5780634f1ef286146103c25780634ffbdde5146103d557806352d1902d146103ea578063561f204b146103ff5780636b0566001461044357600080fd5b806338c87065146103135780633e8919b6146103335780633f7c178d1461036057806343f974cb146103ad57600080fd5b80632f059fca116101cc5780632f059fca1461028057806331e4e992146102a0578063354ca120146102d35780633659cfe6146102f357600080fd5b80630e3a12f3146101fe5780632217b2111461022057806323cfdba51461024057806329b6eca914610260575b600080fd5b34801561020a57600080fd5b5061021e610219366004613375565b610644565b005b34801561022c57600080fd5b5061021e61023b366004613404565b61076b565b34801561024c57600080fd5b5061021e61025b3660046134c3565b610b83565b34801561026c57600080fd5b5061021e61027b366004613375565b610f4c565b34801561028c57600080fd5b5061021e61029b366004613375565b610ffa565b3480156102ac57600080fd5b506102c06102bb36600461353c565b6110ef565b6040519081526020015b60405180910390f35b3480156102df57600080fd5b5061021e6102ee3660046135a3565b6111dd565b3480156102ff57600080fd5b5061021e61030e366004613375565b61131d565b34801561031f57600080fd5b5061021e61032e3660046135e2565b6113e5565b34801561033f57600080fd5b5061034861156b565b6040516001600160a01b0390911681526020016102ca565b34801561036c57600080fd5b5061038061037b366004613650565b611642565b60408051825181526020808401516001600160801b031690820152918101511515908201526060016102ca565b3480156103b957600080fd5b506102c06117f3565b61021e6103d03660046136ac565b6118c0565b3480156103e157600080fd5b50610348611979565b3480156103f657600080fd5b506102c0611a4f565b34801561040b57600080fd5b506040805160608082018352600080835260208084018290529284018190528351918201845280825291810182905291820152610380565b34801561044f57600080fd5b5061021e61045e366004613375565b611b02565b34801561046f57600080fd5b5061021e611bf7565b34801561048457600080fd5b5061021e611c18565b34801561049957600080fd5b506102c06104a8366004613758565b611c8f565b3480156104b957600080fd5b506102c06104c8366004613805565b611d9b565b3480156104d957600080fd5b506033546001600160a01b0316610348565b3480156104f757600080fd5b50610500611e9e565b60405160ff90911681526020016102ca565b34801561051e57600080fd5b50610348611f75565b34801561053357600080fd5b50610348610542366004613375565b61204b565b34801561055357600080fd5b5061021e610562366004613375565b61216d565b34801561057357600080fd5b5061021e61058236600461386d565b612262565b34801561059357600080fd5b5061021e6105a2366004613650565b612483565b3480156105b357600080fd5b506102c06125d8565b3480156105c857600080fd5b506065546001600160a01b0316610348565b3480156105e657600080fd5b506103486126a5565b3480156105fb57600080fd5b5061034861277b565b34801561061057600080fd5b5061021e61061f366004613650565b612851565b34801561063057600080fd5b5061021e61063f366004613375565b61298e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036106955760405162461bcd60e51b815260040161068c90613930565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166106c76129ff565b6001600160a01b0316146106ed5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661071057604051630103019560e11b815260040160405180910390fd5b610718612a1b565b61013380546001600160a01b038381166001600160a01b03198316811790935516908160045b6040517fd194b8423e9cb3c7cbebbbc3fe7f79dc2cbe0b40e03270d975abff491504c7b190600090a45050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036107b35760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166107e56129ff565b6001600160a01b03161461080b5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661082e57604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b0316331461085c5760405163472511eb60e11b815233600482015260240161068c565b61012e54851461088e5761012e5460405163542fced960e11b815261068c918791600401918252602082015260400190565b600061089d8587848787611d9b565b905060006108cb7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836139c8565b61013154604051638a283fc360e01b8152600481018790529192506000916001600160a01b0390911690638a283fc390602401602060405180830381865afa15801561091b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093f91906139ea565b9050806001600160a01b03166343753b4d60405180604001604052808c60006008811061096e5761096e613a07565b602002013581526020018c60016008811061098b5761098b613a07565b60200201359052604080516080810182528d820135918101918252908190606082018f60036020020135815250815260200160405180604001604052808f6004600881106109db576109db613a07565b602002013581526020018f6005600881106109f8576109f8613a07565b60200201359052905260408051808201909152808e6006602002013581526020018e600760088110610a2c57610a2c613a07565b60200201358152506040518060200160405280888152506040518563ffffffff1660e01b8152600401610a629493929190613a40565b6020604051808303816000875af1925050508015610a9d575060408051601f3d908101601f19168201909252610a9a91810190613ae7565b60015b610afd57610aa9613b09565b806308c379a003610ae25750610abd613b24565b80610ac85750610ae4565b8060405162461bcd60e51b815260040161068c9190613bd2565b505b604051631e716a8b60e01b815260040160405180910390fd5b80610b1b57604051631e716a8b60e01b815260040160405180910390fd5b61012e859055600089815261012f6020526040812080546001600160801b031916426001600160801b031617905585906040518b907f25f6d5cc356ee0b49cf708c13c68197947f5740a878a298765e4b18e4afdaf0490600090a4505b505050505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610bcb5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610bfd6129ff565b6001600160a01b031614610c235760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16610c4657604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b03163314610c745760405163472511eb60e11b815233600482015260240161068c565b61012e548214610ca65761012e5460405163542fced960e11b815261068c918491600401918252602082015260400190565b6000610cb5858585858a6110ef565b90506000610ce37f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836139c8565b61013554604051638a283fc360e01b815263ffffffff8a1660048201529192506000916001600160a01b0390911690638a283fc390602401602060405180830381865afa158015610d38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5c91906139ea565b9050806001600160a01b03166343753b4d60405180604001604052808c600060088110610d8b57610d8b613a07565b602002013581526020018c600160088110610da857610da8613a07565b60200201359052604080516080810182528d820135918101918252908190606082018f60036020020135815250815260200160405180604001604052808f600460088110610df857610df8613a07565b602002013581526020018f600560088110610e1557610e15613a07565b60200201359052905260408051808201909152808e6006602002013581526020018e600760088110610e4957610e49613a07565b60200201358152506040518060200160405280888152506040518563ffffffff1660e01b8152600401610e7f9493929190613a40565b6020604051808303816000875af1925050508015610eba575060408051601f3d908101601f19168201909252610eb791810190613ae7565b60015b610ec657610aa9613b09565b80610ee457604051631e716a8b60e01b815260040160405180910390fd5b61012e859055600086815261012f6020526040902080546001600160801b031916426001600160801b031617905584600160405188907f25f6d5cc356ee0b49cf708c13c68197947f5740a878a298765e4b18e4afdaf0490600090a450505050505050505050565b600054600290610100900460ff16158015610f6e575060005460ff8083169116105b610f8a5760405162461bcd60e51b815260040161068c90613c05565b6000805461013580546001600160a01b0319166001600160a01b03861617905561ff001961010060ff851661ffff19909316831717169091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036110425760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166110746129ff565b6001600160a01b03161461109a5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166110bd57604051630103019560e11b815260040160405180910390fd5b6110c5612a1b565b61013180546001600160a01b038381166001600160a01b031983168117909355169081600161073e565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036111395760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661116b6129ff565b6001600160a01b0316146111915760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166111b457604051630103019560e11b815260040160405180910390fd5b604051600483028088833781810195865260209095019390935250506040909101902092915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036112255760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166112576129ff565b6001600160a01b03161461127d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166112a057604051630103019560e11b815260040160405180910390fd5b6112a985612851565b6101335461013454604051634d65479560e11b81526001600160a01b0390921691639aca8f2a916112f191899188918a9189918991600160a81b900460ff1690600401613c53565b60006040518083038186803b15801561130957600080fd5b505afa158015610b78573d6000803e3d6000fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113655760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166113976129ff565b6001600160a01b0316146113bd5760405162461bcd60e51b815260040161068c9061397c565b6113c681612a77565b604080516000808252602082019092526113e291839190612b1f565b50565b600054600190610100900460ff16158015611407575060005460ff8083169116105b6114235760405162461bcd60e51b815260040161068c90613c05565b6000805461ffff191660ff83161761010017905561143f612c8f565b61144886612cbe565b61146a57604051630220cee360e61b815260ff8716600482015260240161068c565b610134805460ff60a81b1916600160a81b60ff891602179055610e106101305561012e85905561013180546001600160a01b03199081166001600160a01b0387811691909117909255610132805482168684161790556101338054821685841617905560335461012d80549190931691161790556114e6612ce5565b6040805160ff88168152602081018790527fd1bcc66c061c32a21f569d138c2dadef4a38a0636309881954af5f44010ec1d8910160405180910390a16000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036115b55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166115e76129ff565b6001600160a01b03161461160d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661163057604051630103019560e11b815260040160405180910390fd5b50610135546001600160a01b03165b90565b60408051606081018252600080825260208201819052918101919091526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036116a75760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166116d96129ff565b6001600160a01b0316146116ff5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661172257604051630103019560e11b815260040160405180910390fd5b61012e5482036117515750506040805160608101825261012e5481526000602082015260019181019190915290565b600082815261012f60205260408120546001600160801b0316908190036117ac5760408051606080820183526000808352602080840182905292840181905283519182018452808252918101829052918201525b9392505050565b610130546000906117c66001600160801b03841642613c8f565b604080516060810182528781526001600160801b039095166020860152911015908301525090505b919050565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361183d5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661186f6129ff565b6001600160a01b0316146118955760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff166118b857604051630103019560e11b815260040160405180910390fd5b506101305490565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036119085760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661193a6129ff565b6001600160a01b0316146119605760405162461bcd60e51b815260040161068c9061397c565b61196982612a77565b61197582826001612b1f565b5050565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036119c35760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166119f56129ff565b6001600160a01b031614611a1b5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611a3e57604051630103019560e11b815260040160405180910390fd5b50610132546001600160a01b031690565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611aef5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161068c565b50600080516020613df483398151915290565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611b4a5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611b7c6129ff565b6001600160a01b031614611ba25760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611bc557604051630103019560e11b815260040160405180910390fd5b611bcd612a1b565b61013280546001600160a01b038381166001600160a01b031983168117909355169081600361073e565b611bff612a1b565b6040516377aeb0ad60e01b815260040160405180910390fd5b60655433906001600160a01b03168114611c865760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840161068c565b6113e281612d1b565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611cd95760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611d0b6129ff565b6001600160a01b031614611d315760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611d5457604051630103019560e11b815260040160405180910390fd5b60008989898989898989604051602001611d75989796959493929190613cd9565b60408051601f1981840301815291905280516020909101209a9950505050505050505050565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611de55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611e176129ff565b6001600160a01b031614611e3d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611e6057604051630103019560e11b815260040160405180910390fd5b60008686868686604051602001611e7b959493929190613d3d565b60408051601f198184030181529190528051602090910120979650505050505050565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611ee85760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611f1a6129ff565b6001600160a01b031614611f405760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16611f6357604051630103019560e11b815260040160405180910390fd5b5061013454600160a81b900460ff1690565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611fbf5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611ff16129ff565b6001600160a01b0316146120175760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661203a57604051630103019560e11b815260040160405180910390fd5b50610131546001600160a01b031690565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036120955760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166120c76129ff565b6001600160a01b0316146120ed5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661211057604051630103019560e11b815260040160405180910390fd5b612118612a1b565b61012d80546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f5a674c516c196404869e5f502b5634ce442416bb016dde54b5de4c812cc019e690600090a392915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036121b55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166121e76129ff565b6001600160a01b03161461220d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661223057604051630103019560e11b815260040160405180910390fd5b612238612a1b565b61013580546001600160a01b038381166001600160a01b031983168117909355169081600261073e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036122aa5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166122dc6129ff565b6001600160a01b0316146123025760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661232557604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b031633146123535760405163472511eb60e11b815233600482015260240161068c565b61012e5488146123855761012e5460405163542fced960e11b815261068c918a91600401918252602082015260400190565b85841415806123945750858214155b156123b25760405163a0b1d72d60e01b815260040160405180910390fd5b60006123c489838a8a8a8a8a8a611c8f565b905060006123f27f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836139c8565b61013254604051638a283fc360e01b8152600481018b90529192506000916001600160a01b0390911690638a283fc390602401602060405180830381865afa158015612442573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246691906139ea565b9050612475818d848e88612d34565b505050505050505050505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036124cb5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166124fd6129ff565b6001600160a01b0316146125235760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661254657604051630103019560e11b815260040160405180910390fd5b61254e612a1b565b8060000361259e5760405162461bcd60e51b815260206004820152601b60248201527f4578706972792074696d652063616e6e6f74206265207a65726f2e0000000000604482015260640161068c565b610130805490829055604051829082907ff62a6f06fde00a303cd5939e6b53762854412c96a196cda26720cedd28af9e7090600090a35050565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036126225760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166126546129ff565b6001600160a01b03161461267a5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661269d57604051630103019560e11b815260040160405180910390fd5b5061012e5490565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036126ef5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166127216129ff565b6001600160a01b0316146127475760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661276a57604051630103019560e11b815260040160405180910390fd5b5061012d546001600160a01b031690565b60006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036127c55760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166127f76129ff565b6001600160a01b03161461281d5760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661284057604051630103019560e11b815260040160405180910390fd5b50610133546001600160a01b031690565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036128995760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166128cb6129ff565b6001600160a01b0316146128f15760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff1661291457604051630103019560e11b815260040160405180910390fd5b61012e5481146113e257600081815261012f60205260408120546001600160801b0316908190036129585760405163ddae3b7160e01b815260040160405180910390fd5b6101305461296f6001600160801b03831642613c8f565b111561197557604051631d739acf60e11b815260040160405180910390fd5b612996612a1b565b606580546001600160a01b0383166001600160a01b031990911681179091556129c76033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b600080516020613df4833981519152546001600160a01b031690565b6033546001600160a01b03163314612a755760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161068c565b565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003612abf5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612af16129ff565b6001600160a01b031614612b175760405162461bcd60e51b815260040161068c9061397c565b6113e2612a1b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612b5757612b528361302b565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612bb1575060408051601f3d908101601f19168201909252612bae91810190613d73565b60015b612c145760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840161068c565b600080516020613df48339815191528114612c835760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840161068c565b50612b528383836130c7565b600054610100900460ff16612cb65760405162461bcd60e51b815260040161068c90613d8c565b612a756130f2565b60006010602060ff84168211801590612cdd57508060ff168460ff1611155b949350505050565b600054610100900460ff16612d0c5760405162461bcd60e51b815260040161068c90613d8c565b60fb805460ff19166001179055565b606580546001600160a01b03191690556113e281613129565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003612d7c5760405162461bcd60e51b815260040161068c90613930565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612dae6129ff565b6001600160a01b031614612dd45760405162461bcd60e51b815260040161068c9061397c565b60fb5460ff16612df757604051630103019560e11b815260040160405180910390fd5b61012d546001600160a01b03163314612e255760405163472511eb60e11b815233600482015260240161068c565b6000604051806040016040528086600060088110612e4557612e45613a07565b6020020135815260200186600160088110612e6257612e62613a07565b6020020135905260408051608081018252878201359181019182529192506000919081906060820189600360200201358152508152602001604051806040016040528089600460088110612eb857612eb8613a07565b6020020135815260200189600560088110612ed557612ed5613a07565b60200201359052905260408051808201909152909150600090808860066020020135815260200188600760088110612f0f57612f0f613a07565b6020020135815250905060006040518060200160405280888152509050886001600160a01b03166343753b4d858585856040518563ffffffff1660e01b8152600401612f5e9493929190613a40565b6020604051808303816000875af1925050508015612f99575060408051601f3d908101601f19168201909252612f9691810190613ae7565b60015b612fa557610aa9613b09565b80612fc357604051631e716a8b60e01b815260040160405180910390fd5b61012e869055600087815261012f6020526040902080546001600160801b031916426001600160801b031617905585600260405189907f25f6d5cc356ee0b49cf708c13c68197947f5740a878a298765e4b18e4afdaf0490600090a450505050505050505050565b6001600160a01b0381163b6130985760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161068c565b600080516020613df483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6130d08361317b565b6000825111806130dd5750805b15612b52576130ec83836131bb565b50505050565b600054610100900460ff166131195760405162461bcd60e51b815260040161068c90613d8c565b6131216132b1565b612a756132e0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6131848161302b565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6132235760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161068c565b600080846001600160a01b03168460405161323e9190613dd7565b600060405180830381855af49150503d8060008114613279576040519150601f19603f3d011682016040523d82523d6000602084013e61327e565b606091505b50915091506132a68282604051806060016040528060278152602001613e1460279139613307565b925050505b92915050565b600054610100900460ff166132d85760405162461bcd60e51b815260040161068c90613d8c565b612a75613320565b600054610100900460ff16612a755760405162461bcd60e51b815260040161068c90613d8c565b606083156133165750816117a5565b6117a58383613350565b600054610100900460ff166133475760405162461bcd60e51b815260040161068c90613d8c565b612a7533612d1b565b815115610ac85781518083602001fd5b6001600160a01b03811681146113e257600080fd5b60006020828403121561338757600080fd5b81356117a581613360565b8061010081018310156132ab57600080fd5b803563ffffffff811681146117ee57600080fd5b60008083601f8401126133ca57600080fd5b50813567ffffffffffffffff8111156133e257600080fd5b6020830191508360208260051b85010111156133fd57600080fd5b9250929050565b600080600080600080610180878903121561341e57600080fd5b6134288888613392565b9550610100870135945061343f61012088016133a4565b935061014087013567ffffffffffffffff81111561345c57600080fd5b61346889828a016133b8565b979a969950949794969561016090950135949350505050565b60008083601f84011261349357600080fd5b50813567ffffffffffffffff8111156134ab57600080fd5b6020830191508360208285010111156133fd57600080fd5b60008060008060008061018087890312156134dd57600080fd5b6134e78888613392565b95506134f661010088016133a4565b945061012087013567ffffffffffffffff81111561351357600080fd5b61351f89828a01613481565b979a96995097610140810135966101609091013595509350505050565b60008060008060006080868803121561355457600080fd5b853567ffffffffffffffff81111561356b57600080fd5b61357788828901613481565b9096509450506020860135925060408601359150613597606087016133a4565b90509295509295909350565b600080600080600061018086880312156135bc57600080fd5b853594506020860135935060408601359250606086013591506135978760808801613392565b600080600080600060a086880312156135fa57600080fd5b853560ff8116811461360b57600080fd5b945060208601359350604086013561362281613360565b9250606086013561363281613360565b9150608086013561364281613360565b809150509295509295909350565b60006020828403121561366257600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff811182821017156136a5576136a5613669565b6040525050565b600080604083850312156136bf57600080fd5b82356136ca81613360565b915060208381013567ffffffffffffffff808211156136e857600080fd5b818601915086601f8301126136fc57600080fd5b81358181111561370e5761370e613669565b6040519150613726601f8201601f191685018361367f565b808252878482850101111561373a57600080fd5b80848401858401376000848284010152508093505050509250929050565b60008060008060008060008060a0898b03121561377457600080fd5b8835975060208901359650604089013567ffffffffffffffff8082111561379a57600080fd5b6137a68c838d016133b8565b909850965060608b01359150808211156137bf57600080fd5b6137cb8c838d016133b8565b909650945060808b01359150808211156137e457600080fd5b506137f18b828c016133b8565b999c989b5096995094979396929594505050565b60008060008060006080868803121561381d57600080fd5b613826866133a4565b94506020860135935060408601359250606086013567ffffffffffffffff81111561385057600080fd5b61385c888289016133b8565b969995985093965092949392505050565b60008060008060008060008060006101a08a8c03121561388c57600080fd5b6138968b8b613392565b98506101008a013597506101208a013567ffffffffffffffff808211156138bc57600080fd5b6138c88d838e016133b8565b90995097506101408c01359150808211156138e257600080fd5b6138ee8d838e016133b8565b90975095506101608c013591508082111561390857600080fd5b506139158c828d016133b8565b9a9d999c50979a969995989497966101800135949350505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000826139e557634e487b7160e01b600052601260045260246000fd5b500690565b6000602082840312156139fc57600080fd5b81516117a581613360565b634e487b7160e01b600052603260045260246000fd5b8060005b60028110156130ec578151845260209384019390910190600101613a21565b6101208101613a4f8287613a1d565b60408083018660005b6002808210613a675750613aa2565b82518460005b83811015613a8b578251825260209283019290910190600101613a6d565b505050928401925060209190910190600101613a58565b50505050613ab360c0830185613a1d565b61010082018360005b6001811015613adb578151835260209283019290910190600101613abc565b50505095945050505050565b600060208284031215613af957600080fd5b815180151581146117a557600080fd5b600060033d111561163f5760046000803e5060005160e01c90565b600060443d1015613b325790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715613b6257505050505090565b8285019150815181811115613b7a5750505050505090565b843d8701016020828501011115613b945750505050505090565b613ba36020828601018761367f565b509095945050505050565b60005b83811015613bc9578181015183820152602001613bb1565b50506000910152565b6020815260008251806020840152613bf1816040850160208701613bae565b601f01601f19169190910160400192915050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006101a08201905087825286602083015285604083015284606083015261010084608084013760ff8316610180830152979650505050505050565b818103818111156132ab57634e487b7160e01b600052601160045260246000fd5b60006001600160fb1b03831115613cc657600080fd5b8260051b80838637939093019392505050565b888152600060208981840152604083018960005b8a811015613d165763ffffffff613d03836133a4565b1683529183019190830190600101613ced565b5050613d2d613d2682898b613cb0565b8688613cb0565b9c9b505050505050505050505050565b63ffffffff60e01b8660e01b1681528460048201528360248201526000613d68604483018486613cb0565b979650505050505050565b600060208284031215613d8557600080fd5b5051919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251613de9818460208701613bae565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202258b63db6550ae18ade93a6816c682fce5f6960e9619c49b1085dddff743c4364736f6c63430008150033", + "sourceMap": "443:11607:43:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37178:393:42;;;;;;;;;;-1:-1:-1;37178:393:42;;;;;:::i;:::-;;:::i;:::-;;17580:2498;;;;;;;;;;-1:-1:-1;17580:2498:42;;;;;:::i;:::-;;:::i;6380:2438:43:-;;;;;;;;;;-1:-1:-1;6380:2438:43;;;;;:::i;:::-;;:::i;3800:152::-;;;;;;;;;;-1:-1:-1;3800:152:43;;;;;:::i;:::-;;:::i;34738:423:42:-;;;;;;;;;;-1:-1:-1;34738:423:42;;;;;:::i;:::-;;:::i;11363:685:43:-;;;;;;;;;;-1:-1:-1;11363:685:43;;;;;:::i;:::-;;:::i;:::-;;;4125:25:80;;;4113:2;4098:18;11363:685:43;;;;;;;;40699:508:42;;;;;;;;;;-1:-1:-1;40699:508:42;;;;;:::i;:::-;;:::i;3317:197:23:-;;;;;;;;;;-1:-1:-1;3317:197:23;;;;;:::i;:::-;;:::i;13806:1014:42:-;;;;;;;;;;-1:-1:-1;13806:1014:42;;;;;:::i;:::-;;:::i;9156:228:43:-;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;6024:32:80;;;6006:51;;5994:2;5979:18;9156:228:43;5860:203:80;32299:567:42;;;;;;;;;;-1:-1:-1;32299:567:42;;;;;:::i;:::-;;:::i;:::-;;;;6471:13:80;;6453:32;;6545:4;6533:17;;;6527:24;-1:-1:-1;;;;;6523:65:80;6501:20;;;6494:95;6647:17;;;6641:24;6634:32;6627:40;6605:20;;;6598:70;6441:2;6426:18;32299:567:42;6253:421:80;37747:189:42;;;;;;;;;;;;;:::i;3763:222:23:-;;;;;;:::i;:::-;;:::i;35454:227:42:-;;;;;;;;;;;;;:::i;3006:131:23:-;;;;;;;;;;;;;:::i;7130:120:42:-;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;7218:25:42;;;;;;;;;;;;;;;;;;;;7130:120;;36071:416;;;;;;;;;;-1:-1:-1;36071:416:42;;;;;:::i;:::-;;:::i;4649:109:44:-;;;;;;;;;;;;;:::i;2010:206:17:-;;;;;;;;;;;;;:::i;31089:465:42:-;;;;;;;;;;-1:-1:-1;31089:465:42;;;;;:::i;:::-;;:::i;29135:413::-;;;;;;;;;;-1:-1:-1;29135:413:42;;;;;:::i;:::-;;:::i;1441:85:18:-;;;;;;;;;;-1:-1:-1;1513:6:18;;-1:-1:-1;;;;;1513:6:18;1441:85;;38714:119:42;;;;;;;;;;;;;:::i;:::-;;;10258:4:80;10246:17;;;10228:36;;10216:2;10201:18;38714:119:42;10086:184:80;34179:231:42;;;;;;;;;;;;;:::i;39480:384::-;;;;;;;;;;-1:-1:-1;39480:384:42;;;;;:::i;:::-;;:::i;9704:418:43:-;;;;;;;;;;-1:-1:-1;9704:418:43;;;;;:::i;:::-;;:::i;22820:1590:42:-;;;;;;;;;;-1:-1:-1;22820:1590:42;;;;;:::i;:::-;;:::i;38168:402::-;;;;;;;;;;-1:-1:-1;38168:402:42;;;;;:::i;:::-;;:::i;31682:121::-;;;;;;;;;;;;;:::i;1123:99:17:-;;;;;;;;;;-1:-1:-1;1202:13:17;;-1:-1:-1;;;;;1202:13:17;1123:99;;39054:133:42;;;;;;;;;;;;;:::i;36670:205::-;;;;;;;;;;;;;:::i;33309:638::-;;;;;;;;;;-1:-1:-1;33309:638:42;;;;;:::i;:::-;;:::i;1415:178:17:-;;;;;;;;;;-1:-1:-1;1415:178:17;;;;;:::i;:::-;;:::i;37178:393:42:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;;;;;;;;;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;1334:13:18::2;:11;:13::i;:::-;37378:17:42::3;::::0;;-1:-1:-1;;;;;37405:31:42;;::::3;-1:-1:-1::0;;;;;;37405:31:42;::::3;::::0;::::3;::::0;;;37378:17:::3;::::0;;37482:28:::3;37451:113;;::::0;::::3;::::0;;;::::3;37335:236;37178:393:::0;:::o;17580:2498::-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;41750:17:42::2;::::0;-1:-1:-1;;;;;41750:17:42::2;41736:10;:31;41732:93;;41790:24;::::0;-1:-1:-1;;;41790:24:42;;41803:10:::2;41790:24;::::0;::::2;6006:51:80::0;5979:18;;41790:24:42::2;5860:203:80::0;41732:93:42::2;17871:11:::3;;17860:7;:22;17856:95;;17928:11;::::0;17905:35:::3;::::0;-1:-1:-1;;;17905:35:42;;::::3;::::0;17919:7;;17905:35:::3;;12764:25:80::0;;;12820:2;12805:18;;12798:34;12752:2;12737:18;;12590:248;17856:95:42::3;18042:17;18062:112;18114:10;18126:7;18135:8;18145:19;;18062:38;:112::i;:::-;18042:132:::0;-1:-1:-1;18445:22:42::3;18470:39;4368:77;18042:132:::0;18470:39:::3;:::i;:::-;18639:23;::::0;:66:::3;::::0;-1:-1:-1;;;18639:66:42;;::::3;::::0;::::3;4125:25:80::0;;;18445:64:42;;-1:-1:-1;18593:31:42::3;::::0;-1:-1:-1;;;;;18639:23:42;;::::3;::::0;:38:::3;::::0;4098:18:80;;18639:66:42::3;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;18593:112;;18774:17;-1:-1:-1::0;;;;;18774:29:42::3;;:267;;;;;;;;18818:14;18833:1;18818:17;;;;;;;:::i;:::-;;;;;18774:267;;;;18837:14;18852:1;18837:17;;;;;;;:::i;:::-;;;;;18774:267:::0;;::::3;::::0;;;;;;;18871:17;;::::3;;18774:267:::0;;::::3;::::0;;;;;;;;;18871:14;18905:1:::3;18890:17;;;;18774:267;;::::0;::::3;;;;;;;;;;;;18911:14;18926:1;18911:17;;;;;;;:::i;:::-;;;;;18774:267;;;;18930:14;18945:1;18930:17;;;;;;;:::i;:::-;;;;;18774:267:::0;;;;::::3;::::0;;;;::::3;::::0;;;;18964:14;18979:1:::3;18964:17;;;;18774:267;;;;18983:14;18998:1;18983:17;;;;;;;:::i;:::-;;;;;18774:267;;::::0;::::3;;;;;;;;19016:14;18774:267;;::::0;::::3;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;18774:267:42::3;::::0;;::::3;;::::0;;::::3;-1:-1:-1::0;;18774:267:42::3;::::0;::::3;::::0;;;::::3;::::0;;::::3;::::0;::::3;:::i;:::-;;;18770:1302;;;;:::i;:::-;;;::::0;::::3;;;;;:::i;:::-;;;;;;;;19824:9;19817:17;;-1:-1:-1::0;;;19817:17:42::3;;;;;;;;:::i;18770:1302::-;;;20037:24;;-1:-1:-1::0;;;20037:24:42::3;;;;;;;;;;;18770:1302;19161:14;19156:85;;19202:24;;-1:-1:-1::0;;;19202:24:42::3;;;;;;;;;;;19156:85;19409:11;:22:::0;;;19577:20:::3;::::0;;;:11:::3;:20;::::0;;;;:47;;-1:-1:-1;;;;;;19577:47:42::3;19608:15;-1:-1:-1::0;;;;;19577:47:42::3;;::::0;;19409:22;;19644:52:::3;::::0;19656:7;;19644:52:::3;::::0;;;::::3;19042:665;18770:1302;17846:2232;;;17580:2498:::0;;;;;;:::o;6380:2438:43:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;41750:17:42::2;::::0;-1:-1:-1;;;;;41750:17:42::2;41736:10;:31;41732:93;;41790:24;::::0;-1:-1:-1;;;41790:24:42;;41803:10:::2;41790:24;::::0;::::2;6006:51:80::0;5979:18;;41790:24:42::2;5860:203:80::0;41732:93:42::2;6665:11:43::3;;6654:7;:22;6650:95;;6722:11;::::0;6699:35:::3;::::0;-1:-1:-1;;;6699:35:43;;::::3;::::0;6713:7;;6699:35:::3;;12764:25:80::0;;;12820:2;12805:18;;12798:34;12752:2;12737:18;;12590:248;6650:95:43::3;6836:17;6868:87;6903:21;;6926:7;6935:8;6945:9;6868:34;:87::i;:::-;6836:119:::0;-1:-1:-1;7226:22:43::3;7251:39;4368:77:42;6836:119:43::0;7251:39:::3;:::i;:::-;7407:22;::::0;:48:::3;::::0;-1:-1:-1;;;7407:48:43;;17424:10:80;17412:23;;7407:48:43::3;::::0;::::3;17394:42:80::0;7226:64:43;;-1:-1:-1;7374:30:43::3;::::0;-1:-1:-1;;;;;7407:22:43;;::::3;::::0;:37:::3;::::0;17367:18:80;;7407:48:43::3;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7374:81;;7524:16;-1:-1:-1::0;;;;;7524:28:43::3;;:258;;;;;;;;7567:13;7581:1;7567:16;;;;;;;:::i;:::-;;;;;7524:258;;;;7585:13;7599:1;7585:16;;;;;;;:::i;:::-;;;;;7524:258:::0;;::::3;::::0;;;;;;;7618:16;;::::3;;7524:258:::0;;::::3;::::0;;;;;;;;;7618:13;7650:1:::3;7636:16;;;;7524:258;;::::0;::::3;;;;;;;;;;;;7656:13;7670:1;7656:16;;;;;;;:::i;:::-;;;;;7524:258;;;;7674:13;7688:1;7674:16;;;;;;;:::i;:::-;;;;;7524:258:::0;;;;::::3;::::0;;;;::::3;::::0;;;;7707:13;7721:1:::3;7707:16;;;;7524:258;;;;7725:13;7739:1;7725:16;;;;;;;:::i;:::-;;;;;7524:258;;::::0;::::3;;;;;;;;7757:14;7524:258;;::::0;::::3;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;7524:258:43::3;::::0;;::::3;;::::0;;::::3;-1:-1:-1::0;;7524:258:43::3;::::0;::::3;::::0;;;::::3;::::0;;::::3;::::0;::::3;:::i;:::-;;;7520:1292;;;;:::i;:::-;7902:14;7897:85;;7943:24;;-1:-1:-1::0;;;7943:24:43::3;;;;;;;;;;;7897:85;8150:11;:22:::0;;;8318:20:::3;::::0;;;:11:::3;:20;::::0;;;;:47;;-1:-1:-1;;;;;;8318:47:43::3;8349:15;-1:-1:-1::0;;;;;8318:47:43::3;;::::0;;8150:22;-1:-1:-1;8385:51:43::3;::::0;8397:7;;8385:51:::3;::::0;;;::::3;7783:664;6640:2178;;;6380:2438:::0;;;;;;:::o;3800:152::-;4871:13:22;;3886:1:43;;4871:13:22;;;;;4870:14;:40;;;;-1:-1:-1;4888:12:22;;:22;;;;:12;;:22;4870:40;4862:99;;;;-1:-1:-1;;;4862:99:22;;;;;;;:::i;:::-;4971:12;:22;;3899::43::1;:46:::0;;-1:-1:-1;;;;;;3899:46:43::1;-1:-1:-1::0;;;;;3899:46:43;::::1;;::::0;;-1:-1:-1;;4971:22:22;;;;-1:-1:-1;;5003:20:22;;;;;;5044:21;;;;5080:20;;10228:36:80;;;5080:20:22;;10216:2:80;10201:18;5080:20:22;;;;;;;3800:152:43;;:::o;34738:423:42:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;1334:13:18::2;:11;:13::i;:::-;34954:23:42::3;::::0;;-1:-1:-1;;;;;34987:34:42;;::::3;-1:-1:-1::0;;;;;;34987:34:42;::::3;::::0;::::3;::::0;;;34954:23:::3;::::0;;;35036:118:::3;::::0;11363:685:43;11591:12;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;11663:4:43::2;11657:11;11719:1;11708:9;11704:17;11790:15;11760:28;11747:11;11734:72;11838:33:::0;;::::2;11884:28:::0;;;11949:2:::2;11932:20:::0;;::::2;11925:38:::0;;;;-1:-1:-1;;12011:2:43::2;12007:24:::0;;::::2;11984:48:::0;;;11363:685;-1:-1:-1;;11363:685:43:o;40699:508:42:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;40987:22:42::2;41004:4;40987:16;:22::i;:::-;41075:17;::::0;41181:9:::2;::::0;41075:125:::2;::::0;-1:-1:-1;;;41075:125:42;;-1:-1:-1;;;;;41075:17:42;;::::2;::::0;:29:::2;::::0;:125:::2;::::0;41118:4;;41124:13;;41139:10;;41151:21;;41174:5;;-1:-1:-1;;;41181:9:42;::::2;;;::::0;41075:125:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;3317:197:23::0;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;3400:36:::1;3418:17;3400;:36::i;:::-;3487:12;::::0;;3497:1:::1;3487:12:::0;;;::::1;::::0;::::1;::::0;;;3446:61:::1;::::0;3468:17;;3487:12;3446:21:::1;:61::i;:::-;3317:197:::0;:::o;13806:1014:42:-;4871:13:22;;14060:1:42;;4871:13:22;;;;;4870:14;:40;;;;-1:-1:-1;4888:12:22;;:22;;;;:12;;:22;4870:40;4862:99;;;;-1:-1:-1;;;4862:99:22;;;;;;;:::i;:::-;4971:12;:22;;-1:-1:-1;;5003:20:22;4971:22;;;5003:20;4971:22;5003:20;;;14148:16:42::1;:14;:16::i;:::-;14180:48;14217:10;14180:36;:48::i;:::-;14175:119;;14251:32;::::0;-1:-1:-1;;;14251:32:42;;10258:4:80;10246:17;;14251:32:42::1;::::0;::::1;10228:36:80::0;10201:18;;14251:32:42::1;10086:184:80::0;14175:119:42::1;14361:9;:22:::0;;-1:-1:-1;;;;14361:22:42::1;-1:-1:-1::0;;;14361:22:42::1;::::0;::::1;;;::::0;;14413:7:::1;14393:17;:27:::0;14430:11:::1;:25:::0;;;14465:23:::1;:50:::0;;-1:-1:-1;;;;;;14465:50:42;;::::1;-1:-1:-1::0;;;;;14465:50:42;;::::1;::::0;;;::::1;::::0;;;14525:23:::1;:47:::0;;;::::1;::::0;;::::1;;::::0;;14582:17:::1;:38:::0;;;::::1;::::0;;::::1;;::::0;;1513:6:18;;14630:17:42::1;:27:::0;;1513:6:18;;;;14630:27:42;::::1;;::::0;;14717:18:::1;:16;:18::i;:::-;14751:62;::::0;;18673:4:80;18661:17;;18643:36;;18710:2;18695:18;;18688:34;;;14751:62:42::1;::::0;18616:18:80;14751:62:42::1;;;;;;;5060:5:22::0;5044:21;;-1:-1:-1;;5044:21:22;;;5080:20;;10258:4:80;10246:17;;10228:36;;5080:20:22;;10216:2:80;10201:18;5080:20:22;;;;;;;13806:1014:42;;;;;;:::o;9156:228:43:-;9316:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;9354:22:43::2;::::0;-1:-1:-1;;;;;9354:22:43::2;1144:1:77;9156:228:43::0;:::o;32299:567:42:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;32478:11:42::2;;32470:4;:19:::0;32466:394:::2;;-1:-1:-1::0;;32512:30:42::2;::::0;;::::2;::::0;::::2;::::0;;32521:11:::2;::::0;32512:30;;-1:-1:-1;32512:30:42::2;::::0;::::2;::::0;32537:4:::2;32512:30:::0;;;;;;;;32299:567::o;32466:394::-:2;32573:21;32597:17:::0;;;:11:::2;:17;::::0;;;;;-1:-1:-1;;;;;32597:17:42::2;::::0;32633:18;;;32629:78:::2;;-1:-1:-1::0;;;;;;;;;;;;;;;;;;;;;;;;;;7218:25:42;;;;;;;;;;;;;;;;;;;;32678:14:::2;32671:21:::0;32299:567;-1:-1:-1;;;32299:567:42:o;32629:78::-:2;32772:17;::::0;32721:12:::2;::::0;32738:31:::2;-1:-1:-1::0;;;;;32738:31:42;::::2;:15;:31;:::i;:::-;32811:38;::::0;;::::2;::::0;::::2;::::0;;;;;-1:-1:-1;;;;;32811:38:42;;::::2;;::::0;::::2;::::0;32738:51;-1:-1:-1;32736:54:42::2;32811:38:::0;;;;-1:-1:-1;32811:38:42;-1:-1:-1;32466:394:42::2;32299:567:::0;;;:::o;37747:189::-;37882:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;37912:17:42::2;::::0;37747:189;:::o;3763:222:23:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;3880:36:::1;3898:17;3880;:36::i;:::-;3926:52;3948:17;3967:4;3973;3926:21;:52::i;:::-;3763:222:::0;;:::o;35454:227:42:-;35612:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;35650:23:42::2;::::0;-1:-1:-1;;;;;35650:23:42::2;35454:227:::0;:::o;3006:131:23:-;3084:7;2324:4;-1:-1:-1;;;;;2333:6:23;2316:23;;2308:92;;;;-1:-1:-1;;;2308:92:23;;19165:2:80;2308:92:23;;;19147:21:80;19204:2;19184:18;;;19177:30;19243:34;19223:18;;;19216:62;19314:26;19294:18;;;19287:54;19358:19;;2308:92:23;18963:420:80;2308:92:23;-1:-1:-1;;;;;;;;;;;;3006:131:23;:::o;36071:416:42:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;1334:13:18::2;:11;:13::i;:::-;36283:23:42::3;::::0;;-1:-1:-1;;;;;36316:34:42;;::::3;-1:-1:-1::0;;;;;;36316:34:42;::::3;::::0;::::3;::::0;;;36283:23:::3;::::0;;36396:36:::3;36365:115;::::0;4649:109:44;1334:13:18;:11;:13::i;:::-;4726:25:44::1;;-1:-1:-1::0;;;4726:25:44::1;;;;;;;;;;;2010:206:17::0;1202:13;;929:10:25;;-1:-1:-1;;;;;1202:13:17;2103:24;;2095:78;;;;-1:-1:-1;;;2095:78:17;;19590:2:80;2095:78:17;;;19572:21:80;19629:2;19609:18;;;19602:30;19668:34;19648:18;;;19641:62;-1:-1:-1;;;19719:18:80;;;19712:39;19768:19;;2095:78:17;19388:405:80;2095:78:17;2183:26;2202:6;2183:18;:26::i;31089:465:42:-;31366:12;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;31390:24:42::2;31446:7;31455:8;31465:11;;31478:13;;31493;;31429:78;;;;;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;31429:78:42;;::::2;::::0;;;;;;31525:22;;31429:78:::2;31525:22:::0;;::::2;::::0;;31089:465;-1:-1:-1;;;;;;;;;;31089:465:42:o;29135:413::-;29370:12;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;29394:24:42::2;29450:10;29462:7;29471:8;29481:19;;29433:68;;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;29433:68:42;;::::2;::::0;;;;;;29519:22;;29433:68:::2;29519:22:::0;;::::2;::::0;;29135:413;-1:-1:-1;;;;;;;29135:413:42:o;38714:119::-;38793:5;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;38817:9:42::2;::::0;-1:-1:-1;;;38817:9:42;::::2;;;::::0;38714:119::o;34179:231::-;34341:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;34379:23:42::2;::::0;-1:-1:-1;;;;;34379:23:42::2;34179:231:::0;:::o;39480:384::-;39646:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;1334:13:18::2;:11;:13::i;:::-;39691:17:42::3;::::0;;-1:-1:-1;;;;;39718:39:42;;::::3;-1:-1:-1::0;;;;;;39718:39:42;::::3;::::0;::::3;::::0;;;39772:57:::3;::::0;39691:17;::::3;::::0;39718:39;39691:17;;39772:57:::3;::::0;39669:19:::3;::::0;39772:57:::3;39846:11:::0;39480:384;-1:-1:-1;;39480:384:42:o;9704:418:43:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;1334:13:18::2;:11;:13::i;:::-;9918:22:43::3;::::0;;-1:-1:-1;;;;;9950:33:43;;::::3;-1:-1:-1::0;;;;;;9950:33:43;::::3;::::0;::::3;::::0;;;9918:22:::3;::::0;;10029:38:::3;9998:117;::::0;22820:1590:42;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;41750:17:42::2;::::0;-1:-1:-1;;;;;41750:17:42::2;41736:10;:31;41732:93;;41790:24;::::0;-1:-1:-1;;;41790:24:42;;41803:10:::2;41790:24;::::0;::::2;6006:51:80::0;5979:18;;41790:24:42::2;5860:203:80::0;41732:93:42::2;23154:11:::3;;23143:7;:22;23139:95;;23211:11;::::0;23188:35:::3;::::0;-1:-1:-1;;;23188:35:42;;::::3;::::0;23202:7;;23188:35:::3;;12764:25:80::0;;;12820:2;12805:18;;12798:34;12752:2;12737:18;;12590:248;23139:95:42::3;23322:42:::0;;::::3;;::::0;:88:::3;;-1:-1:-1::0;23368:42:42;;::::3;;23322:88;23305:172;;;23442:24;;-1:-1:-1::0;;;23442:24:42::3;;;;;;;;;;;23305:172;23564:17;23584:116;23630:7;23639:8;23649:11;;23662:13;;23677;;23584:32;:116::i;:::-;23564:136:::0;-1:-1:-1;23971:24:42::3;23998:39;4368:77;23564:136:::0;23998:39:::3;:::i;:::-;24152:23;::::0;:58:::3;::::0;-1:-1:-1;;;24152:58:42;;::::3;::::0;::::3;4125:25:80::0;;;23971:66:42;;-1:-1:-1;24121:28:42::3;::::0;-1:-1:-1;;;;;24152:23:42;;::::3;::::0;:38:::3;::::0;4098:18:80;;24152:58:42::3;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24121:89;;24316:87;24338:14;24354:11;24367:16;24385:7;24394:8;24316:21;:87::i;:::-;23129:1281;;;22820:1590:::0;;;;;;;;;:::o;38168:402::-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;1334:13:18::2;:11;:13::i;:::-;38330::42::3;38347:1;38330:18:::0;38326:86:::3;;38364:37;::::0;-1:-1:-1;;;38364:37:42;;21716:2:80;38364:37:42::3;::::0;::::3;21698:21:80::0;21755:2;21735:18;;;21728:30;21794:29;21774:18;;;21767:57;21841:18;;38364:37:42::3;21514:351:80::0;38326:86:42::3;38441:17;::::0;;38468:33;;;;38517:46:::3;::::0;38488:13;;38441:17;;38517:46:::3;::::0;38421:17:::3;::::0;38517:46:::3;38316:254;38168:402:::0;:::o;31682:121::-;31759:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;31785:11:42::2;::::0;31682:121;:::o;39054:133::-;39137:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;39163:17:42::2;::::0;-1:-1:-1;;;;;39163:17:42::2;39054:133:::0;:::o;36670:205::-;36812:7;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;-1:-1:-1::0;36850:17:42::2;::::0;-1:-1:-1;;;;;36850:17:42::2;36670:205:::0;:::o;33309:638::-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;33461:11:42::2;::::0;33449:56;;33488:7:::2;33449:56;33580:21;33604:17:::0;;;:11:::2;:17;::::0;;;;;-1:-1:-1;;;;;33604:17:42::2;::::0;33704:18;;;33700:73:::2;;33745:17;;-1:-1:-1::0;;;33745:17:42::2;;;;;;;;;;;33700:73;33877:17;::::0;33843:31:::2;-1:-1:-1::0;;;;;33843:31:42;::::2;:15;:31;:::i;:::-;:51;33839:102;;;33917:13;;-1:-1:-1::0;;;33917:13:42::2;;;;;;;;;;;1415:178:17::0;1334:13:18;:11;:13::i;:::-;1504::17::1;:24:::0;;-1:-1:-1;;;;;1504:24:17;::::1;-1:-1:-1::0;;;;;;1504:24:17;;::::1;::::0;::::1;::::0;;;1568:7:::1;1513:6:18::0;;-1:-1:-1;;;;;1513:6:18;;1441:85;1568:7:17::1;-1:-1:-1::0;;;;;1543:43:17::1;;;;;;;;;;;1415:178:::0;:::o;1563:151:20:-;-1:-1:-1;;;;;;;;;;;1642:65:20;-1:-1:-1;;;;;1642:65:20;;1563:151::o;1599:130:18:-;1513:6;;-1:-1:-1;;;;;1513:6:18;929:10:25;1662:23:18;1654:68;;;;-1:-1:-1;;;1654:68:18;;22072:2:80;1654:68:18;;;22054:21:80;;;22091:18;;;22084:30;22150:34;22130:18;;;22123:62;22202:18;;1654:68:18;21870:356:80;1654:68:18;1599:130::o;4067:204:44:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1334:13:18::1;:11;:13::i;2938:974:20:-:0;951:66;3384:59;;;3380:526;;;3459:37;3478:17;3459:18;:37::i;:::-;2938:974;;;:::o;3380:526::-;3560:17;-1:-1:-1;;;;;3531:61:20;;:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3531:63:20;;;;;;;;-1:-1:-1;;3531:63:20;;;;;;;;;;;;:::i;:::-;;;3527:302;;3758:56;;-1:-1:-1;;;3758:56:20;;22622:2:80;3758:56:20;;;22604:21:80;22661:2;22641:18;;;22634:30;22700:34;22680:18;;;22673:62;-1:-1:-1;;;22751:18:80;;;22744:44;22805:19;;3758:56:20;22420:410:80;3527:302:20;-1:-1:-1;;;;;;;;;;;3644:28:20;;3636:82;;;;-1:-1:-1;;;3636:82:20;;23037:2:80;3636:82:20;;;23019:21:80;23076:2;23056:18;;;23049:30;23115:34;23095:18;;;23088:62;-1:-1:-1;;;23166:18:80;;;23159:39;23215:19;;3636:82:20;22835:405:80;3636:82:20;3595:138;3842:53;3860:17;3879:4;3885:9;3842:17;:53::i;15154:97:42:-;5363:13:22;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:22;;;;;;;:::i;:::-;15224:20:42::1;:18;:20::i;434:207:78:-:0;492:19;540:2;569;588:21;;;;-1:-1:-1;588:21:78;;;:46;;;626:8;613:21;;:9;:21;;;;588:46;581:53;434:207;-1:-1:-1;;;;434:207:78:o;794:90:77:-;5363:13:22;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:22;;;;;;;:::i;:::-;858:12:77::1;:19:::0;;-1:-1:-1;;858:19:77::1;873:4;858:19;::::0;;794:90::o;1777:153:17:-;1866:13;1859:20;;-1:-1:-1;;;;;;1859:20:17;;;1889:34;1914:8;1889:24;:34::i;26242:1763:42:-;-1:-1:-1;;;;;1898:6:23;1881:23;1889:4;1881:23;1873:80;;;;-1:-1:-1;;;1873:80:23;;;;;;;:::i;:::-;1995:6;-1:-1:-1;;;;;1971:30:23;:20;:18;:20::i;:::-;-1:-1:-1;;;;;1971:30:23;;1963:87;;;;-1:-1:-1;;;1963:87:23;;;;;;;:::i;:::-;1059:12:77::1;::::0;::::1;;1054:81;;1094:30;;-1:-1:-1::0;;;1094:30:77::1;;;;;;;;;;;1054:81;41750:17:42::2;::::0;-1:-1:-1;;;;;41750:17:42::2;41736:10;:31;41732:93;;41790:24;::::0;-1:-1:-1;;;41790:24:42;;41803:10:::2;41790:24;::::0;::::2;6006:51:80::0;5979:18;;41790:24:42::2;5860:203:80::0;41732:93:42::2;26566:20:::3;:55;;;;;;;;26590:11;26602:1;26590:14;;;;;;;:::i;:::-;;;;;26566:55;;;;26606:11;26618:1;26606:14;;;;;;;:::i;:::-;;;;;26566:55:::0;;26631:106:::3;::::0;;;;;;;26671:14;;::::3;;26631:106:::0;;::::3;::::0;;;26566:55;;-1:-1:-1;;;26631:106:42;;;;;;26671:11;26699:1:::3;26687:14;;;;26631:106;;::::0;::::3;;;;;;;;;;;;26705:11;26717:1;26705:14;;;;;;;:::i;:::-;;;;;26631:106;;;;26721:11;26733:1;26721:14;;;;;;;:::i;:::-;;;;;26631:106:::0;;;;26747:56:::3;::::0;;;;::::3;::::0;;;26631:106;;-1:-1:-1;26747:21:42::3;::::0;:56;26772:11;26784:1:::3;26772:14;;;;26747:56;;;;26788:11;26800:1;26788:14;;;;;;;:::i;:::-;;;;;26747:56;;::::0;::::3;;26813:28;:42;;;;;;;;26845:9;26813:42;;::::0;::::3;;26920:14;-1:-1:-1::0;;;;;26920:26:42::3;;26947:2;26951;26955:3;26960:10;26920:51;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;26920:51:42::3;::::0;;::::3;;::::0;;::::3;-1:-1:-1::0;;26920:51:42::3;::::0;::::3;::::0;;;::::3;::::0;;::::3;::::0;::::3;:::i;:::-;;;26916:1083;;;;:::i;:::-;27091:14;27086:85;;27132:24;;-1:-1:-1::0;;;27132:24:42::3;;;;;;;;;;;27086:85;27339:11;:22:::0;;;27507:20:::3;::::0;;;:11:::3;:20;::::0;;;;:47;;-1:-1:-1;;;;;;27507:47:42::3;27538:15;-1:-1:-1::0;;;;;27507:47:42::3;;::::0;;27339:22;27595:17:::3;27574:49;::::0;27586:7;;27574:49:::3;::::0;;;::::3;26972:662;26500:1505;;;;26242:1763:::0;;;;;:::o;1805:281:20:-;-1:-1:-1;;;;;1476:19:24;;;1878:106:20;;;;-1:-1:-1;;;1878:106:20;;23859:2:80;1878:106:20;;;23841:21:80;23898:2;23878:18;;;23871:30;23937:34;23917:18;;;23910:62;-1:-1:-1;;;23988:18:80;;;23981:43;24041:19;;1878:106:20;23657:409:80;1878:106:20;-1:-1:-1;;;;;;;;;;;1994:85:20;;-1:-1:-1;;;;;;1994:85:20;-1:-1:-1;;;;;1994:85:20;;;;;;;;;;1805:281::o;2478:288::-;2616:29;2627:17;2616:10;:29::i;:::-;2673:1;2659:4;:11;:15;:28;;;;2678:9;2659:28;2655:105;;;2703:46;2725:17;2744:4;2703:21;:46::i;:::-;;2478:288;;;:::o;3048:131:44:-;5363:13:22;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:22;;;;;;;:::i;:::-;3122:16:44::1;:14;:16::i;:::-;3148:24;:22;:24::i;2673:187:18:-:0;2765:6;;;-1:-1:-1;;;;;2781:17:18;;;-1:-1:-1;;;;;;2781:17:18;;;;;;;2813:40;;2765:6;;;2781:17;2765:6;;2813:40;;2746:16;;2813:40;2736:124;2673:187;:::o;2192:152:20:-;2258:37;2277:17;2258:18;:37::i;:::-;2310:27;;-1:-1:-1;;;;;2310:27:20;;;;;;;;2192:152;:::o;7088:455::-;7171:12;-1:-1:-1;;;;;1476:19:24;;;7195:88:20;;;;-1:-1:-1;;;7195:88:20;;24273:2:80;7195:88:20;;;24255:21:80;24312:2;24292:18;;;24285:30;24351:34;24331:18;;;24324:62;-1:-1:-1;;;24402:18:80;;;24395:36;24448:19;;7195:88:20;24071:402:80;7195:88:20;7354:12;7368:23;7395:6;-1:-1:-1;;;;;7395:19:20;7415:4;7395:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7353:67;;;;7437:99;7473:7;7482:10;7437:99;;;;;;;;;;;;;;;;;:35;:99::i;:::-;7430:106;;;;7088:455;;;;;:::o;1003:95:18:-;5363:13:22;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:22;;;;;;;:::i;:::-;1065:26:18::1;:24;:26::i;1042:67:23:-:0;5363:13:22;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:22;;;;;;;:::i;7438:295:24:-;7584:12;7612:7;7608:119;;;-1:-1:-1;7642:10:24;7635:17;;7608:119;7683:33;7691:10;7703:12;7683:7;:33::i;1104:111:18:-;5363:13:22;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:22;;;;;;;:::i;:::-;1176:32:18::1;929:10:25::0;1176:18:18::1;:32::i;7739:540:24:-:0;7898:17;;:21;7894:379;;8126:10;8120:17;8182:15;8169:10;8165:2;8161:19;8154:44;14:151:80;-1:-1:-1;;;;;109:31:80;;99:42;;89:70;;155:1;152;145:12;170:295;257:6;310:2;298:9;289:7;285:23;281:32;278:52;;;326:1;323;316:12;278:52;365:9;352:23;384:51;429:5;384:51;:::i;470:160::-;564:6;597:3;585:16;;582:25;-1:-1:-1;579:45:80;;;620:1;617;610:12;635:163;702:20;;762:10;751:22;;741:33;;731:61;;788:1;785;778:12;803:367;866:8;876:6;930:3;923:4;915:6;911:17;907:27;897:55;;948:1;945;938:12;897:55;-1:-1:-1;971:20:80;;1014:18;1003:30;;1000:50;;;1046:1;1043;1036:12;1000:50;1083:4;1075:6;1071:17;1059:29;;1143:3;1136:4;1126:6;1123:1;1119:14;1111:6;1107:27;1103:38;1100:47;1097:67;;;1160:1;1157;1150:12;1097:67;803:367;;;;;:::o;1175:773::-;1321:6;1329;1337;1345;1353;1361;1414:3;1402:9;1393:7;1389:23;1385:33;1382:53;;;1431:1;1428;1421:12;1382:53;1454;1499:7;1488:9;1454:53;:::i;:::-;1444:63;;1554:3;1543:9;1539:19;1526:33;1516:43;;1578:38;1611:3;1600:9;1596:19;1578:38;:::i;:::-;1568:48;;1667:3;1656:9;1652:19;1639:33;1695:18;1687:6;1684:30;1681:50;;;1727:1;1724;1717:12;1681:50;1766:70;1828:7;1819:6;1808:9;1804:22;1766:70;:::i;:::-;1175:773;;;;-1:-1:-1;1175:773:80;;;;;1937:3;1922:19;;;1909:33;;1175:773;-1:-1:-1;;;;1175:773:80:o;1953:347::-;2004:8;2014:6;2068:3;2061:4;2053:6;2049:17;2045:27;2035:55;;2086:1;2083;2076:12;2035:55;-1:-1:-1;2109:20:80;;2152:18;2141:30;;2138:50;;;2184:1;2181;2174:12;2138:50;2221:4;2213:6;2209:17;2197:29;;2273:3;2266:4;2257:6;2249;2245:19;2241:30;2238:39;2235:59;;;2290:1;2287;2280:12;2305:745;2435:6;2443;2451;2459;2467;2475;2528:3;2516:9;2507:7;2503:23;2499:33;2496:53;;;2545:1;2542;2535:12;2496:53;2568;2613:7;2602:9;2568:53;:::i;:::-;2558:63;;2640:38;2673:3;2662:9;2658:19;2640:38;:::i;:::-;2630:48;;2729:3;2718:9;2714:19;2701:33;2757:18;2749:6;2746:30;2743:50;;;2789:1;2786;2779:12;2743:50;2828:58;2878:7;2869:6;2858:9;2854:22;2828:58;:::i;:::-;2305:745;;;;-1:-1:-1;2905:8:80;2987:3;2972:19;;2959:33;;3039:3;3024:19;;;3011:33;;-1:-1:-1;2305:745:80;-1:-1:-1;;;;2305:745:80:o;3356:618::-;3452:6;3460;3468;3476;3484;3537:3;3525:9;3516:7;3512:23;3508:33;3505:53;;;3554:1;3551;3544:12;3505:53;3594:9;3581:23;3627:18;3619:6;3616:30;3613:50;;;3659:1;3656;3649:12;3613:50;3698:58;3748:7;3739:6;3728:9;3724:22;3698:58;:::i;:::-;3775:8;;-1:-1:-1;3672:84:80;-1:-1:-1;;3857:2:80;3842:18;;3829:32;;-1:-1:-1;3908:2:80;3893:18;;3880:32;;-1:-1:-1;3931:37:80;3964:2;3949:18;;3931:37;:::i;:::-;3921:47;;3356:618;;;;;;;;:::o;4161:509::-;4281:6;4289;4297;4305;4313;4366:3;4354:9;4345:7;4341:23;4337:33;4334:53;;;4383:1;4380;4373:12;4334:53;4419:9;4406:23;4396:33;;4476:2;4465:9;4461:18;4448:32;4438:42;;4527:2;4516:9;4512:18;4499:32;4489:42;;4578:2;4567:9;4563:18;4550:32;4540:42;;4601:63;4656:7;4650:3;4639:9;4635:19;4601:63;:::i;4947:908::-;5126:6;5134;5142;5150;5158;5211:3;5199:9;5190:7;5186:23;5182:33;5179:53;;;5228:1;5225;5218:12;5179:53;5267:9;5254:23;5317:4;5310:5;5306:16;5299:5;5296:27;5286:55;;5337:1;5334;5327:12;5286:55;5360:5;-1:-1:-1;5412:2:80;5397:18;;5384:32;;-1:-1:-1;5468:2:80;5453:18;;5440:32;5481:53;5440:32;5481:53;:::i;:::-;5553:7;-1:-1:-1;5612:2:80;5597:18;;5584:32;5625:53;5584:32;5625:53;:::i;:::-;5697:7;-1:-1:-1;5756:3:80;5741:19;;5728:33;5770:53;5728:33;5770:53;:::i;:::-;5842:7;5832:17;;;4947:908;;;;;;;;:::o;6068:180::-;6127:6;6180:2;6168:9;6159:7;6155:23;6151:32;6148:52;;;6196:1;6193;6186:12;6148:52;-1:-1:-1;6219:23:80;;6068:180;-1:-1:-1;6068:180:80:o;6861:127::-;6922:10;6917:3;6913:20;6910:1;6903:31;6953:4;6950:1;6943:15;6977:4;6974:1;6967:15;6993:249;7103:2;7084:13;;-1:-1:-1;;7080:27:80;7068:40;;7138:18;7123:34;;7159:22;;;7120:62;7117:88;;;7185:18;;:::i;:::-;7221:2;7214:22;-1:-1:-1;;6993:249:80:o;7247:953::-;7324:6;7332;7385:2;7373:9;7364:7;7360:23;7356:32;7353:52;;;7401:1;7398;7391:12;7353:52;7440:9;7427:23;7459:51;7504:5;7459:51;:::i;:::-;7529:5;-1:-1:-1;7553:2:80;7591:18;;;7578:32;7629:18;7659:14;;;7656:34;;;7686:1;7683;7676:12;7656:34;7724:6;7713:9;7709:22;7699:32;;7769:7;7762:4;7758:2;7754:13;7750:27;7740:55;;7791:1;7788;7781:12;7740:55;7827:2;7814:16;7849:2;7845;7842:10;7839:36;;;7855:18;;:::i;:::-;7904:2;7898:9;;-1:-1:-1;7916:65:80;7971:2;7952:13;;-1:-1:-1;;7948:27:80;7944:36;;7898:9;7916:65;:::i;:::-;8005:2;7997:6;7990:18;8045:7;8040:2;8035;8031;8027:11;8023:20;8020:33;8017:53;;;8066:1;8063;8056:12;8017:53;8122:2;8117;8113;8109:11;8104:2;8096:6;8092:15;8079:46;8167:1;8162:2;8157;8149:6;8145:15;8141:24;8134:35;;8188:6;8178:16;;;;;7247:953;;;;;:::o;8205:1225::-;8380:6;8388;8396;8404;8412;8420;8428;8436;8489:3;8477:9;8468:7;8464:23;8460:33;8457:53;;;8506:1;8503;8496:12;8457:53;8542:9;8529:23;8519:33;;8599:2;8588:9;8584:18;8571:32;8561:42;;8654:2;8643:9;8639:18;8626:32;8677:18;8718:2;8710:6;8707:14;8704:34;;;8734:1;8731;8724:12;8704:34;8773:70;8835:7;8826:6;8815:9;8811:22;8773:70;:::i;:::-;8862:8;;-1:-1:-1;8747:96:80;-1:-1:-1;8950:2:80;8935:18;;8922:32;;-1:-1:-1;8966:16:80;;;8963:36;;;8995:1;8992;8985:12;8963:36;9034:72;9098:7;9087:8;9076:9;9072:24;9034:72;:::i;:::-;9125:8;;-1:-1:-1;9008:98:80;-1:-1:-1;9213:3:80;9198:19;;9185:33;;-1:-1:-1;9230:16:80;;;9227:36;;;9259:1;9256;9249:12;9227:36;;9298:72;9362:7;9351:8;9340:9;9336:24;9298:72;:::i;:::-;8205:1225;;;;-1:-1:-1;8205:1225:80;;-1:-1:-1;8205:1225:80;;;;;;9389:8;-1:-1:-1;;;8205:1225:80:o;9435:646::-;9547:6;9555;9563;9571;9579;9632:3;9620:9;9611:7;9607:23;9603:33;9600:53;;;9649:1;9646;9639:12;9600:53;9672:28;9690:9;9672:28;:::i;:::-;9662:38;;9747:2;9736:9;9732:18;9719:32;9709:42;;9798:2;9787:9;9783:18;9770:32;9760:42;;9853:2;9842:9;9838:18;9825:32;9880:18;9872:6;9869:30;9866:50;;;9912:1;9909;9902:12;9866:50;9951:70;10013:7;10004:6;9993:9;9989:22;9951:70;:::i;:::-;9435:646;;;;-1:-1:-1;9435:646:80;;-1:-1:-1;10040:8:80;;9925:96;9435:646;-1:-1:-1;;;9435:646:80:o;10275:1352::-;10484:6;10492;10500;10508;10516;10524;10532;10540;10548;10601:3;10589:9;10580:7;10576:23;10572:33;10569:53;;;10618:1;10615;10608:12;10569:53;10641;10686:7;10675:9;10641:53;:::i;:::-;10631:63;;10741:3;10730:9;10726:19;10713:33;10703:43;;10797:3;10786:9;10782:19;10769:33;10821:18;10862:2;10854:6;10851:14;10848:34;;;10878:1;10875;10868:12;10848:34;10917:70;10979:7;10970:6;10959:9;10955:22;10917:70;:::i;:::-;11006:8;;-1:-1:-1;10891:96:80;-1:-1:-1;11094:3:80;11079:19;;11066:33;;-1:-1:-1;11111:16:80;;;11108:36;;;11140:1;11137;11130:12;11108:36;11179:72;11243:7;11232:8;11221:9;11217:24;11179:72;:::i;:::-;11270:8;;-1:-1:-1;11153:98:80;-1:-1:-1;11358:3:80;11343:19;;11330:33;;-1:-1:-1;11375:16:80;;;11372:36;;;11404:1;11401;11394:12;11372:36;;11443:72;11507:7;11496:8;11485:9;11481:24;11443:72;:::i;:::-;10275:1352;;;;-1:-1:-1;10275:1352:80;;;;;;;;11534:8;11616:3;11601:19;11588:33;;10275:1352;-1:-1:-1;;;;10275:1352:80:o;11632:408::-;11834:2;11816:21;;;11873:2;11853:18;;;11846:30;11912:34;11907:2;11892:18;;11885:62;-1:-1:-1;;;11978:2:80;11963:18;;11956:42;12030:3;12015:19;;11632:408::o;12045:::-;12247:2;12229:21;;;12286:2;12266:18;;;12259:30;12325:34;12320:2;12305:18;;12298:62;-1:-1:-1;;;12391:2:80;12376:18;;12369:42;12443:3;12428:19;;12045:408::o;12843:209::-;12875:1;12901;12891:132;;12945:10;12940:3;12936:20;12933:1;12926:31;12980:4;12977:1;12970:15;13008:4;13005:1;12998:15;12891:132;-1:-1:-1;13037:9:80;;12843:209::o;13057:294::-;13150:6;13203:2;13191:9;13182:7;13178:23;13174:32;13171:52;;;13219:1;13216;13209:12;13171:52;13251:9;13245:16;13270:51;13315:5;13270:51;:::i;13356:127::-;13417:10;13412:3;13408:20;13405:1;13398:31;13448:4;13445:1;13438:15;13472:4;13469:1;13462:15;13488:326;13581:5;13604:1;13614:194;13628:4;13625:1;13622:11;13614:194;;;13687:13;;13675:26;;13724:4;13748:12;;;;13783:15;;;;13648:1;13641:9;13614:194;;13819:1627;14267:3;14252:19;;14280:43;14256:9;14305:6;14280:43;:::i;:::-;14342:2;14379;14368:9;14364:18;14424:6;14448:1;14458:586;14522:4;14555:2;14552:1;14549:9;14539:30;;14562:5;;;14539:30;14592:13;;14631:3;14714:1;14728:234;14744:2;14739:3;14736:11;14728:234;;;14815:15;;14801:30;;14858:4;14931:17;;;;14888:14;;;;14766:1;14757:11;14728:234;;;-1:-1:-1;;;14982:12:80;;;;-1:-1:-1;15029:4:80;15017:17;;;;;14485:1;14478:9;14458:586;;;14462:3;;;;15053:53;15101:3;15090:9;15086:19;15078:6;15053:53;:::i;:::-;15143:3;15132:9;15128:19;15195:6;15221:1;15231:209;15247:1;15242:3;15239:10;15231:209;;;15309:15;;15295:30;;15348:4;15374:14;;;;15413:17;;;;15268:1;15259:11;15231:209;;;15235:3;;;13819:1627;;;;;;;:::o;15451:277::-;15518:6;15571:2;15559:9;15550:7;15546:23;15542:32;15539:52;;;15587:1;15584;15577:12;15539:52;15619:9;15613:16;15672:5;15665:13;15658:21;15651:5;15648:32;15638:60;;15694:1;15691;15684:12;15733:179;15768:3;15810:1;15792:16;15789:23;15786:120;;;15856:1;15853;15850;15835:23;-1:-1:-1;15893:1:80;15887:8;15882:3;15878:18;15733:179;:::o;15917:671::-;15956:3;15998:4;15980:16;15977:26;15974:39;;;15917:671;:::o;15974:39::-;16040:2;16034:9;-1:-1:-1;;16105:16:80;16101:25;;16098:1;16034:9;16077:50;16156:4;16150:11;16180:16;16215:18;16286:2;16279:4;16271:6;16267:17;16264:25;16259:2;16251:6;16248:14;16245:45;16242:58;;;16293:5;;;;;15917:671;:::o;16242:58::-;16330:6;16324:4;16320:17;16309:28;;16366:3;16360:10;16393:2;16385:6;16382:14;16379:27;;;16399:5;;;;;;15917:671;:::o;16379:27::-;16483:2;16464:16;16458:4;16454:27;16450:36;16443:4;16434:6;16429:3;16425:16;16421:27;16418:69;16415:82;;;16490:5;;;;;;15917:671;:::o;16415:82::-;16506:57;16557:4;16548:6;16540;16536:19;16532:30;16526:4;16506:57;:::i;:::-;-1:-1:-1;16579:3:80;;15917:671;-1:-1:-1;;;;;15917:671:80:o;16593:250::-;16678:1;16688:113;16702:6;16699:1;16696:13;16688:113;;;16778:11;;;16772:18;16759:11;;;16752:39;16724:2;16717:10;16688:113;;;-1:-1:-1;;16835:1:80;16817:16;;16810:27;16593:250::o;16848:396::-;16997:2;16986:9;16979:21;16960:4;17029:6;17023:13;17072:6;17067:2;17056:9;17052:18;17045:34;17088:79;17160:6;17155:2;17144:9;17140:18;17135:2;17127:6;17123:15;17088:79;:::i;:::-;17228:2;17207:15;-1:-1:-1;;17203:29:80;17188:45;;;;17235:2;17184:54;;16848:396;-1:-1:-1;;16848:396:80:o;17447:410::-;17649:2;17631:21;;;17688:2;17668:18;;;17661:30;17727:34;17722:2;17707:18;;17700:62;-1:-1:-1;;;17793:2:80;17778:18;;17771:44;17847:3;17832:19;;17447:410::o;17862:606::-;18140:4;18182:3;18171:9;18167:19;18159:27;;18213:6;18202:9;18195:25;18256:6;18251:2;18240:9;18236:18;18229:34;18299:6;18294:2;18283:9;18279:18;18272:34;18342:6;18337:2;18326:9;18322:18;18315:34;18400:6;18392;18386:3;18375:9;18371:19;18358:49;18456:4;18448:6;18444:17;18438:3;18427:9;18423:19;18416:46;17862:606;;;;;;;;;:::o;18733:225::-;18800:9;;;18821:11;;;18818:134;;;18874:10;18869:3;18865:20;18862:1;18855:31;18909:4;18906:1;18899:15;18937:4;18934:1;18927:15;19798:261;19868:3;-1:-1:-1;;;;;19889:31:80;;19886:51;;;19933:1;19930;19923:12;19886:51;19969:6;19966:1;19962:14;20010:8;20003:5;19998:3;19985:34;20035:18;;;;;19798:261;-1:-1:-1;;;19798:261:80:o;20064:951::-;20495:6;20490:3;20483:19;20465:3;20521:2;20553:6;20548:2;20543:3;20539:12;20532:28;20591:2;20586:3;20582:12;20640:6;20664:1;20674:204;20688:6;20685:1;20682:13;20674:204;;;20782:10;20755:25;20773:6;20755:25;:::i;:::-;20751:42;20737:57;;20816:14;;;;20853:15;;;;20710:1;20703:9;20674:204;;;20678:3;;20894:115;20948:60;21002:5;20994:6;20986;20948:60;:::i;:::-;20940:6;20932;20894:115;:::i;:::-;20887:122;20064:951;-1:-1:-1;;;;;;;;;;;;20064:951:80:o;21020:489::-;21334:10;21329:3;21325:20;21316:6;21311:3;21307:16;21303:43;21298:3;21291:56;21376:6;21372:1;21367:3;21363:11;21356:27;21413:6;21408:2;21403:3;21399:12;21392:28;21273:3;21436:67;21499:2;21494:3;21490:12;21482:6;21474;21436:67;:::i;:::-;21429:74;21020:489;-1:-1:-1;;;;;;;21020:489:80:o;22231:184::-;22301:6;22354:2;22342:9;22333:7;22329:23;22325:32;22322:52;;;22370:1;22367;22360:12;22322:52;-1:-1:-1;22393:16:80;;22231:184;-1:-1:-1;22231:184:80:o;23245:407::-;23447:2;23429:21;;;23486:2;23466:18;;;23459:30;23525:34;23520:2;23505:18;;23498:62;-1:-1:-1;;;23591:2:80;23576:18;;23569:41;23642:3;23627:19;;23245:407::o;24478:287::-;24607:3;24645:6;24639:13;24661:66;24720:6;24715:3;24708:4;24700:6;24696:17;24661:66;:::i;:::-;24743:16;;;;;24478:287;-1:-1:-1;;24478:287:80:o", + "linkReferences": {}, + "immutableReferences": { + "29832": [ + { + "start": 1614, + "length": 32 + }, + { + "start": 1687, + "length": 32 + }, + { + "start": 1909, + "length": 32 + }, + { + "start": 1973, + "length": 32 + }, + { + "start": 2957, + "length": 32 + }, + { + "start": 3021, + "length": 32 + }, + { + "start": 4100, + "length": 32 + }, + { + "start": 4164, + "length": 32 + }, + { + "start": 4347, + "length": 32 + }, + { + "start": 4411, + "length": 32 + }, + { + "start": 4583, + "length": 32 + }, + { + "start": 4647, + "length": 32 + }, + { + "start": 4903, + "length": 32 + }, + { + "start": 4967, + "length": 32 + }, + { + "start": 5495, + "length": 32 + }, + { + "start": 5559, + "length": 32 + }, + { + "start": 5737, + "length": 32 + }, + { + "start": 5801, + "length": 32 + }, + { + "start": 6143, + "length": 32 + }, + { + "start": 6207, + "length": 32 + }, + { + "start": 6346, + "length": 32 + }, + { + "start": 6410, + "length": 32 + }, + { + "start": 6533, + "length": 32 + }, + { + "start": 6597, + "length": 32 + }, + { + "start": 6748, + "length": 32 + }, + { + "start": 6924, + "length": 32 + }, + { + "start": 6988, + "length": 32 + }, + { + "start": 7323, + "length": 32 + }, + { + "start": 7387, + "length": 32 + }, + { + "start": 7591, + "length": 32 + }, + { + "start": 7655, + "length": 32 + }, + { + "start": 7850, + "length": 32 + }, + { + "start": 7914, + "length": 32 + }, + { + "start": 8065, + "length": 32 + }, + { + "start": 8129, + "length": 32 + }, + { + "start": 8279, + "length": 32 + }, + { + "start": 8343, + "length": 32 + }, + { + "start": 8567, + "length": 32 + }, + { + "start": 8631, + "length": 32 + }, + { + "start": 8812, + "length": 32 + }, + { + "start": 8876, + "length": 32 + }, + { + "start": 9357, + "length": 32 + }, + { + "start": 9421, + "length": 32 + }, + { + "start": 9700, + "length": 32 + }, + { + "start": 9764, + "length": 32 + }, + { + "start": 9905, + "length": 32 + }, + { + "start": 9969, + "length": 32 + }, + { + "start": 10119, + "length": 32 + }, + { + "start": 10183, + "length": 32 + }, + { + "start": 10331, + "length": 32 + }, + { + "start": 10395, + "length": 32 + }, + { + "start": 10881, + "length": 32 + }, + { + "start": 10945, + "length": 32 + }, + { + "start": 11582, + "length": 32 + }, + { + "start": 11646, + "length": 32 + } + ] + } + }, + "methodIdentifiers": { + "NO_SUCH_ROOT()": "561f204b", + "acceptOwnership()": "79ba5097", + "calculateIdentityDeletionInputHash(bytes,uint256,uint256,uint32)": "31e4e992", + "calculateIdentityRegistrationInputHash(uint32,uint256,uint256,uint256[])": "8c76a909", + "calculateIdentityUpdateInputHash(uint256,uint256,uint32[],uint256[],uint256[])": "86ec599a", + "deleteIdentities(uint256[8],uint32,bytes,uint256,uint256)": "23cfdba5", + "getDeleteIdentitiesVerifierLookupTableAddress()": "3e8919b6", + "getIdentityUpdateVerifierLookupTableAddress()": "4ffbdde5", + "getRegisterIdentitiesVerifierLookupTableAddress()": "8fc22e9f", + "getRootHistoryExpiry()": "43f974cb", + "getSemaphoreVerifierAddress()": "f2038f95", + "getTreeDepth()": "8e5cdd50", + "identityOperator()": "f134b6ca", + "initialize(uint8,uint256,address,address,address)": "38c87065", + "initializeV2(address)": "29b6eca9", + "latestRoot()": "d7b0fef1", + "owner()": "8da5cb5b", + "pendingOwner()": "e30c3978", + "proxiableUUID()": "52d1902d", + "queryRoot(uint256)": "3f7c178d", + "registerIdentities(uint256[8],uint256,uint32,uint256[],uint256)": "2217b211", + "renounceOwnership()": "715018a6", + "requireValidRoot(uint256)": "f2358e1d", + "setDeleteIdentitiesVerifierLookupTable(address)": "aa4a729e", + "setIdentityOperator(address)": "a7bba582", + "setIdentityUpdateVerifierLookupTable(address)": "6b056600", + "setRegisterIdentitiesVerifierLookupTable(address)": "2f059fca", + "setRootHistoryExpiry(uint256)": "c70aa727", + "setSemaphoreVerifier(address)": "0e3a12f3", + "transferOwnership(address)": "f2fde38b", + "updateIdentities(uint256[8],uint256,uint32[],uint256[],uint256[],uint256)": "b843b4e5", + "upgradeTo(address)": "3659cfe6", + "upgradeToAndCall(address,bytes)": "4f1ef286", + "verifyProof(uint256,uint256,uint256,uint256,uint256[8])": "354ca120" + }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.21+commit.d9974bed\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"CannotRenounceOwnership\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExpiredRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ImplementationNotInitialized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"InvalidCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidStateBridgeAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MismatchedInputLengths\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonExistentRoot\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"providedRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"latestRoot\",\"type\":\"uint256\"}],\"name\":\"NotLatestRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProofValidationFailure\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StateBridgeAlreadyDisabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StateBridgeAlreadyEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enum WorldIDIdentityManagerImplV1.UnreducedElementType\",\"name\":\"elementType\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"element\",\"type\":\"uint256\"}],\"name\":\"UnreducedElement\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"depth\",\"type\":\"uint8\"}],\"name\":\"UnsupportedTreeDepth\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"enum WorldIDIdentityManagerImplV1.Dependency\",\"name\":\"kind\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddress\",\"type\":\"address\"}],\"name\":\"DependencyUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOperator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOperator\",\"type\":\"address\"}],\"name\":\"IdentityOperatorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"oldExpiryTime\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"newExpiryTime\",\"type\":\"uint256\"}],\"name\":\"RootHistoryExpirySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"name\":\"StateBridgeStateChange\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"enum WorldIDIdentityManagerImplV1.TreeChange\",\"name\":\"kind\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"}],\"name\":\"TreeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"_treeDepth\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialRoot\",\"type\":\"uint256\"}],\"name\":\"WorldIDIdentityManagerImplInitialized\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"NO_SUCH_ROOT\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"supersededTimestamp\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isValid\",\"type\":\"bool\"}],\"internalType\":\"struct WorldIDIdentityManagerImplV1.RootInfo\",\"name\":\"rootInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"packedDeletionIndices\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"batchSize\",\"type\":\"uint32\"}],\"name\":\"calculateIdentityDeletionInputHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"startIndex\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"identityCommitments\",\"type\":\"uint256[]\"}],\"name\":\"calculateIdentityRegistrationInputHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"leafIndices\",\"type\":\"uint32[]\"},{\"internalType\":\"uint256[]\",\"name\":\"oldIdentities\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"newIdentities\",\"type\":\"uint256[]\"}],\"name\":\"calculateIdentityUpdateInputHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[8]\",\"name\":\"deletionProof\",\"type\":\"uint256[8]\"},{\"internalType\":\"uint32\",\"name\":\"batchSize\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"packedDeletionIndices\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"}],\"name\":\"deleteIdentities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDeleteIdentitiesVerifierLookupTableAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getIdentityUpdateVerifierLookupTableAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegisterIdentitiesVerifierLookupTableAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRootHistoryExpiry\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSemaphoreVerifierAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTreeDepth\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"identityOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_treeDepth\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"initialRoot\",\"type\":\"uint256\"},{\"internalType\":\"contract VerifierLookupTable\",\"name\":\"_batchInsertionVerifiers\",\"type\":\"address\"},{\"internalType\":\"contract VerifierLookupTable\",\"name\":\"_batchUpdateVerifiers\",\"type\":\"address\"},{\"internalType\":\"contract ISemaphoreVerifier\",\"name\":\"_semaphoreVerifier\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract VerifierLookupTable\",\"name\":\"_batchUpdateVerifiers\",\"type\":\"address\"}],\"name\":\"initializeV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"}],\"name\":\"queryRoot\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"supersededTimestamp\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isValid\",\"type\":\"bool\"}],\"internalType\":\"struct WorldIDIdentityManagerImplV1.RootInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[8]\",\"name\":\"insertionProof\",\"type\":\"uint256[8]\"},{\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"startIndex\",\"type\":\"uint32\"},{\"internalType\":\"uint256[]\",\"name\":\"identityCommitments\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"}],\"name\":\"registerIdentities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"}],\"name\":\"requireValidRoot\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract VerifierLookupTable\",\"name\":\"newTable\",\"type\":\"address\"}],\"name\":\"setDeleteIdentitiesVerifierLookupTable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newIdentityOperator\",\"type\":\"address\"}],\"name\":\"setIdentityOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract VerifierLookupTable\",\"name\":\"newTable\",\"type\":\"address\"}],\"name\":\"setIdentityUpdateVerifierLookupTable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract VerifierLookupTable\",\"name\":\"newTable\",\"type\":\"address\"}],\"name\":\"setRegisterIdentitiesVerifierLookupTable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newExpiryTime\",\"type\":\"uint256\"}],\"name\":\"setRootHistoryExpiry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ISemaphoreVerifier\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"setSemaphoreVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[8]\",\"name\":\"updateProof\",\"type\":\"uint256[8]\"},{\"internalType\":\"uint256\",\"name\":\"preRoot\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"leafIndices\",\"type\":\"uint32[]\"},{\"internalType\":\"uint256[]\",\"name\":\"oldIdentities\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"newIdentities\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"postRoot\",\"type\":\"uint256\"}],\"name\":\"updateIdentities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"root\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signalHash\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nullifierHash\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalNullifierHash\",\"type\":\"uint256\"},{\"internalType\":\"uint256[8]\",\"name\":\"proof\",\"type\":\"uint256[8]\"}],\"name\":\"verifyProof\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Worldcoin\",\"details\":\"The manager is based on the principle of verifying externally-created Zero Knowledge Proofs to perform the insertions.This is the implementation delegated to by a proxy.\",\"errors\":{\"InvalidCommitment(uint256)\":[{\"params\":{\"index\":\"The index in the array of identity commitments where the invalid commitment was found.\"}}],\"NotLatestRoot(uint256,uint256)\":[{\"params\":{\"latestRoot\":\"The actual latest root at the time of the transaction.\",\"providedRoot\":\"The root that was provided as the `preRoot` for a transaction.\"}}],\"Unauthorized(address)\":[{\"params\":{\"user\":\"The user that attempted the action that they were not authorised for.\"}}],\"UnreducedElement(uint8,uint256)\":[{\"details\":\"`r` in this case is given by `SNARK_SCALAR_FIELD`.\",\"params\":{\"element\":\"The value of that element.\",\"elementType\":\"The kind of element that was encountered unreduced.\"}}],\"UnsupportedTreeDepth(uint8)\":[{\"params\":{\"depth\":\"Passed tree depth.\"}}]},\"events\":{\"AdminChanged(address,address)\":{\"details\":\"Emitted when the admin account has changed.\"},\"BeaconUpgraded(address)\":{\"details\":\"Emitted when the beacon is upgraded.\"},\"DependencyUpdated(uint8,address,address)\":{\"params\":{\"kind\":\"The kind of dependency that was updated.\",\"newAddress\":\"The new address of that dependency.\",\"oldAddress\":\"The old address of that dependency.\"}},\"IdentityOperatorChanged(address,address)\":{\"params\":{\"newOperator\":\"The address of the new identity operator.\",\"oldOperator\":\"The address of the old identity operator.\"}},\"Initialized(uint8)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"RootHistoryExpirySet(uint256,uint256)\":{\"params\":{\"newExpiryTime\":\"The expiry time after the change.\",\"oldExpiryTime\":\"The expiry time prior to the change.\"}},\"StateBridgeStateChange(bool)\":{\"params\":{\"isEnabled\":\"Set to `true` if the event comes from the state bridge being enabled, `false` otherwise.\"}},\"TreeChanged(uint256,uint8,uint256)\":{\"params\":{\"kind\":\"Either \\\"insertion\\\" or \\\"update\\\", the kind of alteration that was made to the tree.\",\"postRoot\":\"The value of the tree's root after the update.\",\"preRoot\":\"The value of the tree's root before the update.\"}},\"Upgraded(address)\":{\"details\":\"Emitted when the implementation is upgraded.\"},\"WorldIDIdentityManagerImplInitialized(uint8,uint256)\":{\"params\":{\"_treeDepth\":\"The depth of the MerkeTree\",\"initialRoot\":\"The initial value for the `latestRoot` in the contract. When deploying this should be set to the root of the empty tree.\"}}},\"kind\":\"dev\",\"methods\":{\"NO_SUCH_ROOT()\":{\"details\":\"Can be checked against when querying for root data.\"},\"acceptOwnership()\":{\"details\":\"The new owner accepts the ownership transfer.\"},\"calculateIdentityDeletionInputHash(bytes,uint256,uint256,uint32)\":{\"details\":\"Implements the computation described below.the deletion indices are packed into bytes calldata where each deletion index is 32 bits wide. The indices are encoded using abi.encodePacked for testing. We keccak hash all input to save verification gas. Inputs for the hash are arranged as follows: packedDeletionIndices || PreRoot || PostRoot 32 bits * batchSize || 256 || 256\",\"params\":{\"batchSize\":\"The number of identities that were deleted in this batch\",\"packedDeletionIndices\":\"The indices of the identities that were deleted from the tree.\",\"postRoot\":\"The root value of the tree after these insertions were made.\",\"preRoot\":\"The root value of the tree before these insertions were made.\"},\"returns\":{\"hash\":\"The input hash calculated as described below.\"}},\"calculateIdentityRegistrationInputHash(uint32,uint256,uint256,uint256[])\":{\"details\":\"Implements the computation described below.\",\"params\":{\"identityCommitments\":\"The identities that were added to the tree to produce `postRoot`.\",\"postRoot\":\"The root value of the tree after these insertions were made.\",\"preRoot\":\"The root value of the tree before these insertions were made.\",\"startIndex\":\"The index in the tree from which inserting started.\"},\"returns\":{\"hash\":\"The input hash calculated as described below. We keccak hash all input to save verification gas. Inputs are arranged as follows: StartIndex || PreRoot || PostRoot || IdComms[0] || IdComms[1] || ... || IdComms[batchSize-1] 32\\t || 256 || 256 || 256 || 256 || ... || 256 bits\"}},\"calculateIdentityUpdateInputHash(uint256,uint256,uint32[],uint256[],uint256[])\":{\"details\":\"Implements the computation described below.\",\"params\":{\"leafIndices\":\"The array of leaf indices at which the update operations take place in the tree. Elements in this array are extended to 256 bits when encoding.\",\"newIdentities\":\"The array of new values for the identities. Length must match that of `leafIndices`.\",\"oldIdentities\":\"The array of old values for the identities. Length must match that of `leafIndices`.\",\"postRoot\":\"The root value of the tree after the updates were made.\",\"preRoot\":\"The root value of the tree before the updates were made.\"},\"returns\":{\"hash\":\"The input hash calculated as described below. The arrays `leafIndices`, `oldIdentities` and `newIdentities` are arranged such that the triple at an element `i` in those arrays corresponds to one update operation. We keccak hash all input to save verification gas. The inputs are arranged as follows: preRoot || postRoot || ix[0] || ... || ix[n] || oi[0] || ... || oi[n] || ni[0] || ... || ni[n] || 256 || 256 || 256 || ... || 256 || 256 || ... || 256 || 256 || ... || 256 || where: - `ix[i] == leafIndices[i]` - `oi[i] == oldIdentities[i]` - `ni[i] == newIdentities[i]` - `id[i] == identities[i]` - `n == batchSize - 1`\"}},\"deleteIdentities(uint256[8],uint32,bytes,uint256,uint256)\":{\"custom:reverts\":\"Unauthorized If the message sender is not authorised to add identities.InvalidCommitment If one or more of the provided commitments is invalid.NotLatestRoot If the provided `preRoot` is not the latest root.ProofValidationFailure If `deletionProof` cannot be verified using the provided inputs.UnreducedElement If any of the `preRoot`, `postRoot` and `identityCommitments` is not an element of the field `Kr`. It describes the type and value of the unreduced element.VerifierLookupTable.NoSuchVerifier If the batch sizes doesn't match a known verifier.VerifierLookupTable.BatchTooLarge If the batch size exceeds the maximum batch size.\",\"details\":\"Can only be called by the owner.Deletion is performed off-chain and verified on-chain via the `deletionProof`. This saves gas and time over deleting identities one at a time.\",\"params\":{\"batchSize\":\"The number of identities that are to be deleted in the current batch.\",\"deletionProof\":\"The proof that given the conditions (`preRoot` and `packedDeletionIndices`), deletion into the tree results in `postRoot`. Elements 0 and 1 are the `x` and `y` coordinates for `ar` respectively. Elements 2 and 3 are the `x` coordinate for `bs`, and elements 4 and 5 are the `y` coordinate for `bs`. Elements 6 and 7 are the `x` and `y` coordinates for `krs`.\",\"packedDeletionIndices\":\"The indices of the identities that were deleted from the tree.\",\"postRoot\":\"The root obtained after deleting all of `identityCommitments` into the tree described by `preRoot`. Must be an element of the field `Kr`.\",\"preRoot\":\"The value for the root of the tree before the `identityCommitments` have been inserted. Must be an element of the field `Kr`.\"}},\"getDeleteIdentitiesVerifierLookupTableAddress()\":{\"details\":\"The deletion verifier supports batch deletions of size 10, 100 and 1000 members per batch.\",\"returns\":{\"_0\":\"addr The address of the contract being used as the verifier lookup table.\"}},\"getIdentityUpdateVerifierLookupTableAddress()\":{\"details\":\"The update verifier is also used for member removals.\",\"returns\":{\"_0\":\"addr The address of the contract being used as the verifier lookup table.\"}},\"getRegisterIdentitiesVerifierLookupTableAddress()\":{\"returns\":{\"_0\":\"addr The address of the contract being used as the verifier lookup table.\"}},\"getRootHistoryExpiry()\":{\"returns\":{\"_0\":\"expiryTime The amount of time it takes for a root to expire.\"}},\"getSemaphoreVerifierAddress()\":{\"returns\":{\"_0\":\"addr The address of the contract being used as the verifier.\"}},\"getTreeDepth()\":{\"returns\":{\"_0\":\"initializedTreeDepth Tree depth.\"}},\"identityOperator()\":{\"returns\":{\"_0\":\"_ The address authorized to perform identity operations.\"}},\"initialize(uint8,uint256,address,address,address)\":{\"custom:reverts\":\"string If called more than once at the same initialisation number.UnsupportedTreeDepth If passed tree depth is not among defined values.\",\"details\":\"Must be called exactly once.This is marked `reinitializer()` to allow for updated initialisation steps when working with upgrades based upon this contract. Be aware that there are only 256 (zero-indexed) initialisations allowed, so decide carefully when to use them. Many cases can safely be replaced by use of setters.This function is explicitly not virtual as it does not make sense to override even when upgrading. Create a separate initializer function instead.\",\"params\":{\"_batchInsertionVerifiers\":\"The verifier lookup table for batch insertions.\",\"_batchUpdateVerifiers\":\"The verifier lookup table for batch updates.\",\"_semaphoreVerifier\":\"The verifier to use for semaphore protocol proofs.\",\"_treeDepth\":\"The depth of the MerkeTree\",\"initialRoot\":\"The initial value for the `latestRoot` in the contract. When deploying this should be set to the root of the empty tree.\"}},\"initializeV2(address)\":{\"details\":\"Must be called exactly onceThis is marked `reinitializer()` to allow for updated initialisation steps when working with upgrades based upon this contract. Be aware that there are only 256 (zero-indexed) initialisations allowed, so decide carefully when to use them. Many cases can safely be replaced by use of setters.This function is explicitly not virtual as it does not make sense to override even when upgrading. Create a separate initializer function instead.\"},\"latestRoot()\":{\"returns\":{\"_0\":\"root The value of the latest tree root.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"pendingOwner()\":{\"details\":\"Returns the address of the pending owner.\"},\"proxiableUUID()\":{\"details\":\"Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\"},\"queryRoot(uint256)\":{\"details\":\"Should be used sparingly as the query can be quite expensive.\",\"params\":{\"root\":\"The root for which you are querying information.\"},\"returns\":{\"_0\":\"rootInfo The information about `root`, or `NO_SUCH_ROOT` if `root` does not exist. Note that if the queried root is the current, the timestamp will be invalid as the root has not been superseded.\"}},\"registerIdentities(uint256[8],uint256,uint32,uint256[],uint256)\":{\"custom:reverts\":\"Unauthorized If the message sender is not authorised to add identities.NotLatestRoot If the provided `preRoot` is not the latest root.ProofValidationFailure If `insertionProof` cannot be verified using the provided inputs.VerifierLookupTable.NoSuchVerifier If the batch sizes doesn't match a known verifier.VerifierLookupTable.BatchTooLarge If the batch size exceeds the maximum batch size.\",\"params\":{\"identityCommitments\":\"The identities that were inserted into the tree starting at `startIndex` and `preRoot` to give `postRoot`. All of the commitments must be elements of the field `Kr`.\",\"postRoot\":\"The root obtained after inserting all of `identityCommitments` into the tree described by `preRoot`. Must be an element of the field `Kr`. (alread in reduced form)\",\"startIndex\":\"The position in the tree at which the insertions were made.\"}},\"renounceOwnership()\":{\"details\":\"This function is intentionally not `virtual` as we do not want it to be possible to renounce ownership for any WorldID implementation.This function is marked as `onlyOwner` to maintain the access restriction from the base contract.\"},\"requireValidRoot(uint256)\":{\"custom:reverts\":\"ExpiredRoot If the provided `root` has expired.NonExistentRoot If the provided `root` does not exist in the history.\",\"details\":\"A root is valid if it is either the latest root, or not the latest root but has not expired.\",\"params\":{\"root\":\"The root of the merkle tree to check for validity.\"}},\"setDeleteIdentitiesVerifierLookupTable(address)\":{\"details\":\"Only the owner of the contract can call this function.\",\"params\":{\"newTable\":\"The new verifier lookup table to be used for verifying identity deletions.\"}},\"setIdentityOperator(address)\":{\"params\":{\"newIdentityOperator\":\"The address of the new identity operator.\"},\"returns\":{\"_0\":\"_ The address of the old identity operator.\"}},\"setIdentityUpdateVerifierLookupTable(address)\":{\"details\":\"Only the owner of the contract can call this function.The update verifier is also used for member removals.\",\"params\":{\"newTable\":\"The new lookup table instance to be used for verifying identity updates.\"}},\"setRegisterIdentitiesVerifierLookupTable(address)\":{\"details\":\"Only the owner of the contract can call this function.\",\"params\":{\"newTable\":\"The new verifier lookup table to be used for verifying identity registrations.\"}},\"setRootHistoryExpiry(uint256)\":{\"details\":\"Only the owner of the contract can call this function.\",\"params\":{\"newExpiryTime\":\"The new time to use to expire roots.\"}},\"setSemaphoreVerifier(address)\":{\"details\":\"Only the owner of the contract can call this function.\",\"params\":{\"newVerifier\":\"The new verifier instance to be used for verifying semaphore proofs.\"}},\"transferOwnership(address)\":{\"details\":\"Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner.\"},\"updateIdentities(uint256[8],uint256,uint32[],uint256[],uint256[],uint256)\":{\"custom:reverts\":\"Unauthorized If the message sender is not authorised to update identities.NotLatestRoot If the provided `preRoot` is not the latest root.MismatchedInputLengths If the provided arrays for `leafIndices`, `oldIdentities` and `newIdentities` do not match in length.ProofValidationFailure If `removalProof` cannot be verified using the provided inputs.UnreducedElement If any of the `preRoot`, `postRoot` and `identities` is not an element of the field `Kr`. It describes the type and value of the unreduced element.NoSuchVerifier If the batch sizes doesn't match a known verifier.\",\"params\":{\"leafIndices\":\"The array of leaf indices at which the update operations take place in the tree. Elements in this array are extended to 256 bits when encoding.\",\"newIdentities\":\"The array of new values for the identities. Length must match that of `leafIndices`.\",\"oldIdentities\":\"The array of old values for the identities. Length must match that of `leafIndices`.\",\"postRoot\":\"The root obtained after removing all of `removedIdentities` from the tree described by `preRoot`. Must be an element of the field `Kr`. The arrays `leafIndices`, `oldIdentities` and `newIdentities` are arranged such that the triple at an element `i` in those arrays corresponds to one update operation.\"}},\"upgradeTo(address)\":{\"details\":\"Upgrade the implementation of the proxy to `newImplementation`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event.\"},\"verifyProof(uint256,uint256,uint256,uint256,uint256[8])\":{\"custom:reverts\":\"string If the zero-knowledge proof cannot be verified for the public inputs.\",\"details\":\"Note that a double-signaling check is not included here, and should be carried by the caller.\",\"params\":{\"externalNullifierHash\":\"A keccak256 hash of the external nullifier\",\"nullifierHash\":\"The nullifier hash\",\"proof\":\"The zero-knowledge proof\",\"root\":\"The of the Merkle tree\",\"signalHash\":\"A keccak256 hash of the Semaphore signal\"}}},\"title\":\"WorldID Identity Manager Implementation Version 2\",\"version\":1},\"userdoc\":{\"errors\":{\"CannotRenounceOwnership()\":[{\"notice\":\"Thrown when an attempt is made to renounce ownership.\"}],\"ExpiredRoot()\":[{\"notice\":\"Thrown when attempting to validate a root that has expired.\"}],\"ImplementationNotInitialized()\":[{\"notice\":\"Thrown when attempting to call a function while the implementation has not been initialized.\"}],\"InvalidCommitment(uint256)\":[{\"notice\":\"Thrown when one or more of the identity commitments to be inserted is invalid.\"}],\"InvalidStateBridgeAddress()\":[{\"notice\":\"Thrown when attempting to set the state bridge address to the zero address.\"}],\"MismatchedInputLengths()\":[{\"notice\":\"Thrown when the inputs to `removeIdentities` or `updateIdentities` do not match in length.\"}],\"NonExistentRoot()\":[{\"notice\":\"Thrown when attempting to validate a root that has yet to be added to the root history.\"}],\"NotLatestRoot(uint256,uint256)\":[{\"notice\":\"Thrown when the provided root is not the very latest root.\"}],\"ProofValidationFailure()\":[{\"notice\":\"Thrown when the provided proof cannot be verified for the accompanying inputs.\"}],\"StateBridgeAlreadyDisabled()\":[{\"notice\":\"Thrown when attempting to disable the bridge when it is already disabled.\"}],\"StateBridgeAlreadyEnabled()\":[{\"notice\":\"Thrown when attempting to enable the bridge when it is already enabled.\"}],\"Unauthorized(address)\":[{\"notice\":\"Thrown when trying to execute a privileged action without being the contract manager.\"}],\"UnreducedElement(uint8,uint256)\":[{\"notice\":\"Thrown when encountering an element that should be reduced as a member of `Fr` but is not.\"}],\"UnsupportedTreeDepth(uint8)\":[{\"notice\":\"Thrown when Semaphore tree depth is not supported.\"}]},\"events\":{\"DependencyUpdated(uint8,address,address)\":{\"notice\":\"Emitted when a dependency's address is updated via an admin action.\"},\"IdentityOperatorChanged(address,address)\":{\"notice\":\"Emitted when the identity operator is changed.\"},\"RootHistoryExpirySet(uint256,uint256)\":{\"notice\":\"Emitted when the root history expiry time is changed.\"},\"StateBridgeStateChange(bool)\":{\"notice\":\"Emitted when the state bridge is enabled or disabled.\"},\"TreeChanged(uint256,uint8,uint256)\":{\"notice\":\"Emitted when the current root of the tree is updated.\"}},\"kind\":\"user\",\"methods\":{\"NO_SUCH_ROOT()\":{\"notice\":\"A constant representing a root that doesn't exist.\"},\"calculateIdentityDeletionInputHash(bytes,uint256,uint256,uint32)\":{\"notice\":\"Calculates the input hash for the identity deletion verifier.\"},\"calculateIdentityRegistrationInputHash(uint32,uint256,uint256,uint256[])\":{\"notice\":\"Calculates the input hash for the identity registration verifier.\"},\"calculateIdentityUpdateInputHash(uint256,uint256,uint32[],uint256[],uint256[])\":{\"notice\":\"Calculates the input hash for the identity update verifier.\"},\"deleteIdentities(uint256[8],uint32,bytes,uint256,uint256)\":{\"notice\":\"Deletes identities from the WorldID system.\"},\"getDeleteIdentitiesVerifierLookupTableAddress()\":{\"notice\":\"Gets the address for the lookup table of merkle tree verifiers used for batch identity deletions.\"},\"getIdentityUpdateVerifierLookupTableAddress()\":{\"notice\":\"Gets the address for the lookup table of merkle tree verifiers used for identity updates.\"},\"getRegisterIdentitiesVerifierLookupTableAddress()\":{\"notice\":\"Gets the address for the lookup table of merkle tree verifiers used for identity registrations.\"},\"getRootHistoryExpiry()\":{\"notice\":\"Gets the current amount of time used to expire roots in the history.\"},\"getSemaphoreVerifierAddress()\":{\"notice\":\"Gets the address of the verifier used for verification of semaphore proofs.\"},\"getTreeDepth()\":{\"notice\":\"Gets the Semaphore tree depth the contract was initialized with.\"},\"identityOperator()\":{\"notice\":\"Gets the address that is authorised to perform identity operations on this identity manager instance.\"},\"initialize(uint8,uint256,address,address,address)\":{\"notice\":\"Initializes the contract.\"},\"initializeV2(address)\":{\"notice\":\"Initializes the V2 implementation contract.\"},\"latestRoot()\":{\"notice\":\"Allows a caller to query the latest root.\"},\"queryRoot(uint256)\":{\"notice\":\"Allows a caller to query the root history for information about a given root.\"},\"renounceOwnership()\":{\"notice\":\"Ensures that ownership of WorldID implementations cannot be renounced.\"},\"requireValidRoot(uint256)\":{\"notice\":\"Reverts if the provided root value is not valid.\"},\"setDeleteIdentitiesVerifierLookupTable(address)\":{\"notice\":\"Sets the address for the lookup table of merkle tree verifiers used for identity deletions.\"},\"setIdentityOperator(address)\":{\"notice\":\"Sets the address that is authorised to perform identity operations on this identity manager instance.\"},\"setIdentityUpdateVerifierLookupTable(address)\":{\"notice\":\"Sets the address for the lookup table of merkle tree verifiers to be used for verification of identity updates.\"},\"setRegisterIdentitiesVerifierLookupTable(address)\":{\"notice\":\"Sets the address for the lookup table of merkle tree verifiers used for identity registrations.\"},\"setRootHistoryExpiry(uint256)\":{\"notice\":\"Sets the time to wait before expiring a root from the root history.\"},\"setSemaphoreVerifier(address)\":{\"notice\":\"Sets the address for the semaphore verifier to be used for verification of semaphore proofs.\"},\"verifyProof(uint256,uint256,uint256,uint256,uint256[8])\":{\"notice\":\"A verifier for the semaphore protocol.\"}},\"notice\":\"An implementation of a batch-based identity manager for the WorldID protocol.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/WorldIDIdentityManagerImplV2.sol\":\"WorldIDIdentityManagerImplV2\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@zk-kit/=lib/zk-kit/packages/\",\":contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":ds-test/=lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts/contracts/\",\":semaphore/=lib/semaphore/packages/contracts/contracts/\",\":solmate/=lib/solmate/src/\",\":zk-kit/=lib/zk-kit/\"]},\"sources\":{\"lib/openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol\":{\"keccak256\":\"0xd712fb45b3ea0ab49679164e3895037adc26ce12879d5184feb040e01c1c07a9\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://79ecc0838b0649460c0a538a4adb55b2b530e726c5526afc5e09c8eea4f3af13\",\"dweb:/ipfs/QmUxugyGDGGeLzDFi8QDH2vQMtCFaheiujWv58SuGVx4bZ\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol\":{\"keccak256\":\"0x247c62047745915c0af6b955470a72d1696ebad4352d7d3011aef1a2463cd888\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d7fc8396619de513c96b6e00301b88dd790e83542aab918425633a5f7297a15a\",\"dweb:/ipfs/QmXbP4kiZyp7guuS7xe8KaybnwkRPGrBc2Kbi3vhcTfpxb\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/interfaces/draft-IERC1822Upgradeable.sol\":{\"keccak256\":\"0x77c89f893e403efc6929ba842b7ccf6534d4ffe03afe31670b4a528c0ad78c0f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://496bd9b3df2455d571018c09f0c6badd29713fdeb907c6aa09d8d28cb603f053\",\"dweb:/ipfs/QmXdJDyYs6WMwMh21dez2BYPxhSUaUYFMDtVNcn2cgFR79\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol\":{\"keccak256\":\"0x315887e846f1e5f8d8fa535a229d318bb9290aaa69485117f1ee8a9a6b3be823\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://29dda00da6d269685b555e710e4abf1c3eb6d00c15b888a7880a2f8dd3c4fdc2\",\"dweb:/ipfs/QmSqcjtdECygtT1Gy7uEo42x8542srpgGEeKKHfcnQqXgn\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/beacon/IBeaconUpgradeable.sol\":{\"keccak256\":\"0x24b86ac8c005b8c654fbf6ac34a5a4f61580d7273541e83e013e89d66fbf0908\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4dbfe1a3b3b3fb64294ce41fd2ad362e7b7012208117864f42c1a67620a6d5c1\",\"dweb:/ipfs/QmVMU5tWt7zBQMmf5cpMX8UMHV86T3kFeTxBTBjFqVWfoJ\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x037c334add4b033ad3493038c25be1682d78c00992e1acb0e2795caff3925271\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8a313cf42389440e2706837c91370323b85971c06afd6d056d21e2bc86459618\",\"dweb:/ipfs/QmT8XUrUvQ9aZaPKrqgRU2JVGWnaxBcUYJA7Q7K5KcLBSZ\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol\":{\"keccak256\":\"0x7967d130887c4b40666cd88f8744691d4527039a1b2a38aa0de41481ef646778\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://40e60cbf0e2efede4d9c169e66336a64615af7b719a896ef1f37ae8cd4614ec1\",\"dweb:/ipfs/QmYNiwY22ifhfa8yK6mLCEKfj39caYUHLqe2VBtzDnvdsV\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol\":{\"keccak256\":\"0x2edcb41c121abc510932e8d83ff8b82cf9cdde35e7c297622f5c29ef0af25183\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://72460c66cd1c3b1c11b863e0d8df0a1c56f37743019e468dc312c754f43e3b06\",\"dweb:/ipfs/QmPExYKiNb9PUsgktQBupPaM33kzDHxaYoVeJdLhv8s879\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol\":{\"keccak256\":\"0x963ea7f0b48b032eef72fe3a7582edf78408d6f834115b9feadd673a4d5bd149\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d6520943ea55fdf5f0bafb39ed909f64de17051bc954ff3e88c9e5621412c79c\",\"dweb:/ipfs/QmWZ4rAKTQbNG2HxGs46AcTXShsVytKeLs7CUCdCSv5N7a\"]},\"lib/openzeppelin-contracts-upgradeable/contracts/utils/StorageSlotUpgradeable.sol\":{\"keccak256\":\"0x09864aea84f01e39313375b5610c73a3c1c68abbdc51e5ccdd25ff977fdadf9a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://aedb48081190fa828d243529ce25c708202c7d4ccfe99f0e4ecd6bc0cfcd03f3\",\"dweb:/ipfs/QmWyiDQHPZA56iqsAwTmiJoxvNeRQLUVr4gTfzpdpXivpo\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0x923b9774b81c1abfb992262ae7763b6e6de77b077a7180d53c6ebb7b1c8bd648\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53445dc0431f9b45c06f567c6091da961d4087bec0010cca5bd62100fa624a38\",\"dweb:/ipfs/QmNvBYpBv183czrAqNXr76E8M3LF93ouAJFeAcHfb59Rcx\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol\":{\"keccak256\":\"0x7cdab82b437a17902683a413c86d14f512674a0710007bf44c584a2d2d3ca833\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ffe4db7a9f3cdd5a5d019462c2859f4f98f7aae08704afdcb3ef0d08d966bbeb\",\"dweb:/ipfs/QmTCHSuoi22dAu55qv4TcENyTmv5mTpAoxmYWD8cRnEp3M\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"lib/semaphore/packages/contracts/contracts/base/Pairing.sol\":{\"keccak256\":\"0x44390032d1247a0e3931eb39f1220f170db653c6b3b4321b2e2b0034f5e07334\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://725cc4bdf047d17bf9d47c9a0205d90897c0da334de8e556c1a3049b1beb9aed\",\"dweb:/ipfs/QmSo7SXpqyrqHFhYi7F8SGjcVxCdVr6FNdgiw7Qfre1NGt\"]},\"lib/semaphore/packages/contracts/contracts/interfaces/ISemaphoreVerifier.sol\":{\"keccak256\":\"0x5b5b1118ed7936014d3e410419d6048cc9c0ae69fd700442593f2c2cc782e1af\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://601cf2c7e3c98735ff38eaff225af090ec847d63ec599ecc2340323145430668\",\"dweb:/ipfs/QmUoZYgge8GmQokXrYiRXn24s4HgBZetiNWQssiSoTFrdi\"]},\"src/WorldIDIdentityManagerImplV1.sol\":{\"keccak256\":\"0xa1065360c830348be5e6f45dfb766d9f415d0321170a804da0b2f56338c14b36\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cd10fbb5eaf1f57cfe026baf79ee8cb7ca9d7db50599b77062d2634a147e9645\",\"dweb:/ipfs/QmdtRnh5nPkRFynH2mNsYvaAur8QPwsuCg6A1AAQnKB291\"]},\"src/WorldIDIdentityManagerImplV2.sol\":{\"keccak256\":\"0xa88ed74cd795d2a9a7cbb99f88fa1393c25d7807525c6f081b57d163180f887b\",\"urls\":[\"bzz-raw://5e045ea6313140813d515f5ceb43624cba08cfd14657445a731ba76a1e8252f1\",\"dweb:/ipfs/Qmb4kfWzbV3gVjrhfVo2PphCijTXxdBUvz9N1mV3Mivcd5\"]},\"src/abstract/WorldIDImpl.sol\":{\"keccak256\":\"0xccfff2c5d7af4e505ed13b7d46011d5544317343ea92e7beb874e4d69358e6d0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://428860598ca38e42e29892a0b4759c4d3010378f54c3b3e4392f965ff091076e\",\"dweb:/ipfs/QmYPjcDRTr1UEeSbS7ssdGjbDHzAqjRNKBsYJqKJWeL8bZ\"]},\"src/data/VerifierLookupTable.sol\":{\"keccak256\":\"0xfd213b79aaec8d205c50ab3ed5c4ebed06ae602ed526a820340adc1c76745fbc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6af992a56a7cee8124af7f16d74dc8a2a7ae5f8b3059b92d46862e44c3804b83\",\"dweb:/ipfs/QmV9bQtJ9PjnwsiiZMUGJANB3znSxJ6ACTqWv9WkQeoeB3\"]},\"src/interfaces/IBaseWorldID.sol\":{\"keccak256\":\"0xcec58605726864d72e35d62c85e002acc98d3f8fa19d01b49fff461c2767c144\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://57714fcbceb0497f3fe8906778a837082939489fbb0bd930d015ad6e971913d5\",\"dweb:/ipfs/QmQVVmLr9CEkR727ByMF96a8MbwAeB4AQQWvxneg2Avkq8\"]},\"src/interfaces/IBridge.sol\":{\"keccak256\":\"0x0931c789450d21479da5d4de8c6435fca965660f6e1bd746fff958f4c20cf2ac\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0c564b4d4a15e8075555077a043d773bb20133548376402ff3dbc0eccb57435d\",\"dweb:/ipfs/QmXQRihAFdtfyjTNeHmx9nmNHiS1wy2658Y5aXCXo2tKSQ\"]},\"src/interfaces/ITreeVerifier.sol\":{\"keccak256\":\"0xb572aeae7331d96981d46b0dd4408db9ad507a06a2dbf0624386114b2244c8ad\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6159630f78e9e0b3a326d064772713f8c1e73172718c2a6d5af1fb36b35c5991\",\"dweb:/ipfs/QmPN5VyQvonPfPdTvrmP5wqsFT3QNW3RwC8DHYdEtwXZT4\"]},\"src/interfaces/IWorldID.sol\":{\"keccak256\":\"0x577908eff2d29d96354a06ab2602ffe6b97aa9d491330efcc2fcd0a88a8acbb1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fa0a36a598a851b88cff364b4211dc32081f51940aa8076d9c9b7de8ab126b2f\",\"dweb:/ipfs/QmSne8aRiE8C8RuwEUSk4doETKAGaavrEYyUkwiJc5H8qc\"]},\"src/utils/CheckInitialized.sol\":{\"keccak256\":\"0xfab096b633efd580548007e97920f6088e6d8a5287db84b9aa3d595c02fefcf4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://dee612c9dbad59d535e7a72b79191187fd91c06af9cb5b6f68d60274d0ee2c04\",\"dweb:/ipfs/QmVJbSQ8DAN6igasbgHjZTM4NRZ3EjrhK8wFcvUG1wPYtZ\"]},\"src/utils/SemaphoreTreeDepthValidator.sol\":{\"keccak256\":\"0x50140161de381aa963457cfd2ee8831a435bd79040f38794e6ef07365c49c872\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bcc5b8a3a6f5146aa3fdee550c3e80d828b55df63223485da3d5655a591ad661\",\"dweb:/ipfs/QmWfUzbeFoSaPV1E8QxagUnpt5zfmPXgiropUg1GcV6oZs\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.21+commit.d9974bed" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [], + "type": "error", + "name": "CannotRenounceOwnership" + }, + { + "inputs": [], + "type": "error", + "name": "ExpiredRoot" + }, + { + "inputs": [], + "type": "error", + "name": "ImplementationNotInitialized" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "type": "error", + "name": "InvalidCommitment" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidStateBridgeAddress" + }, + { + "inputs": [], + "type": "error", + "name": "MismatchedInputLengths" + }, + { + "inputs": [], + "type": "error", + "name": "NonExistentRoot" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "providedRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "latestRoot", + "type": "uint256" + } + ], + "type": "error", + "name": "NotLatestRoot" + }, + { + "inputs": [], + "type": "error", + "name": "ProofValidationFailure" + }, + { + "inputs": [], + "type": "error", + "name": "StateBridgeAlreadyDisabled" + }, + { + "inputs": [], + "type": "error", + "name": "StateBridgeAlreadyEnabled" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "type": "error", + "name": "Unauthorized" + }, + { + "inputs": [ + { + "internalType": "enum WorldIDIdentityManagerImplV1.UnreducedElementType", + "name": "elementType", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "element", + "type": "uint256" + } + ], + "type": "error", + "name": "UnreducedElement" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "depth", + "type": "uint8" + } + ], + "type": "error", + "name": "UnsupportedTreeDepth" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "previousAdmin", + "type": "address", + "indexed": false + }, + { + "internalType": "address", + "name": "newAdmin", + "type": "address", + "indexed": false + } + ], + "type": "event", + "name": "AdminChanged", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beacon", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "BeaconUpgraded", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "enum WorldIDIdentityManagerImplV1.Dependency", + "name": "kind", + "type": "uint8", + "indexed": true + }, + { + "internalType": "address", + "name": "oldAddress", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newAddress", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "DependencyUpdated", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "oldOperator", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newOperator", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "IdentityOperatorChanged", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8", + "indexed": false + } + ], + "type": "event", + "name": "Initialized", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "previousOwner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "OwnershipTransferStarted", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "previousOwner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "OwnershipTransferred", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "oldExpiryTime", + "type": "uint256", + "indexed": true + }, + { + "internalType": "uint256", + "name": "newExpiryTime", + "type": "uint256", + "indexed": true + } + ], + "type": "event", + "name": "RootHistoryExpirySet", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "isEnabled", + "type": "bool", + "indexed": true + } + ], + "type": "event", + "name": "StateBridgeStateChange", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256", + "indexed": true + }, + { + "internalType": "enum WorldIDIdentityManagerImplV1.TreeChange", + "name": "kind", + "type": "uint8", + "indexed": true + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256", + "indexed": true + } + ], + "type": "event", + "name": "TreeChanged", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "Upgraded", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_treeDepth", + "type": "uint8", + "indexed": false + }, + { + "internalType": "uint256", + "name": "initialRoot", + "type": "uint256", + "indexed": false + } + ], + "type": "event", + "name": "WorldIDIdentityManagerImplInitialized", + "anonymous": false + }, + { + "inputs": [], + "stateMutability": "pure", + "type": "function", + "name": "NO_SUCH_ROOT", + "outputs": [ + { + "internalType": "struct WorldIDIdentityManagerImplV1.RootInfo", + "name": "rootInfo", + "type": "tuple", + "components": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "supersededTimestamp", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ] + } + ] + }, + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "name": "acceptOwnership" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "packedDeletionIndices", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "batchSize", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function", + "name": "calculateIdentityDeletionInputHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "startIndex", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "identityCommitments", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function", + "name": "calculateIdentityRegistrationInputHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "leafIndices", + "type": "uint32[]" + }, + { + "internalType": "uint256[]", + "name": "oldIdentities", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "newIdentities", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function", + "name": "calculateIdentityUpdateInputHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256[8]", + "name": "deletionProof", + "type": "uint256[8]" + }, + { + "internalType": "uint32", + "name": "batchSize", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "packedDeletionIndices", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "deleteIdentities" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "getDeleteIdentitiesVerifierLookupTableAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "getIdentityUpdateVerifierLookupTableAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "getRegisterIdentitiesVerifierLookupTableAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "getRootHistoryExpiry", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "getSemaphoreVerifierAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "getTreeDepth", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "identityOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_treeDepth", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "initialRoot", + "type": "uint256" + }, + { + "internalType": "contract VerifierLookupTable", + "name": "_batchInsertionVerifiers", + "type": "address" + }, + { + "internalType": "contract VerifierLookupTable", + "name": "_batchUpdateVerifiers", + "type": "address" + }, + { + "internalType": "contract ISemaphoreVerifier", + "name": "_semaphoreVerifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "initialize" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "_batchUpdateVerifiers", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "initializeV2" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "latestRoot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "queryRoot", + "outputs": [ + { + "internalType": "struct WorldIDIdentityManagerImplV1.RootInfo", + "name": "", + "type": "tuple", + "components": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "supersededTimestamp", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ] + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256[8]", + "name": "insertionProof", + "type": "uint256[8]" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "startIndex", + "type": "uint32" + }, + { + "internalType": "uint256[]", + "name": "identityCommitments", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "registerIdentities" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "renounceOwnership" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "requireValidRoot" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "newTable", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "setDeleteIdentitiesVerifierLookupTable" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newIdentityOperator", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "setIdentityOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "newTable", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "setIdentityUpdateVerifierLookupTable" + }, + { + "inputs": [ + { + "internalType": "contract VerifierLookupTable", + "name": "newTable", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "setRegisterIdentitiesVerifierLookupTable" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newExpiryTime", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "setRootHistoryExpiry" + }, + { + "inputs": [ + { + "internalType": "contract ISemaphoreVerifier", + "name": "newVerifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "setSemaphoreVerifier" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "transferOwnership" + }, + { + "inputs": [ + { + "internalType": "uint256[8]", + "name": "updateProof", + "type": "uint256[8]" + }, + { + "internalType": "uint256", + "name": "preRoot", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "leafIndices", + "type": "uint32[]" + }, + { + "internalType": "uint256[]", + "name": "oldIdentities", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "newIdentities", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "postRoot", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "updateIdentities" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "upgradeTo" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function", + "name": "upgradeToAndCall" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "root", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signalHash", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nullifierHash", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "externalNullifierHash", + "type": "uint256" + }, + { + "internalType": "uint256[8]", + "name": "proof", + "type": "uint256[8]" + } + ], + "stateMutability": "view", + "type": "function", + "name": "verifyProof" + } + ], + "devdoc": { + "kind": "dev", + "methods": { + "NO_SUCH_ROOT()": { + "details": "Can be checked against when querying for root data." + }, + "acceptOwnership()": { + "details": "The new owner accepts the ownership transfer." + }, + "calculateIdentityDeletionInputHash(bytes,uint256,uint256,uint32)": { + "details": "Implements the computation described below.the deletion indices are packed into bytes calldata where each deletion index is 32 bits wide. The indices are encoded using abi.encodePacked for testing. We keccak hash all input to save verification gas. Inputs for the hash are arranged as follows: packedDeletionIndices || PreRoot || PostRoot 32 bits * batchSize || 256 || 256", + "params": { + "batchSize": "The number of identities that were deleted in this batch", + "packedDeletionIndices": "The indices of the identities that were deleted from the tree.", + "postRoot": "The root value of the tree after these insertions were made.", + "preRoot": "The root value of the tree before these insertions were made." + }, + "returns": { + "hash": "The input hash calculated as described below." + } + }, + "calculateIdentityRegistrationInputHash(uint32,uint256,uint256,uint256[])": { + "details": "Implements the computation described below.", + "params": { + "identityCommitments": "The identities that were added to the tree to produce `postRoot`.", + "postRoot": "The root value of the tree after these insertions were made.", + "preRoot": "The root value of the tree before these insertions were made.", + "startIndex": "The index in the tree from which inserting started." + }, + "returns": { + "hash": "The input hash calculated as described below. We keccak hash all input to save verification gas. Inputs are arranged as follows: StartIndex || PreRoot || PostRoot || IdComms[0] || IdComms[1] || ... || IdComms[batchSize-1] 32\t || 256 || 256 || 256 || 256 || ... || 256 bits" + } + }, + "calculateIdentityUpdateInputHash(uint256,uint256,uint32[],uint256[],uint256[])": { + "details": "Implements the computation described below.", + "params": { + "leafIndices": "The array of leaf indices at which the update operations take place in the tree. Elements in this array are extended to 256 bits when encoding.", + "newIdentities": "The array of new values for the identities. Length must match that of `leafIndices`.", + "oldIdentities": "The array of old values for the identities. Length must match that of `leafIndices`.", + "postRoot": "The root value of the tree after the updates were made.", + "preRoot": "The root value of the tree before the updates were made." + }, + "returns": { + "hash": "The input hash calculated as described below. The arrays `leafIndices`, `oldIdentities` and `newIdentities` are arranged such that the triple at an element `i` in those arrays corresponds to one update operation. We keccak hash all input to save verification gas. The inputs are arranged as follows: preRoot || postRoot || ix[0] || ... || ix[n] || oi[0] || ... || oi[n] || ni[0] || ... || ni[n] || 256 || 256 || 256 || ... || 256 || 256 || ... || 256 || 256 || ... || 256 || where: - `ix[i] == leafIndices[i]` - `oi[i] == oldIdentities[i]` - `ni[i] == newIdentities[i]` - `id[i] == identities[i]` - `n == batchSize - 1`" + } + }, + "deleteIdentities(uint256[8],uint32,bytes,uint256,uint256)": { + "custom:reverts": "Unauthorized If the message sender is not authorised to add identities.InvalidCommitment If one or more of the provided commitments is invalid.NotLatestRoot If the provided `preRoot` is not the latest root.ProofValidationFailure If `deletionProof` cannot be verified using the provided inputs.UnreducedElement If any of the `preRoot`, `postRoot` and `identityCommitments` is not an element of the field `Kr`. It describes the type and value of the unreduced element.VerifierLookupTable.NoSuchVerifier If the batch sizes doesn't match a known verifier.VerifierLookupTable.BatchTooLarge If the batch size exceeds the maximum batch size.", + "details": "Can only be called by the owner.Deletion is performed off-chain and verified on-chain via the `deletionProof`. This saves gas and time over deleting identities one at a time.", + "params": { + "batchSize": "The number of identities that are to be deleted in the current batch.", + "deletionProof": "The proof that given the conditions (`preRoot` and `packedDeletionIndices`), deletion into the tree results in `postRoot`. Elements 0 and 1 are the `x` and `y` coordinates for `ar` respectively. Elements 2 and 3 are the `x` coordinate for `bs`, and elements 4 and 5 are the `y` coordinate for `bs`. Elements 6 and 7 are the `x` and `y` coordinates for `krs`.", + "packedDeletionIndices": "The indices of the identities that were deleted from the tree.", + "postRoot": "The root obtained after deleting all of `identityCommitments` into the tree described by `preRoot`. Must be an element of the field `Kr`.", + "preRoot": "The value for the root of the tree before the `identityCommitments` have been inserted. Must be an element of the field `Kr`." + } + }, + "getDeleteIdentitiesVerifierLookupTableAddress()": { + "details": "The deletion verifier supports batch deletions of size 10, 100 and 1000 members per batch.", + "returns": { + "_0": "addr The address of the contract being used as the verifier lookup table." + } + }, + "getIdentityUpdateVerifierLookupTableAddress()": { + "details": "The update verifier is also used for member removals.", + "returns": { + "_0": "addr The address of the contract being used as the verifier lookup table." + } + }, + "getRegisterIdentitiesVerifierLookupTableAddress()": { + "returns": { + "_0": "addr The address of the contract being used as the verifier lookup table." + } + }, + "getRootHistoryExpiry()": { + "returns": { + "_0": "expiryTime The amount of time it takes for a root to expire." + } + }, + "getSemaphoreVerifierAddress()": { + "returns": { + "_0": "addr The address of the contract being used as the verifier." + } + }, + "getTreeDepth()": { + "returns": { + "_0": "initializedTreeDepth Tree depth." + } + }, + "identityOperator()": { + "returns": { + "_0": "_ The address authorized to perform identity operations." + } + }, + "initialize(uint8,uint256,address,address,address)": { + "custom:reverts": "string If called more than once at the same initialisation number.UnsupportedTreeDepth If passed tree depth is not among defined values.", + "details": "Must be called exactly once.This is marked `reinitializer()` to allow for updated initialisation steps when working with upgrades based upon this contract. Be aware that there are only 256 (zero-indexed) initialisations allowed, so decide carefully when to use them. Many cases can safely be replaced by use of setters.This function is explicitly not virtual as it does not make sense to override even when upgrading. Create a separate initializer function instead.", + "params": { + "_batchInsertionVerifiers": "The verifier lookup table for batch insertions.", + "_batchUpdateVerifiers": "The verifier lookup table for batch updates.", + "_semaphoreVerifier": "The verifier to use for semaphore protocol proofs.", + "_treeDepth": "The depth of the MerkeTree", + "initialRoot": "The initial value for the `latestRoot` in the contract. When deploying this should be set to the root of the empty tree." + } + }, + "initializeV2(address)": { + "details": "Must be called exactly onceThis is marked `reinitializer()` to allow for updated initialisation steps when working with upgrades based upon this contract. Be aware that there are only 256 (zero-indexed) initialisations allowed, so decide carefully when to use them. Many cases can safely be replaced by use of setters.This function is explicitly not virtual as it does not make sense to override even when upgrading. Create a separate initializer function instead." + }, + "latestRoot()": { + "returns": { + "_0": "root The value of the latest tree root." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "pendingOwner()": { + "details": "Returns the address of the pending owner." + }, + "proxiableUUID()": { + "details": "Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the implementation. It is used to validate the implementation's compatibility when performing an upgrade. IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier." + }, + "queryRoot(uint256)": { + "details": "Should be used sparingly as the query can be quite expensive.", + "params": { + "root": "The root for which you are querying information." + }, + "returns": { + "_0": "rootInfo The information about `root`, or `NO_SUCH_ROOT` if `root` does not exist. Note that if the queried root is the current, the timestamp will be invalid as the root has not been superseded." + } + }, + "registerIdentities(uint256[8],uint256,uint32,uint256[],uint256)": { + "custom:reverts": "Unauthorized If the message sender is not authorised to add identities.NotLatestRoot If the provided `preRoot` is not the latest root.ProofValidationFailure If `insertionProof` cannot be verified using the provided inputs.VerifierLookupTable.NoSuchVerifier If the batch sizes doesn't match a known verifier.VerifierLookupTable.BatchTooLarge If the batch size exceeds the maximum batch size.", + "params": { + "identityCommitments": "The identities that were inserted into the tree starting at `startIndex` and `preRoot` to give `postRoot`. All of the commitments must be elements of the field `Kr`.", + "postRoot": "The root obtained after inserting all of `identityCommitments` into the tree described by `preRoot`. Must be an element of the field `Kr`. (alread in reduced form)", + "startIndex": "The position in the tree at which the insertions were made." + } + }, + "renounceOwnership()": { + "details": "This function is intentionally not `virtual` as we do not want it to be possible to renounce ownership for any WorldID implementation.This function is marked as `onlyOwner` to maintain the access restriction from the base contract." + }, + "requireValidRoot(uint256)": { + "custom:reverts": "ExpiredRoot If the provided `root` has expired.NonExistentRoot If the provided `root` does not exist in the history.", + "details": "A root is valid if it is either the latest root, or not the latest root but has not expired.", + "params": { + "root": "The root of the merkle tree to check for validity." + } + }, + "setDeleteIdentitiesVerifierLookupTable(address)": { + "details": "Only the owner of the contract can call this function.", + "params": { + "newTable": "The new verifier lookup table to be used for verifying identity deletions." + } + }, + "setIdentityOperator(address)": { + "params": { + "newIdentityOperator": "The address of the new identity operator." + }, + "returns": { + "_0": "_ The address of the old identity operator." + } + }, + "setIdentityUpdateVerifierLookupTable(address)": { + "details": "Only the owner of the contract can call this function.The update verifier is also used for member removals.", + "params": { + "newTable": "The new lookup table instance to be used for verifying identity updates." + } + }, + "setRegisterIdentitiesVerifierLookupTable(address)": { + "details": "Only the owner of the contract can call this function.", + "params": { + "newTable": "The new verifier lookup table to be used for verifying identity registrations." + } + }, + "setRootHistoryExpiry(uint256)": { + "details": "Only the owner of the contract can call this function.", + "params": { + "newExpiryTime": "The new time to use to expire roots." + } + }, + "setSemaphoreVerifier(address)": { + "details": "Only the owner of the contract can call this function.", + "params": { + "newVerifier": "The new verifier instance to be used for verifying semaphore proofs." + } + }, + "transferOwnership(address)": { + "details": "Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner." + }, + "updateIdentities(uint256[8],uint256,uint32[],uint256[],uint256[],uint256)": { + "custom:reverts": "Unauthorized If the message sender is not authorised to update identities.NotLatestRoot If the provided `preRoot` is not the latest root.MismatchedInputLengths If the provided arrays for `leafIndices`, `oldIdentities` and `newIdentities` do not match in length.ProofValidationFailure If `removalProof` cannot be verified using the provided inputs.UnreducedElement If any of the `preRoot`, `postRoot` and `identities` is not an element of the field `Kr`. It describes the type and value of the unreduced element.NoSuchVerifier If the batch sizes doesn't match a known verifier.", + "params": { + "leafIndices": "The array of leaf indices at which the update operations take place in the tree. Elements in this array are extended to 256 bits when encoding.", + "newIdentities": "The array of new values for the identities. Length must match that of `leafIndices`.", + "oldIdentities": "The array of old values for the identities. Length must match that of `leafIndices`.", + "postRoot": "The root obtained after removing all of `removedIdentities` from the tree described by `preRoot`. Must be an element of the field `Kr`. The arrays `leafIndices`, `oldIdentities` and `newIdentities` are arranged such that the triple at an element `i` in those arrays corresponds to one update operation." + } + }, + "upgradeTo(address)": { + "details": "Upgrade the implementation of the proxy to `newImplementation`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event." + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call encoded in `data`. Calls {_authorizeUpgrade}. Emits an {Upgraded} event." + }, + "verifyProof(uint256,uint256,uint256,uint256,uint256[8])": { + "custom:reverts": "string If the zero-knowledge proof cannot be verified for the public inputs.", + "details": "Note that a double-signaling check is not included here, and should be carried by the caller.", + "params": { + "externalNullifierHash": "A keccak256 hash of the external nullifier", + "nullifierHash": "The nullifier hash", + "proof": "The zero-knowledge proof", + "root": "The of the Merkle tree", + "signalHash": "A keccak256 hash of the Semaphore signal" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "NO_SUCH_ROOT()": { + "notice": "A constant representing a root that doesn't exist." + }, + "calculateIdentityDeletionInputHash(bytes,uint256,uint256,uint32)": { + "notice": "Calculates the input hash for the identity deletion verifier." + }, + "calculateIdentityRegistrationInputHash(uint32,uint256,uint256,uint256[])": { + "notice": "Calculates the input hash for the identity registration verifier." + }, + "calculateIdentityUpdateInputHash(uint256,uint256,uint32[],uint256[],uint256[])": { + "notice": "Calculates the input hash for the identity update verifier." + }, + "deleteIdentities(uint256[8],uint32,bytes,uint256,uint256)": { + "notice": "Deletes identities from the WorldID system." + }, + "getDeleteIdentitiesVerifierLookupTableAddress()": { + "notice": "Gets the address for the lookup table of merkle tree verifiers used for batch identity deletions." + }, + "getIdentityUpdateVerifierLookupTableAddress()": { + "notice": "Gets the address for the lookup table of merkle tree verifiers used for identity updates." + }, + "getRegisterIdentitiesVerifierLookupTableAddress()": { + "notice": "Gets the address for the lookup table of merkle tree verifiers used for identity registrations." + }, + "getRootHistoryExpiry()": { + "notice": "Gets the current amount of time used to expire roots in the history." + }, + "getSemaphoreVerifierAddress()": { + "notice": "Gets the address of the verifier used for verification of semaphore proofs." + }, + "getTreeDepth()": { + "notice": "Gets the Semaphore tree depth the contract was initialized with." + }, + "identityOperator()": { + "notice": "Gets the address that is authorised to perform identity operations on this identity manager instance." + }, + "initialize(uint8,uint256,address,address,address)": { + "notice": "Initializes the contract." + }, + "initializeV2(address)": { + "notice": "Initializes the V2 implementation contract." + }, + "latestRoot()": { + "notice": "Allows a caller to query the latest root." + }, + "queryRoot(uint256)": { + "notice": "Allows a caller to query the root history for information about a given root." + }, + "renounceOwnership()": { + "notice": "Ensures that ownership of WorldID implementations cannot be renounced." + }, + "requireValidRoot(uint256)": { + "notice": "Reverts if the provided root value is not valid." + }, + "setDeleteIdentitiesVerifierLookupTable(address)": { + "notice": "Sets the address for the lookup table of merkle tree verifiers used for identity deletions." + }, + "setIdentityOperator(address)": { + "notice": "Sets the address that is authorised to perform identity operations on this identity manager instance." + }, + "setIdentityUpdateVerifierLookupTable(address)": { + "notice": "Sets the address for the lookup table of merkle tree verifiers to be used for verification of identity updates." + }, + "setRegisterIdentitiesVerifierLookupTable(address)": { + "notice": "Sets the address for the lookup table of merkle tree verifiers used for identity registrations." + }, + "setRootHistoryExpiry(uint256)": { + "notice": "Sets the time to wait before expiring a root from the root history." + }, + "setSemaphoreVerifier(address)": { + "notice": "Sets the address for the semaphore verifier to be used for verification of semaphore proofs." + }, + "verifyProof(uint256,uint256,uint256,uint256,uint256[8])": { + "notice": "A verifier for the semaphore protocol." + } + }, + "version": 1 + } + }, + "settings": { + "remappings": [ + "@zk-kit/=lib/zk-kit/packages/", + "contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", + "ds-test/=lib/ds-test/src/", + "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", + "forge-std/=lib/forge-std/src/", + "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", + "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", + "openzeppelin/=lib/openzeppelin-contracts/contracts/", + "semaphore/=lib/semaphore/packages/contracts/contracts/", + "solmate/=lib/solmate/src/", + "zk-kit/=lib/zk-kit/" + ], + "optimizer": { + "enabled": true, + "runs": 200 + }, + "metadata": { + "bytecodeHash": "ipfs" + }, + "compilationTarget": { + "src/WorldIDIdentityManagerImplV2.sol": "WorldIDIdentityManagerImplV2" + }, + "libraries": {} + }, + "sources": { + "lib/openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol": { + "keccak256": "0xd712fb45b3ea0ab49679164e3895037adc26ce12879d5184feb040e01c1c07a9", + "urls": [ + "bzz-raw://79ecc0838b0649460c0a538a4adb55b2b530e726c5526afc5e09c8eea4f3af13", + "dweb:/ipfs/QmUxugyGDGGeLzDFi8QDH2vQMtCFaheiujWv58SuGVx4bZ" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol": { + "keccak256": "0x247c62047745915c0af6b955470a72d1696ebad4352d7d3011aef1a2463cd888", + "urls": [ + "bzz-raw://d7fc8396619de513c96b6e00301b88dd790e83542aab918425633a5f7297a15a", + "dweb:/ipfs/QmXbP4kiZyp7guuS7xe8KaybnwkRPGrBc2Kbi3vhcTfpxb" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/interfaces/draft-IERC1822Upgradeable.sol": { + "keccak256": "0x77c89f893e403efc6929ba842b7ccf6534d4ffe03afe31670b4a528c0ad78c0f", + "urls": [ + "bzz-raw://496bd9b3df2455d571018c09f0c6badd29713fdeb907c6aa09d8d28cb603f053", + "dweb:/ipfs/QmXdJDyYs6WMwMh21dez2BYPxhSUaUYFMDtVNcn2cgFR79" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol": { + "keccak256": "0x315887e846f1e5f8d8fa535a229d318bb9290aaa69485117f1ee8a9a6b3be823", + "urls": [ + "bzz-raw://29dda00da6d269685b555e710e4abf1c3eb6d00c15b888a7880a2f8dd3c4fdc2", + "dweb:/ipfs/QmSqcjtdECygtT1Gy7uEo42x8542srpgGEeKKHfcnQqXgn" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/proxy/beacon/IBeaconUpgradeable.sol": { + "keccak256": "0x24b86ac8c005b8c654fbf6ac34a5a4f61580d7273541e83e013e89d66fbf0908", + "urls": [ + "bzz-raw://4dbfe1a3b3b3fb64294ce41fd2ad362e7b7012208117864f42c1a67620a6d5c1", + "dweb:/ipfs/QmVMU5tWt7zBQMmf5cpMX8UMHV86T3kFeTxBTBjFqVWfoJ" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": { + "keccak256": "0x037c334add4b033ad3493038c25be1682d78c00992e1acb0e2795caff3925271", + "urls": [ + "bzz-raw://8a313cf42389440e2706837c91370323b85971c06afd6d056d21e2bc86459618", + "dweb:/ipfs/QmT8XUrUvQ9aZaPKrqgRU2JVGWnaxBcUYJA7Q7K5KcLBSZ" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol": { + "keccak256": "0x7967d130887c4b40666cd88f8744691d4527039a1b2a38aa0de41481ef646778", + "urls": [ + "bzz-raw://40e60cbf0e2efede4d9c169e66336a64615af7b719a896ef1f37ae8cd4614ec1", + "dweb:/ipfs/QmYNiwY22ifhfa8yK6mLCEKfj39caYUHLqe2VBtzDnvdsV" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol": { + "keccak256": "0x2edcb41c121abc510932e8d83ff8b82cf9cdde35e7c297622f5c29ef0af25183", + "urls": [ + "bzz-raw://72460c66cd1c3b1c11b863e0d8df0a1c56f37743019e468dc312c754f43e3b06", + "dweb:/ipfs/QmPExYKiNb9PUsgktQBupPaM33kzDHxaYoVeJdLhv8s879" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol": { + "keccak256": "0x963ea7f0b48b032eef72fe3a7582edf78408d6f834115b9feadd673a4d5bd149", + "urls": [ + "bzz-raw://d6520943ea55fdf5f0bafb39ed909f64de17051bc954ff3e88c9e5621412c79c", + "dweb:/ipfs/QmWZ4rAKTQbNG2HxGs46AcTXShsVytKeLs7CUCdCSv5N7a" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/StorageSlotUpgradeable.sol": { + "keccak256": "0x09864aea84f01e39313375b5610c73a3c1c68abbdc51e5ccdd25ff977fdadf9a", + "urls": [ + "bzz-raw://aedb48081190fa828d243529ce25c708202c7d4ccfe99f0e4ecd6bc0cfcd03f3", + "dweb:/ipfs/QmWyiDQHPZA56iqsAwTmiJoxvNeRQLUVr4gTfzpdpXivpo" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/access/Ownable.sol": { + "keccak256": "0x923b9774b81c1abfb992262ae7763b6e6de77b077a7180d53c6ebb7b1c8bd648", + "urls": [ + "bzz-raw://53445dc0431f9b45c06f567c6091da961d4087bec0010cca5bd62100fa624a38", + "dweb:/ipfs/QmNvBYpBv183czrAqNXr76E8M3LF93ouAJFeAcHfb59Rcx" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol": { + "keccak256": "0x7cdab82b437a17902683a413c86d14f512674a0710007bf44c584a2d2d3ca833", + "urls": [ + "bzz-raw://ffe4db7a9f3cdd5a5d019462c2859f4f98f7aae08704afdcb3ef0d08d966bbeb", + "dweb:/ipfs/QmTCHSuoi22dAu55qv4TcENyTmv5mTpAoxmYWD8cRnEp3M" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/Context.sol": { + "keccak256": "0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7", + "urls": [ + "bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92", + "dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3" + ], + "license": "MIT" + }, + "lib/semaphore/packages/contracts/contracts/base/Pairing.sol": { + "keccak256": "0x44390032d1247a0e3931eb39f1220f170db653c6b3b4321b2e2b0034f5e07334", + "urls": [ + "bzz-raw://725cc4bdf047d17bf9d47c9a0205d90897c0da334de8e556c1a3049b1beb9aed", + "dweb:/ipfs/QmSo7SXpqyrqHFhYi7F8SGjcVxCdVr6FNdgiw7Qfre1NGt" + ], + "license": "MIT" + }, + "lib/semaphore/packages/contracts/contracts/interfaces/ISemaphoreVerifier.sol": { + "keccak256": "0x5b5b1118ed7936014d3e410419d6048cc9c0ae69fd700442593f2c2cc782e1af", + "urls": [ + "bzz-raw://601cf2c7e3c98735ff38eaff225af090ec847d63ec599ecc2340323145430668", + "dweb:/ipfs/QmUoZYgge8GmQokXrYiRXn24s4HgBZetiNWQssiSoTFrdi" + ], + "license": "MIT" + }, + "src/WorldIDIdentityManagerImplV1.sol": { + "keccak256": "0xa1065360c830348be5e6f45dfb766d9f415d0321170a804da0b2f56338c14b36", + "urls": [ + "bzz-raw://cd10fbb5eaf1f57cfe026baf79ee8cb7ca9d7db50599b77062d2634a147e9645", + "dweb:/ipfs/QmdtRnh5nPkRFynH2mNsYvaAur8QPwsuCg6A1AAQnKB291" + ], + "license": "MIT" + }, + "src/WorldIDIdentityManagerImplV2.sol": { + "keccak256": "0xa88ed74cd795d2a9a7cbb99f88fa1393c25d7807525c6f081b57d163180f887b", + "urls": [ + "bzz-raw://5e045ea6313140813d515f5ceb43624cba08cfd14657445a731ba76a1e8252f1", + "dweb:/ipfs/Qmb4kfWzbV3gVjrhfVo2PphCijTXxdBUvz9N1mV3Mivcd5" + ], + "license": null + }, + "src/abstract/WorldIDImpl.sol": { + "keccak256": "0xccfff2c5d7af4e505ed13b7d46011d5544317343ea92e7beb874e4d69358e6d0", + "urls": [ + "bzz-raw://428860598ca38e42e29892a0b4759c4d3010378f54c3b3e4392f965ff091076e", + "dweb:/ipfs/QmYPjcDRTr1UEeSbS7ssdGjbDHzAqjRNKBsYJqKJWeL8bZ" + ], + "license": "MIT" + }, + "src/data/VerifierLookupTable.sol": { + "keccak256": "0xfd213b79aaec8d205c50ab3ed5c4ebed06ae602ed526a820340adc1c76745fbc", + "urls": [ + "bzz-raw://6af992a56a7cee8124af7f16d74dc8a2a7ae5f8b3059b92d46862e44c3804b83", + "dweb:/ipfs/QmV9bQtJ9PjnwsiiZMUGJANB3znSxJ6ACTqWv9WkQeoeB3" + ], + "license": "MIT" + }, + "src/interfaces/IBaseWorldID.sol": { + "keccak256": "0xcec58605726864d72e35d62c85e002acc98d3f8fa19d01b49fff461c2767c144", + "urls": [ + "bzz-raw://57714fcbceb0497f3fe8906778a837082939489fbb0bd930d015ad6e971913d5", + "dweb:/ipfs/QmQVVmLr9CEkR727ByMF96a8MbwAeB4AQQWvxneg2Avkq8" + ], + "license": "MIT" + }, + "src/interfaces/IBridge.sol": { + "keccak256": "0x0931c789450d21479da5d4de8c6435fca965660f6e1bd746fff958f4c20cf2ac", + "urls": [ + "bzz-raw://0c564b4d4a15e8075555077a043d773bb20133548376402ff3dbc0eccb57435d", + "dweb:/ipfs/QmXQRihAFdtfyjTNeHmx9nmNHiS1wy2658Y5aXCXo2tKSQ" + ], + "license": "MIT" + }, + "src/interfaces/ITreeVerifier.sol": { + "keccak256": "0xb572aeae7331d96981d46b0dd4408db9ad507a06a2dbf0624386114b2244c8ad", + "urls": [ + "bzz-raw://6159630f78e9e0b3a326d064772713f8c1e73172718c2a6d5af1fb36b35c5991", + "dweb:/ipfs/QmPN5VyQvonPfPdTvrmP5wqsFT3QNW3RwC8DHYdEtwXZT4" + ], + "license": "MIT" + }, + "src/interfaces/IWorldID.sol": { + "keccak256": "0x577908eff2d29d96354a06ab2602ffe6b97aa9d491330efcc2fcd0a88a8acbb1", + "urls": [ + "bzz-raw://fa0a36a598a851b88cff364b4211dc32081f51940aa8076d9c9b7de8ab126b2f", + "dweb:/ipfs/QmSne8aRiE8C8RuwEUSk4doETKAGaavrEYyUkwiJc5H8qc" + ], + "license": "MIT" + }, + "src/utils/CheckInitialized.sol": { + "keccak256": "0xfab096b633efd580548007e97920f6088e6d8a5287db84b9aa3d595c02fefcf4", + "urls": [ + "bzz-raw://dee612c9dbad59d535e7a72b79191187fd91c06af9cb5b6f68d60274d0ee2c04", + "dweb:/ipfs/QmVJbSQ8DAN6igasbgHjZTM4NRZ3EjrhK8wFcvUG1wPYtZ" + ], + "license": "MIT" + }, + "src/utils/SemaphoreTreeDepthValidator.sol": { + "keccak256": "0x50140161de381aa963457cfd2ee8831a435bd79040f38794e6ef07365c49c872", + "urls": [ + "bzz-raw://bcc5b8a3a6f5146aa3fdee550c3e80d828b55df63223485da3d5655a591ad661", + "dweb:/ipfs/QmWfUzbeFoSaPV1E8QxagUnpt5zfmPXgiropUg1GcV6oZs" + ], + "license": "MIT" + } + }, + "version": 1 + }, + "ast": { + "absolutePath": "src/WorldIDIdentityManagerImplV2.sol", + "id": 34136, + "exportedSymbols": { + "IBridge": [ + 34450 + ], + "ISemaphoreVerifier": [ + 32716 + ], + "ITreeVerifier": [ + 34478 + ], + "IWorldID": [ + 34502 + ], + "SemaphoreTreeDepthValidator": [ + 47908 + ], + "VerifierLookupTable": [ + 34425 + ], + "WorldIDIdentityManagerImplV1": [ + 33896 + ], + "WorldIDIdentityManagerImplV2": [ + 34135 + ], + "WorldIDImpl": [ + 34190 + ] + }, + "nodeType": "SourceUnit", + "src": "0:12051:43", + "nodes": [ + { + "id": 33898, + "nodeType": "PragmaDirective", + "src": "0:24:43", + "nodes": [], + "literals": [ + "solidity", + "^", + "0.8", + ".21" + ] + }, + { + "id": 33899, + "nodeType": "ImportDirective", + "src": "26:44:43", + "nodes": [], + "absolutePath": "src/WorldIDIdentityManagerImplV1.sol", + "file": "./WorldIDIdentityManagerImplV1.sol", + "nameLocation": "-1:-1:-1", + "scope": 34136, + "sourceUnit": 33897, + "symbolAliases": [], + "unitAlias": "" + }, + { + "id": 34135, + "nodeType": "ContractDefinition", + "src": "443:11607:43", + "nodes": [ + { + "id": 33906, + "nodeType": "VariableDeclaration", + "src": "3108:51:43", + "nodes": [], + "constant": false, + "documentation": { + "id": 33903, + "nodeType": "StructuredDocumentation", + "src": "3029:74:43", + "text": "@notice The table of verifiers for verifying batch identity deletions." + }, + "mutability": "mutable", + "name": "batchDeletionVerifiers", + "nameLocation": "3137:22:43", + "scope": 34135, + "stateVariable": true, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + }, + "typeName": { + "id": 33905, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 33904, + "name": "VerifierLookupTable", + "nameLocations": [ + "3108:19:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 34425, + "src": "3108:19:43" + }, + "referencedDeclaration": 34425, + "src": "3108:19:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "visibility": "internal" + }, + { + "id": 33921, + "nodeType": "FunctionDefinition", + "src": "3800:152:43", + "nodes": [], + "body": { + "id": 33920, + "nodeType": "Block", + "src": "3889:63:43", + "nodes": [], + "statements": [ + { + "expression": { + "id": 33918, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftHandSide": { + "id": 33916, + "name": "batchDeletionVerifiers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33906, + "src": "3899:22:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "nodeType": "Assignment", + "operator": "=", + "rightHandSide": { + "id": 33917, + "name": "_batchUpdateVerifiers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33910, + "src": "3924:21:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "src": "3899:46:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "id": 33919, + "nodeType": "ExpressionStatement", + "src": "3899:46:43" + } + ] + }, + "documentation": { + "id": 33907, + "nodeType": "StructuredDocumentation", + "src": "3166:629:43", + "text": "@notice Initializes the V2 implementation contract.\n @dev Must be called exactly once\n @dev This is marked `reinitializer()` to allow for updated initialisation steps when working\n with upgrades based upon this contract. Be aware that there are only 256 (zero-indexed)\n initialisations allowed, so decide carefully when to use them. Many cases can safely be\n replaced by use of setters.\n @dev This function is explicitly not virtual as it does not make sense to override even when\n upgrading. Create a separate initializer function instead." + }, + "functionSelector": "29b6eca9", + "implemented": true, + "kind": "function", + "modifiers": [ + { + "arguments": [ + { + "hexValue": "32", + "id": 33913, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "3886:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_2_by_1", + "typeString": "int_const 2" + }, + "value": "2" + } + ], + "id": 33914, + "kind": "modifierInvocation", + "modifierName": { + "id": 33912, + "name": "reinitializer", + "nameLocations": [ + "3872:13:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 29736, + "src": "3872:13:43" + }, + "nodeType": "ModifierInvocation", + "src": "3872:16:43" + } + ], + "name": "initializeV2", + "nameLocation": "3809:12:43", + "parameters": { + "id": 33911, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 33910, + "mutability": "mutable", + "name": "_batchUpdateVerifiers", + "nameLocation": "3842:21:43", + "nodeType": "VariableDeclaration", + "scope": 33921, + "src": "3822:41:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + }, + "typeName": { + "id": 33909, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 33908, + "name": "VerifierLookupTable", + "nameLocations": [ + "3822:19:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 34425, + "src": "3822:19:43" + }, + "referencedDeclaration": 34425, + "src": "3822:19:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "visibility": "internal" + } + ], + "src": "3821:43:43" + }, + "returnParameters": { + "id": 33915, + "nodeType": "ParameterList", + "parameters": [], + "src": "3889:0:43" + }, + "scope": 34135, + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + { + "id": 34062, + "nodeType": "FunctionDefinition", + "src": "6380:2438:43", + "nodes": [], + "body": { + "id": 34061, + "nodeType": "Block", + "src": "6640:2178:43", + "nodes": [], + "statements": [ + { + "condition": { + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "id": 33945, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "id": 33943, + "name": "preRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33932, + "src": "6654:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "nodeType": "BinaryOperation", + "operator": "!=", + "rightExpression": { + "id": 33944, + "name": "_latestRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32764, + "src": "6665:11:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "src": "6654:22:43", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "id": 33952, + "nodeType": "IfStatement", + "src": "6650:95:43", + "trueBody": { + "id": 33951, + "nodeType": "Block", + "src": "6678:67:43", + "statements": [ + { + "errorCall": { + "arguments": [ + { + "id": 33947, + "name": "preRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33932, + "src": "6713:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "id": 33948, + "name": "_latestRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32764, + "src": "6722:11:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "id": 33946, + "name": "NotLatestRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32868, + "src": "6699:13:43", + "typeDescriptions": { + "typeIdentifier": "t_function_error_pure$_t_uint256_$_t_uint256_$returns$__$", + "typeString": "function (uint256,uint256) pure" + } + }, + "id": 33949, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "6699:35:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 33950, + "nodeType": "RevertStatement", + "src": "6692:42:43" + } + ] + } + }, + { + "assignments": [ + 33954 + ], + "declarations": [ + { + "constant": false, + "id": 33954, + "mutability": "mutable", + "name": "inputHash", + "nameLocation": "6844:9:43", + "nodeType": "VariableDeclaration", + "scope": 34061, + "src": "6836:17:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + }, + "typeName": { + "id": 33953, + "name": "bytes32", + "nodeType": "ElementaryTypeName", + "src": "6836:7:43", + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + } + }, + "visibility": "internal" + } + ], + "id": 33961, + "initialValue": { + "arguments": [ + { + "id": 33956, + "name": "packedDeletionIndices", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33930, + "src": "6903:21:43", + "typeDescriptions": { + "typeIdentifier": "t_bytes_calldata_ptr", + "typeString": "bytes calldata" + } + }, + { + "id": 33957, + "name": "preRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33932, + "src": "6926:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "id": 33958, + "name": "postRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33934, + "src": "6935:8:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "id": 33959, + "name": "batchSize", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33928, + "src": "6945:9:43", + "typeDescriptions": { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_bytes_calldata_ptr", + "typeString": "bytes calldata" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + } + ], + "id": 33955, + "name": "calculateIdentityDeletionInputHash", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 34134, + "src": "6868:34:43", + "typeDescriptions": { + "typeIdentifier": "t_function_internal_view$_t_bytes_calldata_ptr_$_t_uint256_$_t_uint256_$_t_uint32_$returns$_t_bytes32_$", + "typeString": "function (bytes calldata,uint256,uint256,uint32) view returns (bytes32)" + } + }, + "id": 33960, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "6868:87:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + } + }, + "nodeType": "VariableDeclarationStatement", + "src": "6836:119:43" + }, + { + "assignments": [ + 33963 + ], + "declarations": [ + { + "constant": false, + "id": 33963, + "mutability": "mutable", + "name": "reducedElement", + "nameLocation": "7234:14:43", + "nodeType": "VariableDeclaration", + "scope": 34061, + "src": "7226:22:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 33962, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "7226:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + } + ], + "id": 33970, + "initialValue": { + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "id": 33969, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": { + "arguments": [ + { + "id": 33966, + "name": "inputHash", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33954, + "src": "7259:9:43", + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + } + ], + "id": 33965, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "7251:7:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_uint256_$", + "typeString": "type(uint256)" + }, + "typeName": { + "id": 33964, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "7251:7:43", + "typeDescriptions": {} + } + }, + "id": 33967, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "7251:18:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "nodeType": "BinaryOperation", + "operator": "%", + "rightExpression": { + "id": 33968, + "name": "SNARK_SCALAR_FIELD", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32776, + "src": "7272:18:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "src": "7251:39:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "nodeType": "VariableDeclarationStatement", + "src": "7226:64:43" + }, + { + "assignments": [ + 33973 + ], + "declarations": [ + { + "constant": false, + "id": 33973, + "mutability": "mutable", + "name": "deletionVerifier", + "nameLocation": "7388:16:43", + "nodeType": "VariableDeclaration", + "scope": 34061, + "src": "7374:30:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_contract$_ITreeVerifier_$34478", + "typeString": "contract ITreeVerifier" + }, + "typeName": { + "id": 33972, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 33971, + "name": "ITreeVerifier", + "nameLocations": [ + "7374:13:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 34478, + "src": "7374:13:43" + }, + "referencedDeclaration": 34478, + "src": "7374:13:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_ITreeVerifier_$34478", + "typeString": "contract ITreeVerifier" + } + }, + "visibility": "internal" + } + ], + "id": 33978, + "initialValue": { + "arguments": [ + { + "id": 33976, + "name": "batchSize", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33928, + "src": "7445:9:43", + "typeDescriptions": { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + } + ], + "expression": { + "id": 33974, + "name": "batchDeletionVerifiers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33906, + "src": "7407:22:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "id": 33975, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberLocation": "7430:14:43", + "memberName": "getVerifierFor", + "nodeType": "MemberAccess", + "referencedDeclaration": 34297, + "src": "7407:37:43", + "typeDescriptions": { + "typeIdentifier": "t_function_external_view$_t_uint256_$returns$_t_contract$_ITreeVerifier_$34478_$", + "typeString": "function (uint256) view external returns (contract ITreeVerifier)" + } + }, + "id": 33977, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "7407:48:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_contract$_ITreeVerifier_$34478", + "typeString": "contract ITreeVerifier" + } + }, + "nodeType": "VariableDeclarationStatement", + "src": "7374:81:43" + }, + { + "clauses": [ + { + "block": { + "id": 34044, + "nodeType": "Block", + "src": "7813:634:43", + "statements": [ + { + "condition": { + "id": 34017, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "UnaryOperation", + "operator": "!", + "prefix": true, + "src": "7901:15:43", + "subExpression": { + "id": 34016, + "name": "verifierResult", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 34014, + "src": "7902:14:43", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "id": 34022, + "nodeType": "IfStatement", + "src": "7897:85:43", + "trueBody": { + "id": 34021, + "nodeType": "Block", + "src": "7918:64:43", + "statements": [ + { + "errorCall": { + "arguments": [], + "expression": { + "argumentTypes": [], + "id": 34018, + "name": "ProofValidationFailure", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32861, + "src": "7943:22:43", + "typeDescriptions": { + "typeIdentifier": "t_function_error_pure$__$returns$__$", + "typeString": "function () pure" + } + }, + "id": 34019, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "7943:24:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 34020, + "nodeType": "RevertStatement", + "src": "7936:31:43" + } + ] + } + }, + { + "expression": { + "id": 34025, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftHandSide": { + "id": 34023, + "name": "_latestRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32764, + "src": "8150:11:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "nodeType": "Assignment", + "operator": "=", + "rightHandSide": { + "id": 34024, + "name": "postRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33934, + "src": "8164:8:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "src": "8150:22:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "id": 34026, + "nodeType": "ExpressionStatement", + "src": "8150:22:43" + }, + { + "expression": { + "id": 34035, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftHandSide": { + "baseExpression": { + "id": 34027, + "name": "rootHistory", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32769, + "src": "8318:11:43", + "typeDescriptions": { + "typeIdentifier": "t_mapping$_t_uint256_$_t_uint128_$", + "typeString": "mapping(uint256 => uint128)" + } + }, + "id": 34029, + "indexExpression": { + "id": 34028, + "name": "preRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33932, + "src": "8330:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": true, + "nodeType": "IndexAccess", + "src": "8318:20:43", + "typeDescriptions": { + "typeIdentifier": "t_uint128", + "typeString": "uint128" + } + }, + "nodeType": "Assignment", + "operator": "=", + "rightHandSide": { + "arguments": [ + { + "expression": { + "id": 34032, + "name": "block", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -4, + "src": "8349:5:43", + "typeDescriptions": { + "typeIdentifier": "t_magic_block", + "typeString": "block" + } + }, + "id": 34033, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberLocation": "8355:9:43", + "memberName": "timestamp", + "nodeType": "MemberAccess", + "src": "8349:15:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "id": 34031, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "8341:7:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_uint128_$", + "typeString": "type(uint128)" + }, + "typeName": { + "id": 34030, + "name": "uint128", + "nodeType": "ElementaryTypeName", + "src": "8341:7:43", + "typeDescriptions": {} + } + }, + "id": 34034, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "8341:24:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_uint128", + "typeString": "uint128" + } + }, + "src": "8318:47:43", + "typeDescriptions": { + "typeIdentifier": "t_uint128", + "typeString": "uint128" + } + }, + "id": 34036, + "nodeType": "ExpressionStatement", + "src": "8318:47:43" + }, + { + "eventCall": { + "arguments": [ + { + "id": 34038, + "name": "preRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33932, + "src": "8397:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "expression": { + "id": 34039, + "name": "TreeChange", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32819, + "src": "8406:10:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_enum$_TreeChange_$32819_$", + "typeString": "type(enum WorldIDIdentityManagerImplV1.TreeChange)" + } + }, + "id": 34040, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "memberLocation": "8417:8:43", + "memberName": "Deletion", + "nodeType": "MemberAccess", + "referencedDeclaration": 32817, + "src": "8406:19:43", + "typeDescriptions": { + "typeIdentifier": "t_enum$_TreeChange_$32819", + "typeString": "enum WorldIDIdentityManagerImplV1.TreeChange" + } + }, + { + "id": 34041, + "name": "postRoot", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33934, + "src": "8427:8:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_enum$_TreeChange_$32819", + "typeString": "enum WorldIDIdentityManagerImplV1.TreeChange" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "id": 34037, + "name": "TreeChanged", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32895, + "src": "8385:11:43", + "typeDescriptions": { + "typeIdentifier": "t_function_event_nonpayable$_t_uint256_$_t_enum$_TreeChange_$32819_$_t_uint256_$returns$__$", + "typeString": "function (uint256,enum WorldIDIdentityManagerImplV1.TreeChange,uint256)" + } + }, + "id": 34042, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "8385:51:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 34043, + "nodeType": "EmitStatement", + "src": "8380:56:43" + } + ] + }, + "errorName": "", + "id": 34045, + "nodeType": "TryCatchClause", + "parameters": { + "id": 34015, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 34014, + "mutability": "mutable", + "name": "verifierResult", + "nameLocation": "7797:14:43", + "nodeType": "VariableDeclaration", + "scope": 34045, + "src": "7792:19:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + }, + "typeName": { + "id": 34013, + "name": "bool", + "nodeType": "ElementaryTypeName", + "src": "7792:4:43", + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "visibility": "internal" + } + ], + "src": "7791:21:43" + }, + "src": "7783:664:43" + }, + { + "block": { + "id": 34053, + "nodeType": "Block", + "src": "8485:100:43", + "statements": [ + { + "documentation": "This is not the revert we're looking for.", + "expression": { + "arguments": [ + { + "id": 34050, + "name": "errString", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 34047, + "src": "8564:9:43", + "typeDescriptions": { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string memory" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string memory" + } + ], + "id": 34049, + "name": "revert", + "nodeType": "Identifier", + "overloadedDeclarations": [ + -19, + -19 + ], + "referencedDeclaration": -19, + "src": "8557:6:43", + "typeDescriptions": { + "typeIdentifier": "t_function_revert_pure$_t_string_memory_ptr_$returns$__$", + "typeString": "function (string memory) pure" + } + }, + "id": 34051, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "8557:17:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 34052, + "nodeType": "ExpressionStatement", + "src": "8557:17:43" + } + ] + }, + "errorName": "Error", + "id": 34054, + "nodeType": "TryCatchClause", + "parameters": { + "id": 34048, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 34047, + "mutability": "mutable", + "name": "errString", + "nameLocation": "8474:9:43", + "nodeType": "VariableDeclaration", + "scope": 34054, + "src": "8460:23:43", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string" + }, + "typeName": { + "id": 34046, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "8460:6:43", + "typeDescriptions": { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "visibility": "internal" + } + ], + "src": "8459:25:43" + }, + "src": "8448:137:43" + }, + { + "block": { + "id": 34058, + "nodeType": "Block", + "src": "8592:220:43", + "statements": [ + { + "errorCall": { + "arguments": [], + "expression": { + "argumentTypes": [], + "id": 34055, + "name": "ProofValidationFailure", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32861, + "src": "8777:22:43", + "typeDescriptions": { + "typeIdentifier": "t_function_error_pure$__$returns$__$", + "typeString": "function () pure" + } + }, + "id": 34056, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "8777:24:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 34057, + "nodeType": "RevertStatement", + "src": "8770:31:43" + } + ] + }, + "errorName": "", + "id": 34059, + "nodeType": "TryCatchClause", + "src": "8586:226:43" + } + ], + "externalCall": { + "arguments": [ + { + "components": [ + { + "baseExpression": { + "id": 33981, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7567:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 33983, + "indexExpression": { + "hexValue": "30", + "id": 33982, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7581:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_0_by_1", + "typeString": "int_const 0" + }, + "value": "0" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7567:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "baseExpression": { + "id": 33984, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7585:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 33986, + "indexExpression": { + "hexValue": "31", + "id": 33985, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7599:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_1_by_1", + "typeString": "int_const 1" + }, + "value": "1" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7585:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "id": 33987, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "7566:36:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$2_memory_ptr", + "typeString": "uint256[2] memory" + } + }, + { + "components": [ + { + "components": [ + { + "baseExpression": { + "id": 33988, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7618:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 33990, + "indexExpression": { + "hexValue": "32", + "id": 33989, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7632:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_2_by_1", + "typeString": "int_const 2" + }, + "value": "2" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7618:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "baseExpression": { + "id": 33991, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7636:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 33993, + "indexExpression": { + "hexValue": "33", + "id": 33992, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7650:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_3_by_1", + "typeString": "int_const 3" + }, + "value": "3" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7636:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "id": 33994, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "7617:36:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$2_memory_ptr", + "typeString": "uint256[2] memory" + } + }, + { + "components": [ + { + "baseExpression": { + "id": 33995, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7656:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 33997, + "indexExpression": { + "hexValue": "34", + "id": 33996, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7670:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_4_by_1", + "typeString": "int_const 4" + }, + "value": "4" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7656:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "baseExpression": { + "id": 33998, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7674:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 34000, + "indexExpression": { + "hexValue": "35", + "id": 33999, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7688:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_5_by_1", + "typeString": "int_const 5" + }, + "value": "5" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7674:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "id": 34001, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "7655:36:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$2_memory_ptr", + "typeString": "uint256[2] memory" + } + } + ], + "id": 34002, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "7616:76:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_array$_t_uint256_$2_memory_ptr_$2_memory_ptr", + "typeString": "uint256[2] memory[2] memory" + } + }, + { + "components": [ + { + "baseExpression": { + "id": 34003, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7707:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 34005, + "indexExpression": { + "hexValue": "36", + "id": 34004, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7721:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_6_by_1", + "typeString": "int_const 6" + }, + "value": "6" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7707:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "baseExpression": { + "id": 34006, + "name": "deletionProof", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33926, + "src": "7725:13:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8] calldata" + } + }, + "id": 34008, + "indexExpression": { + "hexValue": "37", + "id": 34007, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "7739:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_7_by_1", + "typeString": "int_const 7" + }, + "value": "7" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "IndexAccess", + "src": "7725:16:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "id": 34009, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "7706:36:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$2_memory_ptr", + "typeString": "uint256[2] memory" + } + }, + { + "components": [ + { + "id": 34010, + "name": "reducedElement", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33963, + "src": "7757:14:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + ], + "id": 34011, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "7756:16:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$1_memory_ptr", + "typeString": "uint256[1] memory" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_array$_t_uint256_$2_memory_ptr", + "typeString": "uint256[2] memory" + }, + { + "typeIdentifier": "t_array$_t_array$_t_uint256_$2_memory_ptr_$2_memory_ptr", + "typeString": "uint256[2] memory[2] memory" + }, + { + "typeIdentifier": "t_array$_t_uint256_$2_memory_ptr", + "typeString": "uint256[2] memory" + }, + { + "typeIdentifier": "t_array$_t_uint256_$1_memory_ptr", + "typeString": "uint256[1] memory" + } + ], + "expression": { + "id": 33979, + "name": "deletionVerifier", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33973, + "src": "7524:16:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_ITreeVerifier_$34478", + "typeString": "contract ITreeVerifier" + } + }, + "id": 33980, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberLocation": "7541:11:43", + "memberName": "verifyProof", + "nodeType": "MemberAccess", + "referencedDeclaration": 34477, + "src": "7524:28:43", + "typeDescriptions": { + "typeIdentifier": "t_function_external_nonpayable$_t_array$_t_uint256_$2_memory_ptr_$_t_array$_t_array$_t_uint256_$2_memory_ptr_$2_memory_ptr_$_t_array$_t_uint256_$2_memory_ptr_$_t_array$_t_uint256_$1_memory_ptr_$returns$_t_bool_$", + "typeString": "function (uint256[2] memory,uint256[2] memory[2] memory,uint256[2] memory,uint256[1] memory) external returns (bool)" + } + }, + "id": 34012, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "7524:258:43", + "tryCall": true, + "typeDescriptions": { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + }, + "id": 34060, + "nodeType": "TryStatement", + "src": "7520:1292:43" + } + ] + }, + "documentation": { + "id": 33922, + "nodeType": "StructuredDocumentation", + "src": "4175:2200:43", + "text": "@notice Deletes identities from the WorldID system.\n @dev Can only be called by the owner.\n @dev Deletion is performed off-chain and verified on-chain via the `deletionProof`.\n This saves gas and time over deleting identities one at a time.\n @param deletionProof The proof that given the conditions (`preRoot` and `packedDeletionIndices`),\n deletion into the tree results in `postRoot`. Elements 0 and 1 are the `x` and `y`\n coordinates for `ar` respectively. Elements 2 and 3 are the `x` coordinate for `bs`,\n and elements 4 and 5 are the `y` coordinate for `bs`. Elements 6 and 7 are the `x`\n and `y` coordinates for `krs`.\n @param batchSize The number of identities that are to be deleted in the current batch.\n @param packedDeletionIndices The indices of the identities that were deleted from the tree.\n @param preRoot The value for the root of the tree before the `identityCommitments` have been\n inserted. Must be an element of the field `Kr`.\n @param postRoot The root obtained after deleting all of `identityCommitments` into the tree\n described by `preRoot`. Must be an element of the field `Kr`.\n @custom:reverts Unauthorized If the message sender is not authorised to add identities.\n @custom:reverts InvalidCommitment If one or more of the provided commitments is invalid.\n @custom:reverts NotLatestRoot If the provided `preRoot` is not the latest root.\n @custom:reverts ProofValidationFailure If `deletionProof` cannot be verified using the\n provided inputs.\n @custom:reverts UnreducedElement If any of the `preRoot`, `postRoot` and\n `identityCommitments` is not an element of the field `Kr`. It describes the\n type and value of the unreduced element.\n @custom:reverts VerifierLookupTable.NoSuchVerifier If the batch sizes doesn't match a known\n verifier.\n @custom:reverts VerifierLookupTable.BatchTooLarge If the batch size exceeds the maximum\n batch size." + }, + "functionSelector": "23cfdba5", + "implemented": true, + "kind": "function", + "modifiers": [ + { + "id": 33937, + "kind": "modifierInvocation", + "modifierName": { + "id": 33936, + "name": "onlyProxy", + "nameLocations": [ + "6593:9:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 29855, + "src": "6593:9:43" + }, + "nodeType": "ModifierInvocation", + "src": "6593:9:43" + }, + { + "id": 33939, + "kind": "modifierInvocation", + "modifierName": { + "id": 33938, + "name": "onlyInitialized", + "nameLocations": [ + "6603:15:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 47873, + "src": "6603:15:43" + }, + "nodeType": "ModifierInvocation", + "src": "6603:15:43" + }, + { + "id": 33941, + "kind": "modifierInvocation", + "modifierName": { + "id": 33940, + "name": "onlyIdentityOperator", + "nameLocations": [ + "6619:20:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 33895, + "src": "6619:20:43" + }, + "nodeType": "ModifierInvocation", + "src": "6619:20:43" + } + ], + "name": "deleteIdentities", + "nameLocation": "6389:16:43", + "parameters": { + "id": 33935, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 33926, + "mutability": "mutable", + "name": "deletionProof", + "nameLocation": "6435:13:43", + "nodeType": "VariableDeclaration", + "scope": 34062, + "src": "6415:33:43", + "stateVariable": false, + "storageLocation": "calldata", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_calldata_ptr", + "typeString": "uint256[8]" + }, + "typeName": { + "baseType": { + "id": 33923, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "6415:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "id": 33925, + "length": { + "hexValue": "38", + "id": 33924, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "6423:1:43", + "typeDescriptions": { + "typeIdentifier": "t_rational_8_by_1", + "typeString": "int_const 8" + }, + "value": "8" + }, + "nodeType": "ArrayTypeName", + "src": "6415:10:43", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$8_storage_ptr", + "typeString": "uint256[8]" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 33928, + "mutability": "mutable", + "name": "batchSize", + "nameLocation": "6465:9:43", + "nodeType": "VariableDeclaration", + "scope": 34062, + "src": "6458:16:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + }, + "typeName": { + "id": 33927, + "name": "uint32", + "nodeType": "ElementaryTypeName", + "src": "6458:6:43", + "typeDescriptions": { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 33930, + "mutability": "mutable", + "name": "packedDeletionIndices", + "nameLocation": "6499:21:43", + "nodeType": "VariableDeclaration", + "scope": 34062, + "src": "6484:36:43", + "stateVariable": false, + "storageLocation": "calldata", + "typeDescriptions": { + "typeIdentifier": "t_bytes_calldata_ptr", + "typeString": "bytes" + }, + "typeName": { + "id": 33929, + "name": "bytes", + "nodeType": "ElementaryTypeName", + "src": "6484:5:43", + "typeDescriptions": { + "typeIdentifier": "t_bytes_storage_ptr", + "typeString": "bytes" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 33932, + "mutability": "mutable", + "name": "preRoot", + "nameLocation": "6538:7:43", + "nodeType": "VariableDeclaration", + "scope": 34062, + "src": "6530:15:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 33931, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "6530:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 33934, + "mutability": "mutable", + "name": "postRoot", + "nameLocation": "6563:8:43", + "nodeType": "VariableDeclaration", + "scope": 34062, + "src": "6555:16:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 33933, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "6555:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + } + ], + "src": "6405:172:43" + }, + "returnParameters": { + "id": 33942, + "nodeType": "ParameterList", + "parameters": [], + "src": "6640:0:43" + }, + "scope": 34135, + "stateMutability": "nonpayable", + "virtual": true, + "visibility": "public" + }, + { + "id": 34078, + "nodeType": "FunctionDefinition", + "src": "9156:228:43", + "nodes": [], + "body": { + "id": 34077, + "nodeType": "Block", + "src": "9329:55:43", + "nodes": [], + "statements": [ + { + "expression": { + "arguments": [ + { + "id": 34074, + "name": "batchDeletionVerifiers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33906, + "src": "9354:22:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + ], + "id": 34073, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "9346:7:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_address_$", + "typeString": "type(address)" + }, + "typeName": { + "id": 34072, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "9346:7:43", + "typeDescriptions": {} + } + }, + "id": 34075, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "9346:31:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "functionReturnParameters": 34071, + "id": 34076, + "nodeType": "Return", + "src": "9339:38:43" + } + ] + }, + "documentation": { + "id": 34063, + "nodeType": "StructuredDocumentation", + "src": "8824:327:43", + "text": "@notice Gets the address for the lookup table of merkle tree verifiers used for batch identity\n deletions.\n @dev The deletion verifier supports batch deletions of size 10, 100 and 1000 members per batch.\n @return addr The address of the contract being used as the verifier lookup table." + }, + "functionSelector": "3e8919b6", + "implemented": true, + "kind": "function", + "modifiers": [ + { + "id": 34066, + "kind": "modifierInvocation", + "modifierName": { + "id": 34065, + "name": "onlyProxy", + "nameLocations": [ + "9265:9:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 29855, + "src": "9265:9:43" + }, + "nodeType": "ModifierInvocation", + "src": "9265:9:43" + }, + { + "id": 34068, + "kind": "modifierInvocation", + "modifierName": { + "id": 34067, + "name": "onlyInitialized", + "nameLocations": [ + "9283:15:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 47873, + "src": "9283:15:43" + }, + "nodeType": "ModifierInvocation", + "src": "9283:15:43" + } + ], + "name": "getDeleteIdentitiesVerifierLookupTableAddress", + "nameLocation": "9165:45:43", + "parameters": { + "id": 34064, + "nodeType": "ParameterList", + "parameters": [], + "src": "9210:2:43" + }, + "returnParameters": { + "id": 34071, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 34070, + "mutability": "mutable", + "name": "", + "nameLocation": "-1:-1:-1", + "nodeType": "VariableDeclaration", + "scope": 34078, + "src": "9316:7:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "typeName": { + "id": 34069, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "9316:7:43", + "stateMutability": "nonpayable", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "visibility": "internal" + } + ], + "src": "9315:9:43" + }, + "scope": 34135, + "stateMutability": "view", + "virtual": true, + "visibility": "public" + }, + { + "id": 34114, + "nodeType": "FunctionDefinition", + "src": "9704:418:43", + "nodes": [], + "body": { + "id": 34113, + "nodeType": "Block", + "src": "9877:245:43", + "nodes": [], + "statements": [ + { + "assignments": [ + 34093 + ], + "declarations": [ + { + "constant": false, + "id": 34093, + "mutability": "mutable", + "name": "oldTable", + "nameLocation": "9907:8:43", + "nodeType": "VariableDeclaration", + "scope": 34113, + "src": "9887:28:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + }, + "typeName": { + "id": 34092, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 34091, + "name": "VerifierLookupTable", + "nameLocations": [ + "9887:19:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 34425, + "src": "9887:19:43" + }, + "referencedDeclaration": 34425, + "src": "9887:19:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "visibility": "internal" + } + ], + "id": 34095, + "initialValue": { + "id": 34094, + "name": "batchDeletionVerifiers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33906, + "src": "9918:22:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "nodeType": "VariableDeclarationStatement", + "src": "9887:53:43" + }, + { + "expression": { + "id": 34098, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftHandSide": { + "id": 34096, + "name": "batchDeletionVerifiers", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 33906, + "src": "9950:22:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "nodeType": "Assignment", + "operator": "=", + "rightHandSide": { + "id": 34097, + "name": "newTable", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 34082, + "src": "9975:8:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "src": "9950:33:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "id": 34099, + "nodeType": "ExpressionStatement", + "src": "9950:33:43" + }, + { + "eventCall": { + "arguments": [ + { + "expression": { + "id": 34101, + "name": "Dependency", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32826, + "src": "10029:10:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_enum$_Dependency_$32826_$", + "typeString": "type(enum WorldIDIdentityManagerImplV1.Dependency)" + } + }, + "id": 34102, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "memberLocation": "10040:27:43", + "memberName": "DeletionVerifierLookupTable", + "nodeType": "MemberAccess", + "referencedDeclaration": 32823, + "src": "10029:38:43", + "typeDescriptions": { + "typeIdentifier": "t_enum$_Dependency_$32826", + "typeString": "enum WorldIDIdentityManagerImplV1.Dependency" + } + }, + { + "arguments": [ + { + "id": 34105, + "name": "oldTable", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 34093, + "src": "10077:8:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + ], + "id": 34104, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "10069:7:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_address_$", + "typeString": "type(address)" + }, + "typeName": { + "id": 34103, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "10069:7:43", + "typeDescriptions": {} + } + }, + "id": 34106, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "10069:17:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + { + "arguments": [ + { + "id": 34109, + "name": "newTable", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 34082, + "src": "10096:8:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + ], + "id": 34108, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "10088:7:43", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_address_$", + "typeString": "type(address)" + }, + "typeName": { + "id": 34107, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "10088:7:43", + "typeDescriptions": {} + } + }, + "id": 34110, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "10088:17:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_enum$_Dependency_$32826", + "typeString": "enum WorldIDIdentityManagerImplV1.Dependency" + }, + { + "typeIdentifier": "t_address", + "typeString": "address" + }, + { + "typeIdentifier": "t_address", + "typeString": "address" + } + ], + "id": 34100, + "name": "DependencyUpdated", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 32905, + "src": "9998:17:43", + "typeDescriptions": { + "typeIdentifier": "t_function_event_nonpayable$_t_enum$_Dependency_$32826_$_t_address_$_t_address_$returns$__$", + "typeString": "function (enum WorldIDIdentityManagerImplV1.Dependency,address,address)" + } + }, + "id": 34111, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "9998:117:43", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 34112, + "nodeType": "EmitStatement", + "src": "9993:122:43" + } + ] + }, + "documentation": { + "id": 34079, + "nodeType": "StructuredDocumentation", + "src": "9390:309:43", + "text": "@notice Sets the address for the lookup table of merkle tree verifiers used for identity\n deletions.\n @dev Only the owner of the contract can call this function.\n @param newTable The new verifier lookup table to be used for verifying identity\n deletions." + }, + "functionSelector": "aa4a729e", + "implemented": true, + "kind": "function", + "modifiers": [ + { + "id": 34085, + "kind": "modifierInvocation", + "modifierName": { + "id": 34084, + "name": "onlyProxy", + "nameLocations": [ + "9821:9:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 29855, + "src": "9821:9:43" + }, + "nodeType": "ModifierInvocation", + "src": "9821:9:43" + }, + { + "id": 34087, + "kind": "modifierInvocation", + "modifierName": { + "id": 34086, + "name": "onlyInitialized", + "nameLocations": [ + "9839:15:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 47873, + "src": "9839:15:43" + }, + "nodeType": "ModifierInvocation", + "src": "9839:15:43" + }, + { + "id": 34089, + "kind": "modifierInvocation", + "modifierName": { + "id": 34088, + "name": "onlyOwner", + "nameLocations": [ + "9863:9:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 29157, + "src": "9863:9:43" + }, + "nodeType": "ModifierInvocation", + "src": "9863:9:43" + } + ], + "name": "setDeleteIdentitiesVerifierLookupTable", + "nameLocation": "9713:38:43", + "parameters": { + "id": 34083, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 34082, + "mutability": "mutable", + "name": "newTable", + "nameLocation": "9772:8:43", + "nodeType": "VariableDeclaration", + "scope": 34114, + "src": "9752:28:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + }, + "typeName": { + "id": 34081, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 34080, + "name": "VerifierLookupTable", + "nameLocations": [ + "9752:19:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 34425, + "src": "9752:19:43" + }, + "referencedDeclaration": 34425, + "src": "9752:19:43", + "typeDescriptions": { + "typeIdentifier": "t_contract$_VerifierLookupTable_$34425", + "typeString": "contract VerifierLookupTable" + } + }, + "visibility": "internal" + } + ], + "src": "9751:30:43" + }, + "returnParameters": { + "id": 34090, + "nodeType": "ParameterList", + "parameters": [], + "src": "9877:0:43" + }, + "scope": 34135, + "stateMutability": "nonpayable", + "virtual": true, + "visibility": "public" + }, + { + "id": 34134, + "nodeType": "FunctionDefinition", + "src": "11363:685:43", + "nodes": [], + "body": { + "id": 34133, + "nodeType": "Block", + "src": "11605:443:43", + "nodes": [], + "statements": [ + { + "AST": { + "nativeSrc": "11624:418:43", + "nodeType": "YulBlock", + "src": "11624:418:43", + "statements": [ + { + "nativeSrc": "11638:30:43", + "nodeType": "YulVariableDeclaration", + "src": "11638:30:43", + "value": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "11663:4:43", + "nodeType": "YulLiteral", + "src": "11663:4:43", + "type": "", + "value": "0x40" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "11657:5:43", + "nodeType": "YulIdentifier", + "src": "11657:5:43" + }, + "nativeSrc": "11657:11:43", + "nodeType": "YulFunctionCall", + "src": "11657:11:43" + }, + "variables": [ + { + "name": "startOffset", + "nativeSrc": "11642:11:43", + "nodeType": "YulTypedName", + "src": "11642:11:43", + "type": "" + } + ] + }, + { + "nativeSrc": "11681:40:43", + "nodeType": "YulVariableDeclaration", + "src": "11681:40:43", + "value": { + "arguments": [ + { + "name": "batchSize", + "nativeSrc": "11708:9:43", + "nodeType": "YulIdentifier", + "src": "11708:9:43" + }, + { + "kind": "number", + "nativeSrc": "11719:1:43", + "nodeType": "YulLiteral", + "src": "11719:1:43", + "type": "", + "value": "4" + } + ], + "functionName": { + "name": "mul", + "nativeSrc": "11704:3:43", + "nodeType": "YulIdentifier", + "src": "11704:3:43" + }, + "nativeSrc": "11704:17:43", + "nodeType": "YulFunctionCall", + "src": "11704:17:43" + }, + "variables": [ + { + "name": "indicesByteSize", + "nativeSrc": "11685:15:43", + "nodeType": "YulTypedName", + "src": "11685:15:43", + "type": "" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "startOffset", + "nativeSrc": "11747:11:43", + "nodeType": "YulIdentifier", + "src": "11747:11:43" + }, + { + "name": "packedDeletionIndices.offset", + "nativeSrc": "11760:28:43", + "nodeType": "YulIdentifier", + "src": "11760:28:43" + }, + { + "name": "indicesByteSize", + "nativeSrc": "11790:15:43", + "nodeType": "YulIdentifier", + "src": "11790:15:43" + } + ], + "functionName": { + "name": "calldatacopy", + "nativeSrc": "11734:12:43", + "nodeType": "YulIdentifier", + "src": "11734:12:43" + }, + "nativeSrc": "11734:72:43", + "nodeType": "YulFunctionCall", + "src": "11734:72:43" + }, + "nativeSrc": "11734:72:43", + "nodeType": "YulExpressionStatement", + "src": "11734:72:43" + }, + { + "nativeSrc": "11819:52:43", + "nodeType": "YulVariableDeclaration", + "src": "11819:52:43", + "value": { + "arguments": [ + { + "name": "startOffset", + "nativeSrc": "11842:11:43", + "nodeType": "YulIdentifier", + "src": "11842:11:43" + }, + { + "name": "indicesByteSize", + "nativeSrc": "11855:15:43", + "nodeType": "YulIdentifier", + "src": "11855:15:43" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11838:3:43", + "nodeType": "YulIdentifier", + "src": "11838:3:43" + }, + "nativeSrc": "11838:33:43", + "nodeType": "YulFunctionCall", + "src": "11838:33:43" + }, + "variables": [ + { + "name": "rootsOffset", + "nativeSrc": "11823:11:43", + "nodeType": "YulTypedName", + "src": "11823:11:43", + "type": "" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "rootsOffset", + "nativeSrc": "11891:11:43", + "nodeType": "YulIdentifier", + "src": "11891:11:43" + }, + { + "name": "preRoot", + "nativeSrc": "11904:7:43", + "nodeType": "YulIdentifier", + "src": "11904:7:43" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "11884:6:43", + "nodeType": "YulIdentifier", + "src": "11884:6:43" + }, + "nativeSrc": "11884:28:43", + "nodeType": "YulFunctionCall", + "src": "11884:28:43" + }, + "nativeSrc": "11884:28:43", + "nodeType": "YulExpressionStatement", + "src": "11884:28:43" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "rootsOffset", + "nativeSrc": "11936:11:43", + "nodeType": "YulIdentifier", + "src": "11936:11:43" + }, + { + "kind": "number", + "nativeSrc": "11949:2:43", + "nodeType": "YulLiteral", + "src": "11949:2:43", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11932:3:43", + "nodeType": "YulIdentifier", + "src": "11932:3:43" + }, + "nativeSrc": "11932:20:43", + "nodeType": "YulFunctionCall", + "src": "11932:20:43" + }, + { + "name": "postRoot", + "nativeSrc": "11954:8:43", + "nodeType": "YulIdentifier", + "src": "11954:8:43" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "11925:6:43", + "nodeType": "YulIdentifier", + "src": "11925:6:43" + }, + "nativeSrc": "11925:38:43", + "nodeType": "YulFunctionCall", + "src": "11925:38:43" + }, + "nativeSrc": "11925:38:43", + "nodeType": "YulExpressionStatement", + "src": "11925:38:43" + }, + { + "nativeSrc": "11976:56:43", + "nodeType": "YulAssignment", + "src": "11976:56:43", + "value": { + "arguments": [ + { + "name": "startOffset", + "nativeSrc": "11994:11:43", + "nodeType": "YulIdentifier", + "src": "11994:11:43" + }, + { + "arguments": [ + { + "kind": "number", + "nativeSrc": "12011:2:43", + "nodeType": "YulLiteral", + "src": "12011:2:43", + "type": "", + "value": "64" + }, + { + "name": "indicesByteSize", + "nativeSrc": "12015:15:43", + "nodeType": "YulIdentifier", + "src": "12015:15:43" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "12007:3:43", + "nodeType": "YulIdentifier", + "src": "12007:3:43" + }, + "nativeSrc": "12007:24:43", + "nodeType": "YulFunctionCall", + "src": "12007:24:43" + } + ], + "functionName": { + "name": "keccak256", + "nativeSrc": "11984:9:43", + "nodeType": "YulIdentifier", + "src": "11984:9:43" + }, + "nativeSrc": "11984:48:43", + "nodeType": "YulFunctionCall", + "src": "11984:48:43" + }, + "variableNames": [ + { + "name": "hash", + "nativeSrc": "11976:4:43", + "nodeType": "YulIdentifier", + "src": "11976:4:43" + } + ] + } + ] + }, + "evmVersion": "paris", + "externalReferences": [ + { + "declaration": 34123, + "isOffset": false, + "isSlot": false, + "src": "11708:9:43", + "valueSize": 1 + }, + { + "declaration": 34130, + "isOffset": false, + "isSlot": false, + "src": "11976:4:43", + "valueSize": 1 + }, + { + "declaration": 34117, + "isOffset": true, + "isSlot": false, + "src": "11760:28:43", + "suffix": "offset", + "valueSize": 1 + }, + { + "declaration": 34121, + "isOffset": false, + "isSlot": false, + "src": "11954:8:43", + "valueSize": 1 + }, + { + "declaration": 34119, + "isOffset": false, + "isSlot": false, + "src": "11904:7:43", + "valueSize": 1 + } + ], + "id": 34132, + "nodeType": "InlineAssembly", + "src": "11615:427:43" + } + ] + }, + "documentation": { + "id": 34115, + "nodeType": "StructuredDocumentation", + "src": "10381:977:43", + "text": "@notice Calculates the input hash for the identity deletion verifier.\n @dev Implements the computation described below.\n @param packedDeletionIndices The indices of the identities that were deleted from the tree.\n @param preRoot The root value of the tree before these insertions were made.\n @param postRoot The root value of the tree after these insertions were made.\n @param batchSize The number of identities that were deleted in this batch\n @return hash The input hash calculated as described below.\n @dev the deletion indices are packed into bytes calldata where each deletion index is 32 bits\n wide. The indices are encoded using abi.encodePacked for testing.\n We keccak hash all input to save verification gas. Inputs for the hash are arranged as follows:\n packedDeletionIndices || PreRoot || PostRoot\n 32 bits * batchSize || 256 || 256" + }, + "functionSelector": "31e4e992", + "implemented": true, + "kind": "function", + "modifiers": [ + { + "id": 34126, + "kind": "modifierInvocation", + "modifierName": { + "id": 34125, + "name": "onlyProxy", + "nameLocations": [ + "11556:9:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 29855, + "src": "11556:9:43" + }, + "nodeType": "ModifierInvocation", + "src": "11556:9:43" + }, + { + "id": 34128, + "kind": "modifierInvocation", + "modifierName": { + "id": 34127, + "name": "onlyInitialized", + "nameLocations": [ + "11566:15:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 47873, + "src": "11566:15:43" + }, + "nodeType": "ModifierInvocation", + "src": "11566:15:43" + } + ], + "name": "calculateIdentityDeletionInputHash", + "nameLocation": "11372:34:43", + "parameters": { + "id": 34124, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 34117, + "mutability": "mutable", + "name": "packedDeletionIndices", + "nameLocation": "11431:21:43", + "nodeType": "VariableDeclaration", + "scope": 34134, + "src": "11416:36:43", + "stateVariable": false, + "storageLocation": "calldata", + "typeDescriptions": { + "typeIdentifier": "t_bytes_calldata_ptr", + "typeString": "bytes" + }, + "typeName": { + "id": 34116, + "name": "bytes", + "nodeType": "ElementaryTypeName", + "src": "11416:5:43", + "typeDescriptions": { + "typeIdentifier": "t_bytes_storage_ptr", + "typeString": "bytes" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 34119, + "mutability": "mutable", + "name": "preRoot", + "nameLocation": "11470:7:43", + "nodeType": "VariableDeclaration", + "scope": 34134, + "src": "11462:15:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 34118, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "11462:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 34121, + "mutability": "mutable", + "name": "postRoot", + "nameLocation": "11495:8:43", + "nodeType": "VariableDeclaration", + "scope": 34134, + "src": "11487:16:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 34120, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "11487:7:43", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 34123, + "mutability": "mutable", + "name": "batchSize", + "nameLocation": "11520:9:43", + "nodeType": "VariableDeclaration", + "scope": 34134, + "src": "11513:16:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + }, + "typeName": { + "id": 34122, + "name": "uint32", + "nodeType": "ElementaryTypeName", + "src": "11513:6:43", + "typeDescriptions": { + "typeIdentifier": "t_uint32", + "typeString": "uint32" + } + }, + "visibility": "internal" + } + ], + "src": "11406:129:43" + }, + "returnParameters": { + "id": 34131, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 34130, + "mutability": "mutable", + "name": "hash", + "nameLocation": "11599:4:43", + "nodeType": "VariableDeclaration", + "scope": 34134, + "src": "11591:12:43", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + }, + "typeName": { + "id": 34129, + "name": "bytes32", + "nodeType": "ElementaryTypeName", + "src": "11591:7:43", + "typeDescriptions": { + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" + } + }, + "visibility": "internal" + } + ], + "src": "11590:14:43" + }, + "scope": 34135, + "stateMutability": "view", + "virtual": true, + "visibility": "public" + } + ], + "abstract": false, + "baseContracts": [ + { + "baseName": { + "id": 33901, + "name": "WorldIDIdentityManagerImplV1", + "nameLocations": [ + "484:28:43" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 33896, + "src": "484:28:43" + }, + "id": 33902, + "nodeType": "InheritanceSpecifier", + "src": "484:28:43" + } + ], + "canonicalName": "WorldIDIdentityManagerImplV2", + "contractDependencies": [], + "contractKind": "contract", + "documentation": { + "id": 33900, + "nodeType": "StructuredDocumentation", + "src": "72:371:43", + "text": "@title WorldID Identity Manager Implementation Version 2\n @author Worldcoin\n @notice An implementation of a batch-based identity manager for the WorldID protocol.\n @dev The manager is based on the principle of verifying externally-created Zero Knowledge Proofs\n to perform the insertions.\n @dev This is the implementation delegated to by a proxy." + }, + "fullyImplemented": true, + "linearizedBaseContracts": [ + 34135, + 33896, + 34502, + 34435, + 34190, + 47879, + 29937, + 29622, + 29253, + 29111, + 29243, + 30263, + 29801 + ], + "name": "WorldIDIdentityManagerImplV2", + "nameLocation": "452:28:43", + "scope": 34136, + "usedErrors": [ + 32848, + 32853, + 32858, + 32861, + 32868, + 32871, + 32874, + 32877, + 32882, + 32885, + 34166, + 34431, + 34434, + 47850 + ], + "usedEvents": [ + 29037, + 29128, + 29287, + 29431, + 29496, + 29647, + 32895, + 32905, + 32910, + 32917, + 32924, + 32931 + ] + } + ] + }, + "id": 43 +} \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index c8fea0e4..baecd9d8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,24 +3,23 @@ use std::sync::Arc; use std::time::Instant; use anyhow::Result as AnyhowResult; -use chrono::Duration; +use chrono::{Duration, Utc}; use clap::Parser; use hyper::StatusCode; +use ruint::Uint; use semaphore::poseidon_tree::LazyPoseidonTree; use semaphore::protocol::verify_proof; use serde::Serialize; use tracing::{info, instrument, warn}; use crate::contracts::{IdentityManager, SharedIdentityManager}; -use crate::database::prover::{ProverConfiguration as DbProverConf, Provers}; use crate::database::{self, Database}; use crate::ethereum::{self, Ethereum}; use crate::identity_tree::{ CanonicalTreeBuilder, Hash, InclusionProof, RootItem, Status, TreeState, TreeVersionReadOps, }; -use crate::prover::batch_insertion::ProverConfiguration; -use crate::prover::map::make_insertion_map; -use crate::prover::{self, batch_insertion}; +use crate::prover::map::initialize_prover_maps; +use crate::prover::{self, ProverConfiguration, ProverType, Provers}; use crate::server::error::Error as ServerError; use crate::server::{ToResponseCode, VerifySemaphoreProofQuery, VerifySemaphoreProofRequest}; use crate::task_monitor::TaskMonitor; @@ -111,7 +110,7 @@ pub struct Options { pub database: database::Options, #[clap(flatten)] - pub batch_provers: prover::batch_insertion::Options, + pub batch_provers: prover::Options, #[clap(flatten)] pub committer: task_monitor::Options, @@ -154,14 +153,21 @@ impl App { let (ethereum, db) = tokio::try_join!(ethereum, db)?; let database = Arc::new(db); - let mut provers = database.get_provers().await?; + let mut provers: HashSet = database.get_provers().await?; + let non_inserted_provers = Self::merge_env_provers(options.batch_provers, &mut provers); database.insert_provers(non_inserted_provers).await?; - let insertion_prover_map = make_insertion_map(provers)?; - let identity_manager = - IdentityManager::new(options.contracts, ethereum.clone(), insertion_prover_map).await?; + let (insertion_prover_map, deletion_prover_map) = initialize_prover_maps(provers)?; + + let identity_manager = IdentityManager::new( + options.contracts, + ethereum.clone(), + insertion_prover_map, + deletion_prover_map, + ) + .await?; let identity_manager = Arc::new(identity_manager); @@ -297,10 +303,11 @@ impl App { return Err(ServerError::InvalidCommitment); } - if !self.identity_manager.has_provers().await { + if !self.identity_manager.has_insertion_provers().await { warn!( ?commitment, - "Identity Manager has no provers. Add provers with /addBatchSize request." + "Identity Manager has no insertion provers. Add provers with /addBatchSize \ + request." ); return Err(ServerError::NoProversOnIdInsert); } @@ -318,23 +325,112 @@ impl App { return Err(ServerError::DuplicateCommitment); } - self.database.insert_new_identity(commitment).await?; + self.database + .insert_new_identity(commitment, Utc::now()) + .await?; + + Ok(()) + } + + /// Queues a deletion from the merkle tree. + /// + /// # Errors + /// + /// Will return `Err` if identity is already queued, not in the tree, or the + /// queue malfunctions. + #[instrument(level = "debug", skip(self))] + pub async fn delete_identity(&self, commitment: &Hash) -> Result<(), ServerError> { + // Ensure that deletion provers exist + if !self.identity_manager.has_deletion_provers().await { + warn!( + ?commitment, + "Identity Manager has no deletion provers. Add provers with /addBatchSize request." + ); + return Err(ServerError::NoProversOnIdDeletion); + } + + if !self.database.identity_exists(*commitment).await? { + return Err(ServerError::IdentityCommitmentNotFound); + } + + // Get the leaf index for the id commitment + let leaf_index = self + .database + .get_identity_leaf_index(commitment) + .await? + .ok_or(ServerError::IdentityCommitmentNotFound)? + .leaf_index; + + // Check if the id has already been deleted + if self.tree_state.get_latest_tree().get_leaf(leaf_index) == Uint::ZERO { + return Err(ServerError::IdentityAlreadyDeleted); + } + + // Check if the id is already queued for deletion + if self + .database + .identity_is_queued_for_deletion(commitment) + .await? + { + return Err(ServerError::IdentityQueuedForDeletion); + } + + // Check if there are any deletions, if not, set the latest deletion timestamp + // to now to ensure that the new deletion is processed by the next deletion + // interval + if self.database.get_deletions().await?.is_empty() { + self.database.update_latest_deletion(Utc::now()).await?; + } + + // If the id has not been deleted, insert into the deletions table + self.database + .insert_new_deletion(leaf_index, commitment) + .await?; Ok(()) } - fn merge_env_provers( - options: batch_insertion::Options, - existing_provers: &mut Provers, - ) -> Provers { - let options_set: HashSet = options + /// Queues a deletion from the merkle tree. + /// + /// # Errors + /// + /// Will return `Err` if identity is already queued, not in the tree, or the + /// queue malfunctions. + #[instrument(level = "debug", skip(self))] + pub async fn recover_identity( + &self, + existing_commitment: &Hash, + new_commitment: &Hash, + ) -> Result<(), ServerError> { + // Ensure that insertion provers exist + if !self.identity_manager.has_insertion_provers().await { + warn!( + ?new_commitment, + "Identity Manager has no provers. Add provers with /addBatchSize request." + ); + return Err(ServerError::NoProversOnIdInsert); + } + + // Delete the existing id and insert the commitments into the recovery table + self.delete_identity(existing_commitment).await?; + + self.database + .insert_new_recovery(existing_commitment, new_commitment) + .await?; + + Ok(()) + } + + fn merge_env_provers(options: prover::Options, existing_provers: &mut Provers) -> Provers { + let options_set: HashSet = options .prover_urls .0 .into_iter() - .map(|opt| DbProverConf { - url: opt.url, - batch_size: opt.batch_size, - timeout_s: opt.timeout_s, + .map(|opt| ProverConfiguration { + url: opt.url, + batch_size: opt.batch_size, + timeout_s: opt.timeout_s, + prover_type: opt.prover_type, }) .collect(); @@ -361,13 +457,14 @@ impl App { url: String, batch_size: usize, timeout_seconds: u64, + prover_type: ProverType, ) -> Result<(), ServerError> { self.identity_manager - .add_batch_size(&url, batch_size, timeout_seconds) + .add_batch_size(&url, batch_size, timeout_seconds, prover_type) .await?; self.database - .insert_prover_configuration(batch_size, url, timeout_seconds) + .insert_prover_configuration(batch_size, url, timeout_seconds, prover_type) .await?; Ok(()) @@ -378,10 +475,16 @@ impl App { /// Will return `Err` if the requested batch size does not exist. /// Will return `Err` if batch size fails to be removed from database. #[instrument(level = "debug", skip(self))] - pub async fn remove_batch_size(&self, batch_size: usize) -> Result<(), ServerError> { - self.identity_manager.remove_batch_size(batch_size).await?; + pub async fn remove_batch_size( + &self, + batch_size: usize, + prover_type: ProverType, + ) -> Result<(), ServerError> { + self.identity_manager + .remove_batch_size(batch_size, prover_type) + .await?; - self.database.remove_prover(batch_size).await?; + self.database.remove_prover(batch_size, prover_type).await?; Ok(()) } @@ -427,7 +530,11 @@ impl App { .await? .ok_or(ServerError::IdentityCommitmentNotFound)?; - let proof = self.tree_state.get_proof_for(&item); + let (leaf, proof) = self.tree_state.get_proof_for(&item); + + if leaf != *commitment { + return Err(ServerError::InvalidCommitment); + } Ok(InclusionProofResponse(proof)) } diff --git a/src/contracts/abi.rs b/src/contracts/abi.rs index ee3467bb..32f7e7aa 100644 --- a/src/contracts/abi.rs +++ b/src/contracts/abi.rs @@ -2,15 +2,45 @@ use ethers::prelude::abigen; +/// The `TreeChanged` event emitted by the `IdentityManager` contract. +/// Maps to the following enum in the contract code: +/// +/// ```sol +/// enum TreeChange { +/// Insertion, +/// Deletion, +/// Update +/// } +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TreeChangeKind { + Insertion, + Deletion, + Update, +} + +impl From for TreeChangeKind { + fn from(value: u8) -> Self { + match value { + 0 => Self::Insertion, + 1 => Self::Deletion, + 2 => Self::Update, + _ => panic!("Invalid value for TreeChangeKind: {}", value), + } + } +} + abigen!( WorldId, r#"[ struct RootInfo { uint256 root; uint128 supersededTimestamp; bool isValid } event TreeChanged(uint256 indexed preRoot, uint8 indexed kind, uint256 indexed postRoot) function registerIdentities(uint256[8] calldata insertionProof, uint256 preRoot, uint32 startIndex, uint256[] calldata identityCommitments, uint256 postRoot) public virtual + function deleteIdentities(uint256[8] calldata deletionProof, uint32 batchSize, bytes calldata packedDeletionIndices, uint256 preRoot, uint256 postRoot) public virtual function latestRoot() public view virtual returns (uint256 root) function owner() public view virtual returns (address) function queryRoot(uint256 root) public view virtual returns (RootInfo memory) + function getRootHistoryExpiry() external view returns (uint256) ]"#, ); diff --git a/src/contracts/mod.rs b/src/contracts/mod.rs index 044c5f1f..aa0719ab 100644 --- a/src/contracts/mod.rs +++ b/src/contracts/mod.rs @@ -5,22 +5,23 @@ pub mod scanner; use std::collections::HashMap; use std::sync::Arc; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use clap::Parser; use ethers::providers::Middleware; -use ethers::types::{Address, U256}; +use ethers::types::{Address, H256, U256}; use semaphore::Field; use tokio::sync::RwLockReadGuard; use tracing::{error, info, instrument, warn}; -use self::abi::{BridgedWorldId, WorldId}; +use self::abi::{BridgedWorldId, DeleteIdentitiesCall, WorldId}; use crate::ethereum::write::TransactionId; use crate::ethereum::{Ethereum, ReadProvider}; -use crate::prover::batch_insertion::ProverConfiguration; -use crate::prover::map::{InsertionProverMap, ReadOnlyInsertionProver}; -use crate::prover::{batch_insertion, Proof, ReadOnlyProver}; +use crate::prover::identity::Identity; +use crate::prover::map::{DeletionProverMap, InsertionProverMap, ReadOnlyInsertionProver}; +use crate::prover::{Proof, Prover, ProverConfiguration, ProverType, ReadOnlyProver}; use crate::serde_utils::JsonStrWrapper; use crate::server::error::Error as ServerError; +use crate::utils::index_packing::unpack_indices; /// Configuration options for the component responsible for interacting with the /// contract. @@ -58,6 +59,7 @@ pub struct Options { pub struct IdentityManager { ethereum: Ethereum, insertion_prover_map: InsertionProverMap, + deletion_prover_map: DeletionProverMap, abi: WorldId, secondary_abis: Vec>, initial_leaf_value: Field, @@ -79,6 +81,7 @@ impl IdentityManager { options: Options, ethereum: Ethereum, insertion_prover_map: InsertionProverMap, + deletion_prover_map: DeletionProverMap, ) -> anyhow::Result where Self: Sized, @@ -128,6 +131,7 @@ impl IdentityManager { let identity_manager = Self { ethereum, insertion_prover_map, + deletion_prover_map, abi, secondary_abis, initial_leaf_value, @@ -153,10 +157,7 @@ impl IdentityManager { /// Validates that merkle proofs are of the correct length against tree /// depth - pub fn validate_merkle_proofs( - &self, - identity_commitments: &[batch_insertion::Identity], - ) -> anyhow::Result<()> { + pub fn validate_merkle_proofs(&self, identity_commitments: &[Identity]) -> anyhow::Result<()> { for id in identity_commitments { if id.merkle_proof.len() != self.tree_depth { return Err(anyhow!(format!( @@ -170,10 +171,10 @@ impl IdentityManager { Ok(()) } - pub async fn get_suitable_prover( + pub async fn get_suitable_insertion_prover( &self, num_identities: usize, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let prover_map = self.insertion_prover_map.read().await; match RwLockReadGuard::try_map(prover_map, |map| map.get(num_identities)) { @@ -184,13 +185,31 @@ impl IdentityManager { } } + pub async fn get_suitable_deletion_prover( + &self, + num_identities: usize, + ) -> anyhow::Result> { + let prover_map = self.deletion_prover_map.read().await; + + match RwLockReadGuard::try_map(prover_map, |map| map.get(num_identities)) { + Ok(p) => anyhow::Ok(p), + Err(_) => Err(anyhow!( + "No available prover for batch size: {num_identities}" + )), + } + } + + pub async fn root_history_expiry(&self) -> anyhow::Result { + Ok(self.abi.get_root_history_expiry().call().await?) + } + #[instrument(level = "debug", skip(prover, identity_commitments))] - pub async fn prepare_proof( + pub async fn prepare_insertion_proof( prover: ReadOnlyInsertionProver<'_>, start_index: usize, pre_root: U256, + identity_commitments: &[Identity], post_root: U256, - identity_commitments: &[batch_insertion::Identity], ) -> anyhow::Result { let batch_size = identity_commitments.len(); @@ -203,7 +222,7 @@ impl IdentityManager { ); let proof_data: Proof = prover - .generate_proof( + .generate_insertion_proof( actual_start_index, pre_root, post_root, @@ -214,13 +233,39 @@ impl IdentityManager { Ok(proof_data) } + #[instrument(level = "debug", skip(prover, identity_commitments))] + pub async fn prepare_deletion_proof( + prover: ReadOnlyProver<'_, Prover>, + pre_root: U256, + packed_deletion_indices: Vec, + identity_commitments: Vec, + post_root: U256, + ) -> anyhow::Result { + info!( + "Sending {} identities to prover of batch size {}", + identity_commitments.len(), + prover.batch_size() + ); + + let proof_data: Proof = prover + .generate_deletion_proof( + pre_root, + post_root, + packed_deletion_indices, + identity_commitments, + ) + .await?; + + Ok(proof_data) + } + #[instrument(level = "debug", skip(self, identity_commitments, proof_data))] pub async fn register_identities( &self, start_index: usize, pre_root: U256, post_root: U256, - identity_commitments: Vec, + identity_commitments: Vec, proof_data: Proof, ) -> anyhow::Result { let actual_start_index: u32 = start_index.try_into()?; @@ -251,9 +296,39 @@ impl IdentityManager { .map_err(|tx_err| anyhow!("{}", tx_err.to_string())) } + // TODO: docs + #[instrument(level = "debug")] + pub async fn delete_identities( + &self, + deletion_proof: Proof, + batch_size: u32, + packed_deletion_indices: Vec, + pre_root: U256, + post_root: U256, + ) -> anyhow::Result { + let proof_points_array: [U256; 8] = deletion_proof.into(); + + let register_identities_transaction = self + .abi + .delete_identities( + proof_points_array, + batch_size, + packed_deletion_indices.into(), + pre_root, + post_root, + ) + .tx; + + self.ethereum + .send_transaction(register_identities_transaction, true) + .await + .map_err(|tx_err| anyhow!("{}", tx_err.to_string())) + } + #[instrument(level = "debug", skip(self))] pub async fn mine_identities(&self, transaction_id: TransactionId) -> anyhow::Result { let result = self.ethereum.mine_transaction(transaction_id).await?; + Ok(result) } @@ -286,6 +361,48 @@ impl IdentityManager { Ok(latest_root) } + /// Fetches the identity commitments from a + /// `deleteIdentities` transaction by tx hash + #[instrument(level = "debug", skip_all)] + pub async fn fetch_deletion_indices_from_tx( + &self, + tx_hash: H256, + ) -> anyhow::Result> { + let provider = self.ethereum.provider(); + + let tx = provider + .get_transaction(tx_hash) + .await? + .context("Missing tx")?; + + use ethers::abi::AbiDecode; + let delete_identities = DeleteIdentitiesCall::decode(&tx.input)?; + + let packed_deletion_indices: &[u8] = delete_identities.packed_deletion_indices.as_ref(); + let indices = unpack_indices(packed_deletion_indices); + + tracing::error!("unpacked = {indices:?}"); + + let padding_index = 2u32.pow(self.tree_depth as u32); + + Ok(indices + .into_iter() + .filter(|idx| *idx != padding_index) + .map(|x| x as usize) + .collect()) + } + + #[instrument(level = "debug", skip_all)] + pub async fn is_root_mined(&self, root: U256) -> anyhow::Result { + let (root_on_mainnet, ..) = self.abi.query_root(root).call().await?; + + if root_on_mainnet.is_zero() { + return Ok(false); + } + + Ok(true) + } + #[instrument(level = "debug", skip_all)] pub async fn is_root_mined_multi_chain(&self, root: U256) -> anyhow::Result { let (root_on_mainnet, ..) = self.abi.query_root(root).call().await?; @@ -319,16 +436,21 @@ impl IdentityManager { url: &impl ToString, batch_size: usize, timeout_seconds: u64, + prover_type: ProverType, ) -> Result<(), ServerError> { - let mut map = self.insertion_prover_map.write().await; + let mut map = match prover_type { + ProverType::Insertion => self.insertion_prover_map.write().await, + ProverType::Deletion => self.deletion_prover_map.write().await, + }; if map.batch_size_exists(batch_size) { return Err(ServerError::BatchSizeAlreadyExists); } - let prover = batch_insertion::Prover::new(&ProverConfiguration { + let prover = Prover::new(&ProverConfiguration { url: url.to_string(), batch_size, + prover_type, timeout_s: timeout_seconds, })?; @@ -341,8 +463,15 @@ impl IdentityManager { /// /// Will return `Err` if the batch size requested for removal doesn't exist /// in the prover map. - pub async fn remove_batch_size(&self, batch_size: usize) -> Result<(), ServerError> { - let mut map = self.insertion_prover_map.write().await; + pub async fn remove_batch_size( + &self, + batch_size: usize, + prover_type: ProverType, + ) -> Result<(), ServerError> { + let mut map = match prover_type { + ProverType::Insertion => self.insertion_prover_map.write().await, + ProverType::Deletion => self.deletion_prover_map.write().await, + }; if map.len() == 1 { warn!("Attempting to remove the last batch size."); @@ -363,9 +492,13 @@ impl IdentityManager { .as_configuration_vec()) } - pub async fn has_provers(&self) -> bool { + pub async fn has_insertion_provers(&self) -> bool { self.insertion_prover_map.read().await.len() > 0 } + + pub async fn has_deletion_provers(&self) -> bool { + self.deletion_prover_map.read().await.len() > 0 + } } /// A type for an identity manager object that can be sent across threads. diff --git a/src/database/mod.rs b/src/database/mod.rs index a3389d35..cba83032 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -7,6 +7,7 @@ use std::collections::HashSet; use anyhow::{anyhow, Context, Error as ErrReport}; +use chrono::{DateTime, Utc}; use clap::Parser; use sqlx::migrate::{Migrate, MigrateDatabase, Migrator}; use sqlx::pool::PoolOptions; @@ -14,11 +15,11 @@ use sqlx::{Executor, Pool, Postgres, Row}; use thiserror::Error; use tracing::{error, info, instrument, warn}; -use self::prover::ProverConfiguration; +use self::types::{DeletionEntry, LatestDeletionEntry, RecoveryEntry}; use crate::identity_tree::{Hash, RootItem, Status, TreeItem, TreeUpdate}; -pub mod prover; pub mod types; +use crate::prover::{ProverConfiguration, ProverType, Provers}; use crate::secret::SecretUrl; // Statically link in migration files @@ -157,23 +158,23 @@ impl Database { Ok(()) } - pub async fn get_leaf_index_by_root( + pub async fn get_id_by_root( tx: impl Executor<'_, Database = Postgres>, root: &Hash, ) -> Result, Error> { - let root_leaf_index_query = sqlx::query( + let root_index_query = sqlx::query( r#" - SELECT leaf_index FROM identities WHERE root = $1 + SELECT id FROM identities WHERE root = $1 "#, ) .bind(root); - let row = tx.fetch_optional(root_leaf_index_query).await?; + let row = tx.fetch_optional(root_index_query).await?; let Some(row) = row else { return Ok(None) }; - let root_leaf_index = row.get::(0); + let root_id = row.get::(0); - Ok(Some(root_leaf_index as usize)) + Ok(Some(root_id as usize)) } /// Marks the identities and roots from before a given root hash as mined @@ -186,25 +187,24 @@ impl Database { let mut tx = self.pool.begin().await?; - let root_leaf_index = Self::get_leaf_index_by_root(&mut tx, root).await?; + let root_id = Self::get_id_by_root(&mut tx, root).await?; - let Some(root_leaf_index) = root_leaf_index else { + let Some(root_id) = root_id else { return Err(Error::MissingRoot { root: *root }); }; - let root_leaf_index = root_leaf_index as i64; - + let root_id = root_id as i64; // TODO: Can I get rid of line `AND status <> $2 let update_previous_roots = sqlx::query( r#" UPDATE identities SET status = $2, mined_at = CURRENT_TIMESTAMP - WHERE leaf_index <= $1 + WHERE id <= $1 AND status <> $2 AND status <> $3 "#, ) - .bind(root_leaf_index) + .bind(root_id) .bind(<&str>::from(processed_status)) .bind(<&str>::from(mined_status)); @@ -212,10 +212,10 @@ impl Database { r#" UPDATE identities SET status = $2, mined_at = NULL - WHERE leaf_index > $1 + WHERE id > $1 "#, ) - .bind(root_leaf_index) + .bind(root_id) .bind(<&str>::from(pending_status)); tx.execute(update_previous_roots).await?; @@ -234,23 +234,23 @@ impl Database { let mut tx = self.pool.begin().await?; - let root_leaf_index = Self::get_leaf_index_by_root(&mut tx, root).await?; + let root_id = Self::get_id_by_root(&mut tx, root).await?; - let Some(root_leaf_index) = root_leaf_index else { + let Some(root_id) = root_id else { return Err(Error::MissingRoot { root: *root }); }; - let root_leaf_index = root_leaf_index as i64; + let root_id = root_id as i64; let update_previous_roots = sqlx::query( r#" UPDATE identities SET status = $2 - WHERE leaf_index <= $1 + WHERE id <= $1 AND status <> $2 "#, ) - .bind(root_leaf_index) + .bind(root_id) .bind(<&str>::from(mined_status)); tx.execute(update_previous_roots).await?; @@ -286,6 +286,7 @@ impl Database { SELECT leaf_index, status FROM identities WHERE commitment = $1 + ORDER BY id DESC LIMIT 1; "#, ) @@ -389,10 +390,10 @@ impl Database { Ok(result.get::(0) as i32) } - pub async fn get_provers(&self) -> Result { + pub async fn get_provers(&self) -> Result { let query = sqlx::query( r#" - SELECT batch_size, url, timeout_s + SELECT batch_size, url, timeout_s, prover_type FROM provers "#, ); @@ -405,13 +406,15 @@ impl Database { let batch_size = row.get::(0) as usize; let url = row.get::(1); let timeout_s = row.get::(2) as u64; - prover::ProverConfiguration { + let prover_type = row.get::(3); + ProverConfiguration { url, - batch_size, timeout_s, + batch_size, + prover_type, } }) - .collect::()) + .collect::()) } pub async fn insert_prover_configuration( @@ -419,20 +422,20 @@ impl Database { batch_size: usize, url: impl ToString, timeout_seconds: u64, + prover_type: ProverType, ) -> Result<(), Error> { let url = url.to_string(); let query = sqlx::query( r#" - INSERT INTO provers (batch_size, url, timeout_s) - VALUES ($1, $2, $3) - ON CONFLICT (batch_size) - DO UPDATE SET (url, timeout_s) = ($2, $3) + INSERT INTO provers (batch_size, url, timeout_s, prover_type) + VALUES ($1, $2, $3, $4) "#, ) .bind(batch_size as i64) .bind(url) - .bind(timeout_seconds as i64); + .bind(timeout_seconds as i64) + .bind(prover_type); self.pool.execute(query).await?; @@ -446,14 +449,15 @@ impl Database { let mut query_builder = sqlx::QueryBuilder::new( r#" - INSERT INTO provers (batch_size, url, timeout_s) + INSERT INTO provers (batch_size, url, timeout_s, prover_type) "#, ); query_builder.push_values(provers, |mut b, prover| { b.push_bind(prover.batch_size as i64) .push_bind(prover.url) - .push_bind(prover.timeout_s as i64); + .push_bind(prover.timeout_s as i64) + .push_bind(prover.prover_type); }); let query = query_builder.build(); @@ -462,40 +466,188 @@ impl Database { Ok(()) } - pub async fn remove_prover(&self, batch_size: usize) -> Result<(), Error> { + pub async fn remove_prover( + &self, + batch_size: usize, + prover_type: ProverType, + ) -> Result<(), Error> { let query = sqlx::query( r#" - DELETE FROM provers WHERE batch_size = $1 + DELETE FROM provers WHERE batch_size = $1 AND prover_type = $2 "#, ) - .bind(batch_size as i64); + .bind(batch_size as i64) + .bind(prover_type); self.pool.execute(query).await?; Ok(()) } - pub async fn insert_new_identity(&self, identity: Hash) -> Result { + pub async fn insert_new_identity( + &self, + identity: Hash, + eligibility_timestamp: sqlx::types::chrono::DateTime, + ) -> Result { let query = sqlx::query( r#" - INSERT INTO unprocessed_identities (commitment, status, created_at) - VALUES ($1, $2, CURRENT_TIMESTAMP) + INSERT INTO unprocessed_identities (commitment, status, created_at, eligibility) + VALUES ($1, $2, CURRENT_TIMESTAMP, $3) "#, ) .bind(identity) - .bind(<&str>::from(Status::New)); + .bind(<&str>::from(Status::New)) + .bind(eligibility_timestamp); + self.pool.execute(query).await?; Ok(identity) } - pub async fn get_unprocessed_commitments( + pub async fn insert_new_recovery( + &self, + existing_commitment: &Hash, + new_commitment: &Hash, + ) -> Result<(), Error> { + let query = sqlx::query( + r#" + INSERT INTO recoveries (existing_commitment, new_commitment) + VALUES ($1, $2) + "#, + ) + .bind(existing_commitment) + .bind(new_commitment); + self.pool.execute(query).await?; + Ok(()) + } + + pub async fn get_latest_deletion(&self) -> Result { + let query = + sqlx::query("SELECT deletion_timestamp FROM latest_deletion_root WHERE Lock = 'X';"); + + let row = self.pool.fetch_optional(query).await?; + + if let Some(row) = row { + Ok(LatestDeletionEntry { + timestamp: row.get(0), + }) + } else { + Ok(LatestDeletionEntry { + timestamp: Utc::now(), + }) + } + } + + pub async fn update_latest_deletion( + &self, + deletion_timestamp: DateTime, + ) -> Result<(), Error> { + let query = sqlx::query( + r#" + INSERT INTO latest_deletion_root (Lock, deletion_timestamp) + VALUES ('X', $1) + ON CONFLICT (Lock) + DO UPDATE SET deletion_timestamp = EXCLUDED.deletion_timestamp; + "#, + ) + .bind(deletion_timestamp); + + self.pool.execute(query).await?; + Ok(()) + } + + // TODO: consider using a larger value than i64 for leaf index, ruint should + // have postgres compatibility for u256 + pub async fn get_recoveries(&self) -> Result, Error> { + let query = sqlx::query( + r#" + SELECT * + FROM recoveries + "#, + ); + + let result = self.pool.fetch_all(query).await?; + + Ok(result + .into_iter() + .map(|row| RecoveryEntry { + existing_commitment: row.get::(0), + new_commitment: row.get::(1), + }) + .collect::>()) + } + + pub async fn insert_new_deletion( + &self, + leaf_index: usize, + identity: &Hash, + ) -> Result<(), Error> { + let query = sqlx::query( + r#" + INSERT INTO deletions (leaf_index, commitment) + VALUES ($1, $2) + "#, + ) + .bind(leaf_index as i64) + .bind(identity); + + self.pool.execute(query).await?; + Ok(()) + } + + // TODO: consider using a larger value than i64 for leaf index, ruint should + // have postgres compatibility for u256 + pub async fn get_deletions(&self) -> Result, Error> { + let query = sqlx::query( + r#" + SELECT * + FROM deletions + "#, + ); + + let result = self.pool.fetch_all(query).await?; + + Ok(result + .into_iter() + .map(|row| DeletionEntry { + leaf_index: row.get::(0) as usize, + commitment: row.get::(1), + }) + .collect::>()) + } + + /// Remove a list of entries from the deletions table + pub async fn remove_deletions(&self, commitments: Vec) -> Result<(), Error> { + let placeholders: String = commitments + .iter() + .enumerate() + .map(|(i, _)| format!("${}", i + 1)) + .collect::>() + .join(", "); + + let query = format!( + "DELETE FROM deletions WHERE commitment IN ({})", + placeholders + ); + + let mut query = sqlx::query(&query); + + for commitment in &commitments { + query = query.bind(commitment); + } + + query.execute(&self.pool).await?; + + Ok(()) + } + + pub async fn get_eligible_unprocessed_commitments( &self, status: Status, ) -> Result, Error> { let query = sqlx::query( r#" SELECT * FROM unprocessed_identities - WHERE status = $1 + WHERE status = $1 AND CURRENT_TIMESTAMP > eligibility LIMIT $2 "#, ) @@ -512,6 +664,7 @@ impl Database { created_at: row.get::<_, _>(2), processed_at: row.get::<_, _>(3), error_message: row.get::<_, _>(4), + eligibility_timestamp: row.get::<_, _>(5), }) .collect::>()) } @@ -573,14 +726,14 @@ impl Database { pub async fn identity_exists(&self, commitment: Hash) -> Result { let query_unprocessed_identity = sqlx::query( - r#"SELECT exists(SELECT 1 from unprocessed_identities where commitment = $1)"#, + r#"SELECT exists(SELECT 1 FROM unprocessed_identities where commitment = $1)"#, ) .bind(commitment); let row_unprocessed = self.pool.fetch_one(query_unprocessed_identity).await?; let query_processed_identity = - sqlx::query(r#"SELECT exists(SELECT 1 from identities where commitment = $1)"#) + sqlx::query(r#"SELECT exists(SELECT 1 FROM identities where commitment = $1)"#) .bind(commitment); let row_processed = self.pool.fetch_one(query_processed_identity).await?; @@ -589,6 +742,15 @@ impl Database { Ok(exists) } + + // TODO: add docs + pub async fn identity_is_queued_for_deletion(&self, commitment: &Hash) -> Result { + let query_queued_deletion = + sqlx::query(r#"SELECT exists(SELECT 1 FROM deletions where commitment = $1)"#) + .bind(commitment); + let row_unprocessed = self.pool.fetch_one(query_queued_deletion).await?; + Ok(row_unprocessed.get::(0)) + } } #[derive(Debug, Error)] @@ -602,17 +764,20 @@ pub enum Error { #[cfg(test)] mod test { + use std::collections::HashSet; use std::str::FromStr; use std::time::Duration; use anyhow::Context; - use chrono::Utc; + use chrono::{Days, Utc}; use ethers::types::U256; use postgres_docker_utils::DockerContainerGuard; + use ruint::Uint; use semaphore::Field; use super::{Database, Options}; use crate::identity_tree::{Hash, Status}; + use crate::prover::{ProverConfiguration, ProverType}; use crate::secret::SecretUrl; macro_rules! assert_same_time { @@ -635,10 +800,11 @@ mod test { chrono::Duration::milliseconds(x.num_milliseconds().abs()) } + // TODO: we should probably consolidate all tests that propagate errors to + // TODO: either use anyhow or eyre async fn setup_db() -> anyhow::Result<(Database, DockerContainerGuard)> { let db_container = postgres_docker_utils::setup().await?; let port = db_container.port(); - let url = format!("postgres://postgres:postgres@localhost:{port}/database"); let db = Database::new(Options { @@ -683,7 +849,12 @@ mod test { let commit_hash: Hash = U256::from_dec_str(dec) .expect("cant convert to u256") .into(); - let hash = db.insert_new_identity(commit_hash).await?; + + let eligibility_timestamp = Utc::now(); + + let hash = db + .insert_new_identity(commit_hash, eligibility_timestamp) + .await?; assert_eq!(commit_hash, hash); @@ -693,7 +864,11 @@ mod test { .expect("expected commitment status"); assert_eq!(commit.0, Status::New); - let identity_count = db.get_unprocessed_commitments(Status::New).await?.len(); + let identity_count = db + .get_eligible_unprocessed_commitments(Status::New) + .await? + .len(); + assert_eq!(identity_count, 1); assert!(db.remove_unprocessed_identity(&commit_hash).await.is_ok()); @@ -701,6 +876,295 @@ mod test { Ok(()) } + #[tokio::test] + async fn insert_and_delete_identity() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + let zero: Hash = U256::zero().into(); + let zero_root: Hash = U256::from_dec_str("6789")?.into(); + let root: Hash = U256::from_dec_str("54321")?.into(); + let commitment: Hash = U256::from_dec_str("12345")?.into(); + + db.insert_pending_identity(0, &commitment, &root).await?; + db.insert_pending_identity(0, &zero, &zero_root).await?; + + let leaf_index = db + .get_identity_leaf_index(&commitment) + .await? + .context("Missing identity")?; + + assert_eq!(leaf_index.leaf_index, 0); + + Ok(()) + } + + fn mock_provers() -> HashSet { + let mut provers = HashSet::new(); + + provers.insert(ProverConfiguration { + batch_size: 100, + url: "http://localhost:8080".to_string(), + timeout_s: 100, + prover_type: ProverType::Insertion, + }); + + provers.insert(ProverConfiguration { + batch_size: 100, + url: "http://localhost:8080".to_string(), + timeout_s: 100, + prover_type: ProverType::Deletion, + }); + + provers + } + + #[tokio::test] + async fn test_insert_prover_configuration() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + let mock_prover_configuration_0 = ProverConfiguration { + batch_size: 100, + url: "http://localhost:8080".to_string(), + timeout_s: 100, + prover_type: ProverType::Insertion, + }; + + let mock_prover_configuration_1 = ProverConfiguration { + batch_size: 100, + url: "http://localhost:8081".to_string(), + timeout_s: 100, + prover_type: ProverType::Deletion, + }; + + db.insert_prover_configuration( + mock_prover_configuration_0.batch_size, + mock_prover_configuration_0.url.clone(), + mock_prover_configuration_0.timeout_s, + mock_prover_configuration_0.prover_type, + ) + .await?; + + db.insert_prover_configuration( + mock_prover_configuration_1.batch_size, + mock_prover_configuration_1.url.clone(), + mock_prover_configuration_1.timeout_s, + mock_prover_configuration_1.prover_type, + ) + .await?; + + let provers = db.get_provers().await?; + + assert!(provers.contains(&mock_prover_configuration_0)); + assert!(provers.contains(&mock_prover_configuration_1)); + + Ok(()) + } + + #[tokio::test] + async fn test_insert_provers() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let mock_provers = mock_provers(); + + db.insert_provers(mock_provers.clone()).await?; + + let provers = db.get_provers().await?; + + assert_eq!(provers, mock_provers); + Ok(()) + } + + #[tokio::test] + async fn test_remove_prover() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let mock_provers = mock_provers(); + + db.insert_provers(mock_provers.clone()).await?; + db.remove_prover(100, ProverType::Insertion).await?; + let provers = db.get_provers().await?; + + assert_eq!(provers, HashSet::new()); + + Ok(()) + } + + #[tokio::test] + async fn test_insert_new_recovery() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + let existing_commitment: Uint<256, 4> = Uint::from(1); + let new_commitment: Uint<256, 4> = Uint::from(2); + + db.insert_new_recovery(&existing_commitment, &new_commitment) + .await?; + + let recoveries = db.get_recoveries().await?; + + assert_eq!(recoveries.len(), 1); + assert_eq!(recoveries[0].existing_commitment, existing_commitment); + assert_eq!(recoveries[0].new_commitment, new_commitment); + + Ok(()) + } + + #[tokio::test] + async fn test_insert_new_deletion() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let existing_commitment: Uint<256, 4> = Uint::from(1); + + db.insert_new_deletion(0, &existing_commitment).await?; + + let deletions = db.get_deletions().await?; + assert_eq!(deletions.len(), 1); + assert_eq!(deletions[0].leaf_index, 0); + assert_eq!(deletions[0].commitment, existing_commitment); + + Ok(()) + } + + #[tokio::test] + async fn test_get_eligible_unprocessed_commitments() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let commitment_0: Uint<256, 4> = Uint::from(1); + let eligibility_timestamp_0 = Utc::now(); + + db.insert_new_identity(commitment_0, eligibility_timestamp_0) + .await?; + + let commitment_1: Uint<256, 4> = Uint::from(2); + let eligibility_timestamp_1 = Utc::now() + .checked_add_days(Days::new(7)) + .expect("Could not create eligibility timestamp"); + + db.insert_new_identity(commitment_1, eligibility_timestamp_1) + .await?; + + let unprocessed_commitments = db.get_eligible_unprocessed_commitments(Status::New).await?; + + assert_eq!(unprocessed_commitments.len(), 1); + assert_eq!(unprocessed_commitments[0].commitment, commitment_0); + assert!( + unprocessed_commitments[0].eligibility_timestamp.timestamp() + - eligibility_timestamp_0.timestamp() + <= 1 + ); + + Ok(()) + } + + #[tokio::test] + async fn test_get_unprocessed_commitments() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + // Insert new identity with a valid eligibility timestamp + let commitment_0: Uint<256, 4> = Uint::from(1); + let eligibility_timestamp_0 = Utc::now(); + db.insert_new_identity(commitment_0, eligibility_timestamp_0) + .await?; + + // Insert new identity with eligibility timestamp in the future + let commitment_1: Uint<256, 4> = Uint::from(2); + let eligibility_timestamp_1 = Utc::now() + .checked_add_days(Days::new(7)) + .expect("Could not create eligibility timestamp"); + db.insert_new_identity(commitment_1, eligibility_timestamp_1) + .await?; + + let unprocessed_commitments = db.get_eligible_unprocessed_commitments(Status::New).await?; + + // Assert unprocessed commitments against expected values + assert_eq!(unprocessed_commitments.len(), 1); + assert_eq!(unprocessed_commitments[0].commitment, commitment_0); + assert_eq!( + unprocessed_commitments[0].eligibility_timestamp.timestamp(), + eligibility_timestamp_0.timestamp() + ); + + Ok(()) + } + + #[tokio::test] + async fn test_identity_is_queued_for_deletion() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let existing_commitment: Uint<256, 4> = Uint::from(1); + + db.insert_new_deletion(0, &existing_commitment).await?; + + assert!( + db.identity_is_queued_for_deletion(&existing_commitment) + .await? + ); + + Ok(()) + } + + #[tokio::test] + async fn test_update_eligibility_timestamp() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let dec = "1234500000000000000"; + let commit_hash: Hash = U256::from_dec_str(dec) + .expect("cant convert to u256") + .into(); + + // Set eligibility to Utc::now() day and check db entries + let eligibility_timestamp = Utc::now(); + db.insert_new_identity(commit_hash, eligibility_timestamp) + .await?; + + let commitments = db.get_eligible_unprocessed_commitments(Status::New).await?; + assert_eq!(commitments.len(), 1); + + let eligible_commitments = db.get_eligible_unprocessed_commitments(Status::New).await?; + assert_eq!(eligible_commitments.len(), 1); + + // Set eligibility to Utc::now() + 7 days and check db entries + let eligibility_timestamp = Utc::now() + .checked_add_days(Days::new(7)) + .expect("Could not create eligibility timestamp"); + + // Insert new identity with an eligibility timestamp in the future + let commit_hash: Hash = Hash::from(1); + db.insert_new_identity(commit_hash, eligibility_timestamp) + .await?; + + let eligible_commitments = db.get_eligible_unprocessed_commitments(Status::New).await?; + assert_eq!(eligible_commitments.len(), 1); + + Ok(()) + } + + #[tokio::test] + async fn test_insert_deletion() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + let identities = mock_identities(3); + + db.insert_new_deletion(0, &identities[0]).await?; + db.insert_new_deletion(1, &identities[1]).await?; + db.insert_new_deletion(2, &identities[2]).await?; + + let deletions = db.get_deletions().await?; + + assert_eq!(deletions.len(), 3); + + Ok(()) + } + + #[tokio::test] + async fn test_insert_recovery() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + let old_identities = mock_identities(3); + let new_identities = mock_identities(3); + + for (old, new) in old_identities.into_iter().zip(new_identities) { + db.insert_new_recovery(&old, &new).await?; + } + + let recoveries = db.get_recoveries().await?; + assert_eq!(recoveries.len(), 3); + + Ok(()) + } + #[tokio::test] async fn get_last_leaf_index() -> anyhow::Result<()> { let (db, _db_container) = setup_db().await?; @@ -1058,7 +1522,7 @@ mod test { } #[tokio::test] - async fn check_identity_existance() -> anyhow::Result<()> { + async fn check_identity_existence() -> anyhow::Result<()> { let (db, _db_container) = setup_db().await?; let identities = mock_identities(2); @@ -1068,8 +1532,9 @@ mod test { assert!(!db.identity_exists(identities[0]).await?); // When there's only unprocessed identity + let eligibility_timestamp = Utc::now(); - db.insert_new_identity(identities[0]) + db.insert_new_identity(identities[0], eligibility_timestamp) .await .context("Inserting new identity")?; assert!(db.identity_exists(identities[0]).await?); @@ -1083,4 +1548,62 @@ mod test { Ok(()) } + + #[tokio::test] + async fn test_remove_deletions() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + let identities = mock_identities(4); + + // Insert new identities + db.insert_new_deletion(0, &identities[0]) + .await + .context("Inserting new identity")?; + + db.insert_new_deletion(1, &identities[1]) + .await + .context("Inserting new identity")?; + + db.insert_new_deletion(2, &identities[2]) + .await + .context("Inserting new identity")?; + db.insert_new_deletion(3, &identities[3]) + .await + .context("Inserting new identity")?; + + // Remove identities 0 to 2 + db.remove_deletions(identities[0..=2].to_vec()).await?; + let deletions = db.get_deletions().await?; + + assert_eq!(deletions.len(), 1); + + Ok(()) + } + + #[tokio::test] + async fn test_latest_deletion_root() -> anyhow::Result<()> { + let (db, _db_container) = setup_db().await?; + + // Update with initial timestamp + let initial_timestamp = chrono::Utc::now(); + db.update_latest_deletion(initial_timestamp) + .await + .context("Inserting initial root")?; + + // Assert values + let initial_entry = db.get_latest_deletion().await?; + assert!(initial_entry.timestamp.timestamp() - initial_timestamp.timestamp() <= 1); + + // Update with a new timestamp + let new_timestamp = chrono::Utc::now(); + db.update_latest_deletion(new_timestamp) + .await + .context("Updating with new root")?; + + // Assert values + let new_entry = db.get_latest_deletion().await?; + assert!((new_entry.timestamp.timestamp() - new_timestamp.timestamp()) <= 1); + + Ok(()) + } } diff --git a/src/database/prover.rs b/src/database/prover.rs deleted file mode 100644 index 91125bc4..00000000 --- a/src/database/prover.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::collections::HashSet; -use std::hash::{Hash, Hasher}; - -pub type Provers = HashSet; - -#[derive(Debug, Clone)] -pub struct ProverConfiguration { - pub url: String, - pub batch_size: usize, - pub timeout_s: u64, -} - -impl Hash for ProverConfiguration { - fn hash(&self, state: &mut H) { - self.batch_size.hash(state); - } -} - -impl PartialEq for ProverConfiguration { - fn eq(&self, other: &Self) -> bool { - self.batch_size == other.batch_size - } -} - -impl Eq for ProverConfiguration {} diff --git a/src/database/types.rs b/src/database/types.rs index c59c2e79..e3179d3d 100644 --- a/src/database/types.rs +++ b/src/database/types.rs @@ -3,9 +3,25 @@ use chrono::{DateTime, Utc}; use crate::identity_tree::{Hash, Status}; pub struct UnprocessedCommitment { - pub commitment: Hash, - pub status: Status, - pub created_at: DateTime, - pub processed_at: Option>, - pub error_message: Option, + pub commitment: Hash, + pub status: Status, + pub created_at: DateTime, + pub processed_at: Option>, + pub error_message: Option, + pub eligibility_timestamp: DateTime, +} + +pub struct RecoveryEntry { + pub existing_commitment: Hash, + pub new_commitment: Hash, +} + +pub struct LatestDeletionEntry { + pub timestamp: DateTime, +} + +#[derive(Hash, PartialEq, Eq)] +pub struct DeletionEntry { + pub leaf_index: usize, + pub commitment: Hash, } diff --git a/src/identity_tree.rs b/src/identity_tree.rs index d1b109c2..21d2bca9 100644 --- a/src/identity_tree.rs +++ b/src/identity_tree.rs @@ -183,23 +183,46 @@ where self.tree.root() } + /// Gets the leaf value at a given index. + fn get_leaf(&self, leaf: usize) -> Hash { + self.tree.get_leaf(leaf) + } + /// Gets the proof of the given leaf index element fn get_proof(&self, leaf: usize) -> (Hash, Proof) { let proof = self.tree.proof(leaf); (self.tree.root(), proof) } - /// Returns _up to_ `maximum_update_count` updates that are to be applied to - /// the tree. + /// Returns _up to_ `maximum_update_count` contiguous deletion or insertion + /// updates that are to be applied to the tree. fn peek_next_updates(&self, maximum_update_count: usize) -> Vec { let Some(next) = self.next.as_ref() else { return Vec::new(); }; let next = next.get_data(); + + let first_is_zero = match next.metadata.diff.first() { + Some(first) => first.update.element == Hash::ZERO, + None => return vec![], + }; + + // Gets the next contiguous of insertion or deletion updates from the diff + let should_take = |elem: &&AppliedTreeUpdate| { + if first_is_zero { + // If first is zero, we should take only consecutive zeros + elem.update.element == Hash::ZERO + } else { + // If first is not zero, we should take only non-zeros + elem.update.element != Hash::ZERO + } + }; + next.metadata .diff .iter() + .take_while(should_take) .take(maximum_update_count) .cloned() .collect() @@ -244,7 +267,9 @@ impl BasicTreeOps for TreeVersionData { take_mut::take(&mut self.tree, |tree| { tree.update_with_mutation(leaf_index, &element) }); - self.next_leaf = leaf_index + 1; + if element != Hash::ZERO { + self.next_leaf = leaf_index + 1; + } self.metadata.count_since_last_flatten += 1; } @@ -296,7 +321,9 @@ impl BasicTreeOps for TreeVersionData { self.tree = updated_tree.clone(); - self.next_leaf = leaf_index + 1; + if element != Hash::ZERO { + self.next_leaf = leaf_index + 1; + } self.metadata.diff.push(AppliedTreeUpdate { update: TreeUpdate { leaf_index, @@ -313,7 +340,10 @@ impl BasicTreeOps for TreeVersionData { if let Some(last) = last { self.tree = last.result.clone(); - self.next_leaf = last.update.leaf_index + 1; + + if last.update.element != Hash::ZERO { + self.next_leaf = last.update.leaf_index + 1; + } } } @@ -399,8 +429,12 @@ pub trait TreeVersionReadOps { fn get_root(&self) -> Hash; /// Returns the next free leaf. fn next_leaf(&self) -> usize; + /// Returns the given leaf value, the root of the tree and the proof + fn get_leaf_and_proof(&self, leaf: usize) -> (Hash, Hash, Proof); /// Returns the merkle proof and element at the given leaf. fn get_proof(&self, leaf: usize) -> (Hash, Proof); + /// Gets the leaf value at a given index. + fn get_leaf(&self, leaf: usize) -> Hash; } impl TreeVersionReadOps for TreeVersion @@ -415,10 +449,24 @@ where self.get_data().next_leaf } + fn get_leaf_and_proof(&self, leaf: usize) -> (Hash, Hash, Proof) { + let tree = self.get_data(); + + let (root, proof) = tree.get_proof(leaf); + let leaf = tree.get_leaf(leaf); + + (leaf, root, proof) + } + fn get_proof(&self, leaf: usize) -> (Hash, Proof) { let tree = self.get_data(); tree.get_proof(leaf) } + + fn get_leaf(&self, leaf: usize) -> Hash { + let tree = self.get_data(); + tree.get_leaf(leaf) + } } impl TreeVersion { @@ -448,6 +496,41 @@ impl TreeVersion { output } + + /// Deletes many identities from the tree, returns a list with the root + /// and proof of inclusion + #[must_use] + pub fn delete_many(&self, leaf_indices: &[usize]) -> Vec<(Hash, Proof)> { + let mut data = self.get_data(); + + let mut output = Vec::with_capacity(leaf_indices.len()); + + for leaf_index in leaf_indices { + data.update(*leaf_index, Hash::ZERO); + let (root, proof) = data.get_proof(*leaf_index); + + output.push((root, proof)); + } + + output + } +} + +impl TreeVersion +where + T: Version, +{ + pub fn commitments_by_indices(&self, indices: impl IntoIterator) -> Vec { + let tree = self.get_data(); + + let mut commitments = vec![]; + + for idx in indices { + commitments.push(tree.tree.get_leaf(idx)); + } + + commitments + } } /// Public API for working with versions that have a successor. Such versions @@ -516,21 +599,23 @@ impl TreeState { } #[must_use] - pub fn get_proof_for(&self, item: &TreeItem) -> InclusionProof { - let (root, proof) = match item.status { + pub fn get_proof_for(&self, item: &TreeItem) -> (Field, InclusionProof) { + let (leaf, root, proof) = match item.status { Status::Pending | Status::New | Status::Failed => { - self.latest.get_proof(item.leaf_index) + self.latest.get_leaf_and_proof(item.leaf_index) } - Status::Processed => self.processed.get_proof(item.leaf_index), - Status::Mined => self.mined.get_proof(item.leaf_index), + Status::Processed => self.processed.get_leaf_and_proof(item.leaf_index), + Status::Mined => self.mined.get_leaf_and_proof(item.leaf_index), }; - InclusionProof { + let proof = InclusionProof { status: item.status, root: Some(root), proof: Some(proof), message: None, - } + }; + + (leaf, proof) } } @@ -656,3 +741,48 @@ impl DerivedTreeBuilder

{ sealed } } + +#[cfg(test)] +mod tests { + + use super::{CanonicalTreeBuilder, Hash, TreeWithNextVersion}; + + #[test] + fn test_peek_next_updates() { + let (canonical_tree, processed_builder) = + CanonicalTreeBuilder::new(10, 10, 0, Hash::ZERO, &[]).seal(); + let processed_tree = processed_builder.seal(); + let insertion_updates = processed_tree.append_many(&vec![ + Hash::from(1), + Hash::from(2), + Hash::from(3), + Hash::from(4), + Hash::from(5), + Hash::from(6), + Hash::from(7), + ]); + + let _deletion_updates = processed_tree.delete_many(&[0, 1, 2]); + + let next_updates = canonical_tree.peek_next_updates(10); + assert_eq!(next_updates.len(), 7); + + canonical_tree.apply_updates_up_to( + insertion_updates + .last() + .expect("Could not get insertion updates") + .0, + ); + + let _ = processed_tree.append_many(&[ + Hash::from(5), + Hash::from(6), + Hash::from(7), + Hash::from(8), + ]); + + let next_updates = canonical_tree.peek_next_updates(10); + + assert_eq!(next_updates.len(), 3); + } +} diff --git a/src/prover/batch_insertion/identity.rs b/src/prover/identity.rs similarity index 100% rename from src/prover/batch_insertion/identity.rs rename to src/prover/identity.rs diff --git a/src/prover/map.rs b/src/prover/map.rs index 51b6fc7d..ba5a27c2 100644 --- a/src/prover/map.rs +++ b/src/prover/map.rs @@ -2,9 +2,7 @@ use std::collections::BTreeMap; use tokio::sync::{RwLock, RwLockReadGuard}; -use crate::database::prover; -use crate::prover::batch_insertion; -use crate::prover::batch_insertion::ProverConfiguration; +use crate::prover::{Prover, ProverConfiguration, ProverType, Provers}; /// The type of a map containing a mapping from a usize to a locked item. type SharedProverMap

= RwLock>; @@ -23,6 +21,10 @@ pub struct ProverMap

{ } impl

ProverMap

{ + pub fn new(map: BTreeMap) -> Self { + Self { map } + } + /// Get the smallest prover that can handle the given batch size. pub fn get(&self, batch_size: usize) -> Option<&P> { for (size, prover) in &self.map { @@ -57,14 +59,15 @@ impl

ProverMap

{ } } -impl ProverMap { +impl ProverMap { pub fn as_configuration_vec(&self) -> Vec { self.map .iter() .map(|(k, v)| ProverConfiguration { - url: v.url(), - timeout_s: v.timeout_s(), - batch_size: *k, + url: v.url(), + timeout_s: v.timeout_s(), + batch_size: *k, + prover_type: v.prover_type(), }) .collect() } @@ -77,24 +80,36 @@ impl

From> for ProverMap

{ } /// A map of provers for batch insertion operations. -pub type InsertionProverMap = SharedProverMap; +pub type InsertionProverMap = SharedProverMap; +/// A map of provers for batch deletion operations. +pub type DeletionProverMap = SharedProverMap; /// The type of provers that can only be read from for insertion operations. -pub type ReadOnlyInsertionProver<'a> = ReadOnlyProver<'a, batch_insertion::Prover>; +pub type ReadOnlyInsertionProver<'a> = ReadOnlyProver<'a, Prover>; /// Builds an insertion prover map from the provided configuration. -pub fn make_insertion_map(db_provers: prover::Provers) -> anyhow::Result { - let mut map = BTreeMap::new(); +pub fn initialize_prover_maps( + db_provers: Provers, +) -> anyhow::Result<(InsertionProverMap, DeletionProverMap)> { + let mut insertion_map = BTreeMap::new(); + let mut deletion_map = BTreeMap::new(); for prover in db_provers { - map.insert( - prover.batch_size, - batch_insertion::Prover::from_prover_conf(&prover)?, - ); + match prover.prover_type { + ProverType::Insertion => { + insertion_map.insert(prover.batch_size, Prover::from_prover_conf(&prover)?); + } + + ProverType::Deletion => { + deletion_map.insert(prover.batch_size, Prover::from_prover_conf(&prover)?); + } + } } - let insertion_map = ProverMap::from(map); - Ok(RwLock::new(insertion_map)) + Ok(( + RwLock::new(ProverMap::new(insertion_map)), + RwLock::new(ProverMap::new(deletion_map)), + )) } #[cfg(test)] diff --git a/src/prover/mod.rs b/src/prover/mod.rs index 5672a806..25c91f52 100644 --- a/src/prover/mod.rs +++ b/src/prover/mod.rs @@ -7,9 +7,728 @@ //! APIs are designed to be imported for use qualified (e.g. //! `batch_insertion::Prover`, `batch_insertion::Identity` and so on). -pub mod batch_insertion; +pub mod identity; pub mod map; pub mod proof; +use std::collections::HashSet; +use std::fmt::{Display, Formatter}; +use std::hash::{Hash, Hasher}; +use std::mem::size_of; +use std::time::Duration; + +use clap::Parser; +use ethers::types::U256; +use ethers::utils::keccak256; pub use map::{InsertionProverMap, ProverMap, ReadOnlyProver}; +use once_cell::sync::Lazy; +use prometheus::{exponential_buckets, register_histogram, Histogram}; pub use proof::Proof; +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::prover::identity::Identity; +use crate::serde_utils::JsonStrWrapper; + +/// The endpoint used for proving operations. +const MTB_PROVE_ENDPOINT: &str = "prove"; + +static TOTAL_PROVING_TIME: Lazy = Lazy::new(|| { + register_histogram!( + "total_proving_time", + "The time to generate a proof in seconds. Includes preparing the data for the prover", + exponential_buckets(0.1, 1.5, 25).unwrap() + ) + .unwrap() +}); + +static PROVER_PROVING_TIME: Lazy = Lazy::new(|| { + register_histogram!( + "prover_proving_time", + "Only the time between sending a request and receiving the proof", + exponential_buckets(0.1, 1.5, 25).unwrap() + ) + .unwrap() +}); + +#[derive(Clone, Debug, PartialEq, Eq, Parser)] +#[group(skip)] +pub struct Options { + /// The options for configuring the batch insertion prover service. + /// + /// This should be a JSON array containing objects of the following format `{"url": "http://localhost:3001","batch_size": 3,"timeout_s": 30,"prover_type", "insertion"}` + #[clap( + long, + env, + default_value = r#"[{"url": "http://localhost:3001","batch_size": 3,"timeout_s": 30,"prover_type": "insertion"}]"# //TODO: update this and test + )] + pub prover_urls: JsonStrWrapper>, +} + +/// Configuration options for the component responsible for interacting with the +/// prover service. +#[derive(Clone, Debug, Eq, Serialize, Deserialize)] +pub struct ProverConfiguration { + /// The URL at which to contact the semaphore prover service for proof + /// generation. + pub url: String, + + /// The number of seconds to wait before timing out the transaction. + pub timeout_s: u64, + + // TODO Add and query a prover `info` endpoint instead. + /// The batch size that the prover is set up to work with. This must match + /// the deployed prover. + pub batch_size: usize, + + // TODO: add docs + pub prover_type: ProverType, +} + +#[derive(Debug, Copy, Clone, sqlx::Type, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +#[sqlx(type_name = "prover_enum", rename_all = "PascalCase")] +pub enum ProverType { + #[default] + Insertion, + Deletion, +} + +impl Hash for ProverConfiguration { + fn hash(&self, state: &mut H) { + self.batch_size.hash(state); + } +} + +impl PartialEq for ProverConfiguration { + fn eq(&self, other: &Self) -> bool { + self.batch_size == other.batch_size + } +} + +pub type Provers = HashSet; + +/// A representation of the connection to the MTB prover service. +#[derive(Clone, Debug)] +pub struct Prover { + target_url: Url, + client: reqwest::Client, + batch_size: usize, + timeout_s: u64, + prover_type: ProverType, +} + +impl Prover { + /// Constructs a new instance of the Merkle Tree Batcher (or Mtb). + /// + /// # Arguments + /// - `options`: The prover configuration options. + pub fn new(options: &ProverConfiguration) -> anyhow::Result { + let target_url = Url::parse(&options.url)?; + let timeout_duration = Duration::from_secs(options.timeout_s); + let client = reqwest::Client::builder() + .connect_timeout(timeout_duration) + .https_only(false) + .build()?; + + let mtb = Self { + target_url, + client, + batch_size: options.batch_size, + timeout_s: options.timeout_s, + prover_type: options.prover_type, + }; + + Ok(mtb) + } + + /// Creates a new batch insertion prover from the prover taken from the + /// database + pub fn from_prover_conf(prover_conf: &ProverConfiguration) -> anyhow::Result { + let target_url = Url::parse(&prover_conf.url)?; + let timeout_duration = Duration::from_secs(prover_conf.timeout_s); + let client = reqwest::Client::builder() + .connect_timeout(timeout_duration) + .https_only(false) + .build()?; + + Ok(Self { + target_url, + client, + batch_size: prover_conf.batch_size, + timeout_s: prover_conf.timeout_s, + prover_type: prover_conf.prover_type, + }) + } + + pub fn batch_size(&self) -> usize { + self.batch_size + } + + pub fn prover_type(&self) -> ProverType { + self.prover_type + } + + pub fn timeout_s(&self) -> u64 { + self.timeout_s + } + + /// Generates a proof term for the provided identity insertions into the + /// merkle tree. + /// + /// # Arguments + /// - `start_index`: The index in the merkle tree at which the insertions + /// were started. + /// - `pre_root`: The value of the merkle tree's root before identities were + /// inserted. + /// - `post_root`: The value of the merkle tree's root after the identities + /// were inserted. + /// - `identities`: A list of identity insertions, ordered in the order the + /// identities were inserted into the merkle tree. + pub async fn generate_insertion_proof( + &self, + start_index: u32, + pre_root: U256, + post_root: U256, + identities: &[Identity], + ) -> anyhow::Result { + if identities.len() != self.batch_size { + return Err(anyhow::Error::msg( + "Provided batch does not match prover batch size.", + )); + } + + let total_proving_time_timer = TOTAL_PROVING_TIME.start_timer(); + + let identity_commitments: Vec = identities.iter().map(|id| id.commitment).collect(); + let input_hash = compute_insertion_proof_input_hash( + start_index, + pre_root, + post_root, + &identity_commitments, + ); + let merkle_proofs = identities + .iter() + .map(|id| id.merkle_proof.clone()) + .collect(); + + let proof_input = InsertionProofInput { + input_hash, + start_index, + pre_root, + post_root, + identity_commitments, + merkle_proofs, + }; + + let request = self + .client + .post(self.target_url.join(MTB_PROVE_ENDPOINT)?) + .body("OH MY GOD") + .json(&proof_input) + .build()?; + + let prover_proving_time_timer = PROVER_PROVING_TIME.start_timer(); + let proof_term = self.client.execute(request).await?; + let proof_term = proof_term.error_for_status()?; + prover_proving_time_timer.observe_duration(); + + let json = proof_term.text().await?; + + let Ok(proof) = serde_json::from_str::(&json) else { + let error: ProverError = serde_json::from_str(&json)?; + return Err(anyhow::Error::msg(format!("{error}"))); + }; + + total_proving_time_timer.observe_duration(); + + Ok(proof) + } + + pub async fn generate_deletion_proof( + &self, + pre_root: U256, + post_root: U256, + packed_deletion_indices: Vec, + identities: Vec, + ) -> anyhow::Result { + if identities.len() != self.batch_size { + return Err(anyhow::Error::msg( + "Provided batch does not match prover batch size.", + )); + } + + let total_proving_time_timer = TOTAL_PROVING_TIME.start_timer(); + + let (identity_commitments, merkle_proofs): (Vec, Vec>) = identities + .into_iter() + .map(|id| (id.commitment, id.merkle_proof)) + .unzip(); + + let input_hash = + compute_deletion_proof_input_hash(packed_deletion_indices.clone(), pre_root, post_root); + + let proof_input = DeletionProofInput { + input_hash, + pre_root, + post_root, + packed_deletion_indices, + identity_commitments, + merkle_proofs, + }; + + let request = self + .client + .post(self.target_url.join(MTB_PROVE_ENDPOINT)?) + .body("OH MY GOD") + .json(&proof_input) + .build()?; + + let prover_proving_time_timer = PROVER_PROVING_TIME.start_timer(); + let proof_term = self.client.execute(request).await?; + let proof_term = proof_term.error_for_status()?; + prover_proving_time_timer.observe_duration(); + + let json = proof_term.text().await?; + + let Ok(proof) = serde_json::from_str::(&json) else { + let error: ProverError = serde_json::from_str(&json)?; + return Err(anyhow::Error::msg(format!("{error}"))); + }; + + total_proving_time_timer.observe_duration(); + + Ok(proof) + } + + pub fn url(&self) -> String { + self.target_url.to_string() + } +} + +/// Computes the input hash to the prover. +/// +/// The input hash is specified as the `keccak256` hash of the inputs arranged +/// as follows: +/// +/// ```md +/// StartIndex || PreRoot || PostRoot || IdComms[0] || IdComms[1] || ... || IdComms[batchSize-1] +/// 32 || 256 || 256 || 256 || 256 || ... || 256 bits +/// ``` +/// +/// where: +/// - `StartIndex` is `start_index`, the leaf index in the tree from which the +/// insertions started. +/// - `PreRoot` is `pre_root`, the root value of the merkle tree before the +/// insertions were made. +/// - `PostRoot` is `post_root`, the root value of the merkle tree after the +/// insertions were made. +/// - `IdComms` is `identity_commitments`, the list of identity commitments +/// provided in the order that they were inserted into the tree. +/// +/// The result is computed using the inputs in _big-endian_ byte ordering. +pub fn compute_insertion_proof_input_hash( + start_index: u32, + pre_root: U256, + post_root: U256, + identity_commitments: &[U256], +) -> U256 { + let mut pre_root_bytes: [u8; size_of::()] = Default::default(); + pre_root.to_big_endian(pre_root_bytes.as_mut_slice()); + let mut post_root_bytes: [u8; size_of::()] = Default::default(); + post_root.to_big_endian(post_root_bytes.as_mut_slice()); + + let mut bytes: Vec = vec![]; + bytes.extend_from_slice(&start_index.to_be_bytes()); + bytes.extend(pre_root_bytes.iter()); + bytes.extend(post_root_bytes.iter()); + + for commitment in identity_commitments { + let mut commitment_bytes: [u8; size_of::()] = Default::default(); + commitment.to_big_endian(commitment_bytes.as_mut_slice()); + bytes.extend(commitment_bytes.iter()); + } + + keccak256(bytes).into() +} + +// TODO: check this and update docs + +pub fn compute_deletion_proof_input_hash( + packed_deletion_indices: Vec, + pre_root: U256, + post_root: U256, +) -> U256 { + // Convert pre_root and post_root to bytes + let mut pre_root_bytes = vec![0u8; 32]; + pre_root.to_big_endian(&mut pre_root_bytes); + + let mut post_root_bytes = vec![0u8; 32]; + post_root.to_big_endian(&mut post_root_bytes); + + let mut bytes = vec![]; + + // Append packed_deletion_indices + bytes.extend_from_slice(&packed_deletion_indices); + + // Append pre_root and post_root bytes + bytes.extend_from_slice(&pre_root_bytes); + bytes.extend_from_slice(&post_root_bytes); + + // Compute and return the Keccak-256 hash + keccak256(bytes).into() +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct ProverError { + pub code: String, + pub message: String, +} + +impl Display for ProverError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "PROVER FAILURE: Code = {}, Message = {}", + self.code, self.message + ) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct InsertionProofInput { + input_hash: U256, + start_index: u32, + pre_root: U256, + post_root: U256, + identity_commitments: Vec, + merkle_proofs: Vec>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct DeletionProofInput { + input_hash: U256, + pre_root: U256, + post_root: U256, + packed_deletion_indices: Vec, + identity_commitments: Vec, + merkle_proofs: Vec>, +} + +#[cfg(test)] +mod test { + use super::*; + + #[tokio::test] + async fn mtb_should_generate_proof_with_correct_inputs() -> anyhow::Result<()> { + let mock_url: String = "0.0.0.0:3001".into(); + let mock_service = mock::Service::new(mock_url.clone()).await?; + + let options = ProverConfiguration { + url: "http://localhost:3001".into(), + timeout_s: 30, + batch_size: 3, + prover_type: ProverType::Insertion, + }; + let mtb = Prover::new(&options).unwrap(); + let input_data = get_default_proof_input(); + let identities: Vec = extract_identities_from(&input_data); + + let expected_proof = get_default_proof_output(); + let proof = mtb + .generate_insertion_proof( + input_data.start_index, + input_data.pre_root, + input_data.post_root, + &identities, + ) + .await?; + + mock_service.stop(); + + assert_eq!(proof, expected_proof); + + Ok(()) + } + + #[tokio::test] + async fn mtb_should_respond_with_error_if_inputs_incorrect() -> anyhow::Result<()> { + let mock_url: String = "0.0.0.0:3002".into(); + let mock_service = mock::Service::new(mock_url.clone()).await?; + + let options = ProverConfiguration { + url: "http://localhost:3002".into(), + timeout_s: 30, + batch_size: 3, + prover_type: ProverType::Insertion, + }; + let mtb = Prover::new(&options).unwrap(); + let mut input_data = get_default_proof_input(); + let identities = extract_identities_from(&input_data); + input_data.post_root = U256::from(2); + + let prover_result = mtb + .generate_insertion_proof( + input_data.start_index, + input_data.pre_root, + input_data.post_root, + &identities, + ) + .await; + + mock_service.stop(); + assert!(prover_result.is_err()); + + Ok(()) + } + + #[tokio::test] + async fn prover_should_error_if_batch_size_wrong() -> anyhow::Result<()> { + let options = ProverConfiguration { + url: "http://localhost:3002".into(), + timeout_s: 30, + batch_size: 10, + prover_type: ProverType::Insertion, + }; + let mtb = Prover::new(&options).unwrap(); + let input_data = get_default_proof_input(); + let identities = extract_identities_from(&input_data); + + let prover_result = mtb + .generate_insertion_proof( + input_data.start_index, + input_data.pre_root, + input_data.post_root, + &identities, + ) + .await; + + assert!(prover_result.is_err()); + assert_eq!( + prover_result.unwrap_err().to_string(), + anyhow::Error::msg("Provided batch does not match prover batch size.").to_string() + ); + + Ok(()) + } + + #[test] + fn compute_input_hash_should_succeed() { + let input = get_default_proof_input(); + + assert_eq!( + compute_insertion_proof_input_hash( + input.start_index, + input.pre_root, + input.post_root, + &input.identity_commitments + ), + input.input_hash + ); + } + + #[test] + fn proof_input_should_serde() { + let expected_data: InsertionProofInput = serde_json::from_str(EXPECTED_JSON).unwrap(); + let proof_input = get_default_proof_input(); + + assert_eq!(proof_input, expected_data); + } + + fn extract_identities_from(proof_input: &InsertionProofInput) -> Vec { + proof_input + .identity_commitments + .iter() + .zip(&proof_input.merkle_proofs) + .map(|(comm, prf)| Identity::new(*comm, prf.clone())) + .collect() + } + + pub fn get_default_proof_output() -> Proof { + Proof::from([ + "0x12bba8b5a46139c819d83544f024828ece34f4f46be933a377a07c1904e96ec4".into(), + "0x112c8d7c63b6c431cef23e9c0d9ffff39d1d660f514030d4f2787960b437a1d5".into(), + "0x2413396a2af3add6fbe8137cfe7657917e31a5cdab0b7d1d645bd5eeb47ba601".into(), + "0x1ad029539528b32ba70964ce43dbf9bba2501cdb3aaa04e4d58982e2f6c34752".into(), + "0x5bb975296032b135458bd49f92d5e9d363367804440d4692708de92e887cf17".into(), + "0x14932600f53a1ceb11d79a7bdd9688a2f8d1919176f257f132587b2b3274c41e".into(), + "0x13d7b19c7b67bf5d3adf2ac2d3885fd5d49435b6069c0656939cd1fb7bef9dc9".into(), + "0x142e14f90c49c79b4edf5f6b7acbcdb0b0f376a4311fc036f1006679bd53ca9e".into(), + ]) + } + + fn get_default_proof_input() -> InsertionProofInput { + let start_index: u32 = 0; + let pre_root: U256 = + "0x1b7201da72494f1e28717ad1a52eb469f95892f957713533de6175e5da190af2".into(); + let post_root: U256 = + "0x7b248024e18c30f6c8a6c63dad3748d72cd13d1197bfd79a1323216d6ac6e99".into(); + let identities: Vec = vec!["0x1".into(), "0x2".into(), "0x3".into()]; + let merkle_proofs: Vec> = vec![ + vec![ + "0x0".into(), + "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864".into(), + "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1".into(), + "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238".into(), + "0x7f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a".into(), + "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55".into(), + "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78".into(), + "0x78295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d".into(), + "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61".into(), + "0xe884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747".into(), + ], + vec![ + "0x1".into(), + "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864".into(), + "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1".into(), + "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238".into(), + "0x7f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a".into(), + "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55".into(), + "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78".into(), + "0x78295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d".into(), + "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61".into(), + "0xe884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747".into(), + ], + vec![ + "0x0".into(), + "0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a".into(), + "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1".into(), + "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238".into(), + "0x7f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a".into(), + "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55".into(), + "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78".into(), + "0x78295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d".into(), + "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61".into(), + "0xe884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747".into(), + ], + ]; + let input_hash: U256 = + "0xa2d9c54a0aecf0f2aeb502c4a14ac45209d636986294c5e3168a54a7f143b1d8".into(); + + InsertionProofInput { + input_hash, + start_index, + pre_root, + post_root, + identity_commitments: identities, + merkle_proofs, + } + } + + const EXPECTED_JSON: &str = r#"{ + "inputHash": "0xa2d9c54a0aecf0f2aeb502c4a14ac45209d636986294c5e3168a54a7f143b1d8", + "startIndex": 0, + "preRoot": "0x1b7201da72494f1e28717ad1a52eb469f95892f957713533de6175e5da190af2", + "postRoot": "0x7b248024e18c30f6c8a6c63dad3748d72cd13d1197bfd79a1323216d6ac6e99", + "identityCommitments": [ + "0x1", + "0x2", + "0x3" + ], + "merkleProofs": [ + [ + "0x0", + "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864", + "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1", + "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238", + "0x7f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a", + "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55", + "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78", + "0x78295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d", + "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61", + "0xe884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747" + ], + [ + "0x1", + "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864", + "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1", + "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238", + "0x7f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a", + "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55", + "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78", + "0x78295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d", + "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61", + "0xe884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747" + ], + [ + "0x0", + "0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a", + "0x1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1", + "0x18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238", + "0x7f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a", + "0x2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55", + "0x2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78", + "0x78295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d", + "0x2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61", + "0xe884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747" + ] + ] +} +"#; +} + +#[cfg(test)] +pub mod mock { + use std::net::SocketAddr; + + use axum::routing::post; + use axum::{Json, Router}; + use axum_server::Handle; + + use super::*; + + pub struct Service { + server: Handle, + } + + #[derive(Serialize, Deserialize)] + #[serde(untagged)] + #[allow(clippy::large_enum_variant)] + enum ProveResponse { + ProofSuccess(Proof), + ProofFailure(ProverError), + } + + impl Service { + pub async fn new(url: String) -> anyhow::Result { + let prove = |Json(payload): Json| async move { + match payload.post_root.div_mod(U256::from(2)) { + (_, y) if y != U256::zero() => { + Json(ProveResponse::ProofSuccess(test::get_default_proof_output())) + } + _ => { + let error = ProverError { + code: "Oh no!".into(), + message: "Things went wrong.".into(), + }; + Json(ProveResponse::ProofFailure(error)) + } + } + }; + let app = Router::new().route("/prove", post(prove)); + + let addr: SocketAddr = url.parse()?; + let server = Handle::new(); + let serverside_handle = server.clone(); + let service = app.into_make_service(); + + tokio::spawn(async move { + axum_server::bind(addr) + .handle(serverside_handle) + .serve(service) + .await + .unwrap(); + }); + + let service = Self { server }; + Ok(service) + } + + pub fn stop(self) { + self.server.shutdown(); + } + } +} diff --git a/src/server/custom_middleware.rs b/src/server/custom_middleware/mod.rs similarity index 100% rename from src/server/custom_middleware.rs rename to src/server/custom_middleware/mod.rs diff --git a/src/server/error.rs b/src/server/error.rs index dacb8ab7..fc5be160 100644 --- a/src/server/error.rs +++ b/src/server/error.rs @@ -33,6 +33,10 @@ pub enum Error { RootMismatch, #[error("Root provided in semaphore proof is too old.")] RootTooOld, + #[error("Identity is already queued for deletion.")] + IdentityQueuedForDeletion, + #[error("Identity has already been deleted.")] + IdentityAlreadyDeleted, #[error("invalid JSON request: {0}")] InvalidSerialization(#[from] serde_json::Error), #[error(transparent)] @@ -57,6 +61,8 @@ pub enum Error { CannotRemoveLastBatchSize, #[error("Identity Manager had no provers on point of identity insertion.")] NoProversOnIdInsert, + #[error("Identity Manager had no provers on point of identity deletion.")] + NoProversOnIdDeletion, #[error(transparent)] Other(#[from] EyreError), } diff --git a/src/server/mod.rs b/src/server/mod.rs index 06595f24..34266b67 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -22,6 +22,7 @@ use crate::app::{ App, InclusionProofResponse, ListBatchSizesResponse, VerifySemaphoreProofResponse, }; use crate::identity_tree::Hash; +use crate::prover::ProverType; mod custom_middleware; @@ -55,6 +56,8 @@ pub struct AddBatchSizeRequest { batch_size: usize, /// The timeout for communications with the prover service. timeout_seconds: u64, + // TODO: add docs + prover_type: ProverType, } #[derive(Clone, Serialize, Deserialize)] @@ -62,7 +65,9 @@ pub struct AddBatchSizeRequest { #[serde(deny_unknown_fields)] pub struct RemoveBatchSizeRequest { /// The batch size to remove from the prover map. - batch_size: usize, + batch_size: usize, + // TODO: add docs + prover_type: ProverType, } #[derive(Serialize, Deserialize)] @@ -91,6 +96,24 @@ pub struct VerifySemaphoreProofQuery { pub max_root_age_seconds: Option, } +#[derive(Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct DeletionRequest { + /// The identity commitment to delete. + identity_commitment: Hash, +} + +#[derive(Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct RecoveryRequest { + /// The leaf index of the identity commitment to delete. + previous_identity_commitment: Hash, + /// The new identity commitment to insert. + new_identity_commitment: Hash, +} + pub trait ToResponseCode { fn to_response_code(&self) -> StatusCode; } @@ -145,16 +168,43 @@ async fn add_batch_size( State(app): State>, Json(req): Json, ) -> Result<(), Error> { - app.add_batch_size(req.url, req.batch_size, req.timeout_seconds) - .await?; + app.add_batch_size( + req.url, + req.batch_size, + req.timeout_seconds, + req.prover_type, + ) + .await?; Ok(()) } + +async fn delete_identity( + State(app): State>, + Json(req): Json, +) -> Result<(), Error> { + app.delete_identity(&req.identity_commitment).await?; + Ok(()) +} + +async fn recover_identity( + State(app): State>, + Json(req): Json, +) -> Result<(), Error> { + app.recover_identity( + &req.previous_identity_commitment, + &req.new_identity_commitment, + ) + .await?; + Ok(()) +} + async fn remove_batch_size( State(app): State>, Json(req): Json, ) -> Result<(), Error> { - app.remove_batch_size(req.batch_size).await?; + app.remove_batch_size(req.batch_size, req.prover_type) + .await?; Ok(()) } @@ -214,6 +264,8 @@ pub async fn bind_from_listener( .route("/inclusionProof", post(inclusion_proof)) .route("/insertIdentity", post(insert_identity)) .route("/addBatchSize", post(add_batch_size)) + .route("/deleteIdentity", post(delete_identity)) + .route("/recoverIdentity", post(recover_identity)) .route("/removeBatchSize", post(remove_batch_size)) .route("/listBatchSizes", get(list_batch_sizes)) .layer(middleware::from_fn( diff --git a/src/task_monitor.rs b/src/task_monitor.rs index 90e768f6..25f130d8 100644 --- a/src/task_monitor.rs +++ b/src/task_monitor.rs @@ -3,43 +3,32 @@ use std::time::Duration; use anyhow::Result as AnyhowResult; use clap::Parser; -use ethers::types::U256; use once_cell::sync::Lazy; use prometheus::{linear_buckets, register_gauge, register_histogram, Gauge, Histogram}; use tokio::sync::{broadcast, Notify, RwLock}; use tokio::task::JoinHandle; use tracing::{info, instrument, warn}; +use self::tasks::delete_identities::DeleteIdentities; use self::tasks::finalize_identities::FinalizeRoots; use self::tasks::insert_identities::InsertIdentities; -use self::tasks::mine_identities::MineIdentities; use self::tasks::process_identities::ProcessIdentities; use crate::contracts::SharedIdentityManager; use crate::database::Database; -use crate::ethereum::write::TransactionId; use crate::identity_tree::TreeState; -use crate::utils::async_queue::AsyncQueue; pub mod tasks; const PROCESS_IDENTITIES_BACKOFF: Duration = Duration::from_secs(5); const FINALIZE_IDENTITIES_BACKOFF: Duration = Duration::from_secs(5); -const MINE_IDENTITIES_BACKOFF: Duration = Duration::from_secs(5); const INSERT_IDENTITIES_BACKOFF: Duration = Duration::from_secs(5); +const DELETE_IDENTITIES_BACKOFF: Duration = Duration::from_secs(5); struct RunningInstance { handles: Vec>, shutdown_sender: broadcast::Sender<()>, } -#[derive(Debug, Clone)] -pub struct PendingBatchSubmission { - transaction_id: TransactionId, - pre_root: U256, - post_root: U256, - start_index: usize, -} - static PENDING_IDENTITIES: Lazy = Lazy::new(|| { register_gauge!("pending_identities", "Identities not submitted on-chain").unwrap() }); @@ -86,13 +75,23 @@ impl RunningInstance { pub struct Options { /// The maximum number of seconds the sequencer will wait before sending a /// batch of identities to the chain, even if the batch is not full. + // TODO: do we want to change this to batch_insertion_timeout_secs #[clap(long, env, default_value = "180")] pub batch_timeout_seconds: u64, - /// How many transactions can be sent "at once" to the blockchain via the - /// write provider. - #[clap(long, env, default_value = "1")] - pub pending_identities_capacity: usize, + /// TODO: + #[clap(long, env, default_value = "3600")] + pub batch_deletion_timeout_seconds: i64, + + /// TODO: + #[clap(long, env, default_value = "100")] + pub min_batch_deletion_size: usize, + + /// How many identities can be held in the API insertion queue at any given + /// time Past this limit the API request will block until the queue has + /// space for the insertion. + #[clap(long, env, default_value = "100")] + pub insert_identities_capacity: usize, /// The maximum number of windows to scan for finalization logs #[clap(long, env, default_value = "100")] @@ -114,16 +113,19 @@ pub struct TaskMonitor { /// when shutdown is called we want to be able to gracefully /// await the join handles - which requires ownership of the handle and by /// extension the instance. - instance: RwLock>, - database: Arc, - identity_manager: SharedIdentityManager, - tree_state: TreeState, - batch_insert_timeout_secs: u64, - pending_identities_capacity: usize, + instance: RwLock>, + database: Arc, + identity_manager: SharedIdentityManager, + tree_state: TreeState, + batch_insert_timeout_secs: u64, // Finalization params - scanning_window_size: u64, - time_between_scans: Duration, + scanning_window_size: u64, + time_between_scans: Duration, + // TODO: docs + batch_deletion_timeout_seconds: i64, + // TODO: docs + min_batch_deletion_size: usize, } impl TaskMonitor { @@ -135,9 +137,11 @@ impl TaskMonitor { ) -> Self { let Options { batch_timeout_seconds, - pending_identities_capacity, scanning_window_size, time_between_scans_seconds, + batch_deletion_timeout_seconds: _, + min_batch_deletion_size: _, + insert_identities_capacity: _, } = *options; Self { @@ -146,9 +150,10 @@ impl TaskMonitor { identity_manager: contracts, tree_state, batch_insert_timeout_secs: batch_timeout_seconds, - pending_identities_capacity, scanning_window_size, time_between_scans: Duration::from_secs(time_between_scans_seconds), + batch_deletion_timeout_seconds: options.batch_deletion_timeout_seconds, + min_batch_deletion_size: options.min_batch_deletion_size, } } @@ -168,8 +173,6 @@ impl TaskMonitor { // in the database wake_up_notify.notify_one(); - let pending_batch_submissions_queue = AsyncQueue::new(self.pending_identities_capacity); - let mut handles = Vec::new(); // Finalize identities task @@ -190,29 +193,12 @@ impl TaskMonitor { handles.push(finalize_identities_handle); - // Mine identities task - let mine_identities = MineIdentities::new( - self.database.clone(), - self.identity_manager.clone(), - self.tree_state.get_processed_tree(), - pending_batch_submissions_queue.clone(), - ); - - let mine_identities_handle = crate::utils::spawn_monitored_with_backoff( - move || mine_identities.clone().run(), - shutdown_sender.clone(), - MINE_IDENTITIES_BACKOFF, - ); - - handles.push(mine_identities_handle); - - // Prcess identities task + // Process identities task let process_identities = ProcessIdentities::new( self.database.clone(), self.identity_manager.clone(), self.tree_state.get_batching_tree(), self.batch_insert_timeout_secs, - pending_batch_submissions_queue, wake_up_notify.clone(), ); @@ -228,7 +214,7 @@ impl TaskMonitor { let insert_identities = InsertIdentities::new( self.database.clone(), self.tree_state.get_latest_tree(), - wake_up_notify, + wake_up_notify.clone(), ); let insert_identities_handle = crate::utils::spawn_monitored_with_backoff( @@ -239,6 +225,23 @@ impl TaskMonitor { handles.push(insert_identities_handle); + // Delete identities task + let delete_identities = DeleteIdentities::new( + self.database.clone(), + self.tree_state.get_latest_tree(), + self.batch_deletion_timeout_seconds, + self.min_batch_deletion_size, + wake_up_notify, + ); + + let delete_identities_handle = crate::utils::spawn_monitored_with_backoff( + move || delete_identities.clone().run(), + shutdown_sender.clone(), + DELETE_IDENTITIES_BACKOFF, + ); + + handles.push(delete_identities_handle); + *instance = Some(RunningInstance { handles, shutdown_sender, diff --git a/src/task_monitor/tasks/delete_identities.rs b/src/task_monitor/tasks/delete_identities.rs new file mode 100644 index 00000000..83b8a984 --- /dev/null +++ b/src/task_monitor/tasks/delete_identities.rs @@ -0,0 +1,109 @@ +use std::collections::HashSet; +use std::sync::Arc; + +use anyhow::Result as AnyhowResult; +use chrono::Utc; +use tokio::sync::Notify; +use tracing::info; + +use crate::database::types::DeletionEntry; +use crate::database::Database; +use crate::identity_tree::{Hash, Latest, TreeVersion}; + +pub struct DeleteIdentities { + database: Arc, + latest_tree: TreeVersion, + deletion_time_interval: i64, + min_deletion_batch_size: usize, + wake_up_notify: Arc, +} + +impl DeleteIdentities { + pub fn new( + database: Arc, + latest_tree: TreeVersion, + deletion_time_interval: i64, + min_deletion_batch_size: usize, + wake_up_notify: Arc, + ) -> Arc { + Arc::new(Self { + database, + latest_tree, + deletion_time_interval, + min_deletion_batch_size, + wake_up_notify, + }) + } + + pub async fn run(self: Arc) -> anyhow::Result<()> { + delete_identities( + &self.database, + &self.latest_tree, + self.deletion_time_interval, + self.min_deletion_batch_size, + self.wake_up_notify.clone(), + ) + .await + } +} + +async fn delete_identities( + database: &Database, + latest_tree: &TreeVersion, + deletion_time_interval: i64, + min_deletion_batch_size: usize, + wake_up_notify: Arc, +) -> AnyhowResult<()> { + info!("Starting deletion processor."); + + let deletion_time_interval = chrono::Duration::seconds(deletion_time_interval); + + loop { + let deletions = database.get_deletions().await?; + if deletions.is_empty() { + // Sleep for one hour + // TODO: should we make this dynamic? This causes an issue with tests so its set + // to 1 sec atm + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + continue; + } + + let last_deletion_timestamp = database.get_latest_deletion().await?.timestamp; + + // If the minimum deletions batch size is reached or the deletion time interval + // has elapsed, run a batch of deletions + if deletions.len() >= min_deletion_batch_size + || Utc::now() - last_deletion_timestamp > deletion_time_interval + { + // Dedup deletion entries + let deletions = deletions.into_iter().collect::>(); + + let (leaf_indices, previous_commitments): (Vec, Vec) = deletions + .iter() + .map(|d| (d.leaf_index, d.commitment)) + .unzip(); + + // Delete the commitments at the target leaf indices in the latest tree, + // generating the proof for each update + let data = latest_tree.delete_many(&leaf_indices); + + assert_eq!( + data.len(), + leaf_indices.len(), + "Length mismatch when appending identities to tree" + ); + + // Insert the new items into pending identities + let items = data.into_iter().zip(leaf_indices.into_iter()); + for ((root, _proof), leaf_index) in items { + database + .insert_pending_identity(leaf_index, &Hash::ZERO, &root) + .await?; + } + + // Remove the previous commitments from the deletions table + database.remove_deletions(previous_commitments).await?; + wake_up_notify.notify_one(); + } + } +} diff --git a/src/task_monitor/tasks/finalize_identities.rs b/src/task_monitor/tasks/finalize_identities.rs index 92837d88..0159cb8d 100644 --- a/src/task_monitor/tasks/finalize_identities.rs +++ b/src/task_monitor/tasks/finalize_identities.rs @@ -2,18 +2,20 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use anyhow::Result as AnyhowResult; +use anyhow::{Context, Result as AnyhowResult}; +use chrono::{DateTime, Utc}; use ethers::abi::RawLog; use ethers::contract::EthEvent; use ethers::providers::Middleware; use ethers::types::{Address, Log, Topic, ValueOrArray, U256}; use tracing::{info, instrument}; -use crate::contracts::abi::{BridgedWorldId, RootAddedFilter, TreeChangedFilter}; +use crate::contracts::abi::{BridgedWorldId, RootAddedFilter, TreeChangeKind, TreeChangedFilter}; use crate::contracts::scanner::BlockScanner; use crate::contracts::{IdentityManager, SharedIdentityManager}; use crate::database::Database; use crate::identity_tree::{Canonical, Intermediate, TreeVersion, TreeWithNextVersion}; +use crate::task_monitor::TaskMonitor; pub struct FinalizeRoots { database: Arc, @@ -76,37 +78,26 @@ async fn finalize_roots_loop( let mainnet_address = mainnet_abi.address(); loop { - let all_roots = fetch_logs( - &mut mainnet_scanner, - &mut secondary_scanners, - mainnet_address, - ) - .await?; + let mainnet_logs = fetch_mainnet_logs(&mut mainnet_scanner, mainnet_address).await?; - finalize_roots( - database, - identity_manager, - processed_tree, - finalized_tree, - all_roots, - ) - .await?; + finalize_mainnet_roots(database, identity_manager, processed_tree, &mainnet_logs).await?; + + let mut roots = extract_roots_from_mainnet_logs(mainnet_logs); + roots.extend(fetch_secondary_logs(&mut secondary_scanners).await?); + + finalize_secondary_roots(database, identity_manager, finalized_tree, roots).await?; tokio::time::sleep(time_between_scans).await; } } -#[instrument(level = "info", skip_all)] -async fn fetch_logs( - mainnet_scanner: &mut BlockScanner, - secondary_scanners: &mut HashMap>, +async fn fetch_mainnet_logs( + mainnet_scanner: &mut BlockScanner, mainnet_address: Address, -) -> anyhow::Result> +) -> anyhow::Result> where - A: Middleware, - ::Error: 'static, - B: Middleware, - ::Error: 'static, + M: Middleware, + ::Error: 'static, { let mainnet_topics = [ Some(Topic::from(TreeChangedFilter::signature())), @@ -115,6 +106,22 @@ where None, ]; + let mainnet_address = Some(ValueOrArray::Value(mainnet_address)); + + let mainnet_logs = mainnet_scanner + .next(mainnet_address, mainnet_topics.clone()) + .await?; + + Ok(mainnet_logs) +} + +async fn fetch_secondary_logs( + secondary_scanners: &mut HashMap>, +) -> anyhow::Result> +where + M: Middleware, + ::Error: 'static, +{ let bridged_topics = [ Some(Topic::from(RootAddedFilter::signature())), None, @@ -122,11 +129,6 @@ where None, ]; - let mainnet_address = Some(ValueOrArray::Value(mainnet_address)); - - let mainnet_logs = mainnet_scanner - .next(mainnet_address, mainnet_topics.clone()) - .await?; let mut secondary_logs = vec![]; for (address, scanner) in secondary_scanners { @@ -137,42 +139,74 @@ where secondary_logs.extend(logs); } - let mut roots = extract_root_from_mainnet_logs(&mainnet_logs); - roots.extend(extract_roots_from_secondary_logs(&secondary_logs)); + let roots = extract_roots_from_secondary_logs(&secondary_logs); Ok(roots) } #[instrument(level = "info", skip_all)] -async fn finalize_roots( +async fn finalize_mainnet_roots( database: &Database, identity_manager: &IdentityManager, processed_tree: &TreeVersion, - finalized_tree: &TreeVersion, - all_roots: Vec, + logs: &[Log], ) -> Result<(), anyhow::Error> { - for root in all_roots { - info!(?root, "Finalizing root"); + for log in logs { + let Some(event) = raw_log_to_tree_changed(log) else { + continue; + }; - let is_root_finalized = identity_manager.is_root_mined_multi_chain(root).await?; + let pre_root = event.pre_root; + let post_root = event.post_root; + let kind = TreeChangeKind::from(event.kind); - if is_root_finalized { - // What can sometimes happen is that this finalize roots function is faster - // than the mine_identities task. In which case we'll try to finalize a given - // root, but it's not yet present in the processed tree. - // - // In that case we can safely apply updates to the processed tree as well. - processed_tree.apply_updates_up_to(root.into()); + info!(?pre_root, ?post_root, ?kind, "Mining batch"); - // We also need to run this update to mark the root as processed - // and apply a mined_at timestamp - database.mark_root_as_processed(&root.into()).await?; + // Double check + if !identity_manager.is_root_mined(post_root).await? { + continue; + } - finalized_tree.apply_updates_up_to(root.into()); - database.mark_root_as_mined(&root.into()).await?; + database.mark_root_as_processed(&post_root.into()).await?; - info!(?root, "Root finalized"); + info!(?pre_root, ?post_root, ?kind, "Batch mined"); + + if kind == TreeChangeKind::Deletion { + // NOTE: We must do this before updating the tree + // because we fetch commitments from the processed tree + // before they are deleted + update_eligible_recoveries(database, identity_manager, processed_tree, &log).await?; } + + let updates_count = processed_tree.apply_updates_up_to(post_root.into()); + + info!(updates_count, ?pre_root, ?post_root, "Mined tree updated"); + + TaskMonitor::log_identities_queues(database).await?; + } + + Ok(()) +} + +#[instrument(level = "info", skip_all)] +async fn finalize_secondary_roots( + database: &Database, + identity_manager: &IdentityManager, + finalized_tree: &TreeVersion, + roots: Vec, +) -> Result<(), anyhow::Error> { + for root in roots { + info!(?root, "Finalizing root"); + + // Check if mined on all L2s + if !identity_manager.is_root_mined_multi_chain(root).await? { + continue; + } + + database.mark_root_as_mined(&root.into()).await?; + finalized_tree.apply_updates_up_to(root.into()); + + info!(?root, "Root finalized"); } Ok(()) @@ -200,19 +234,26 @@ where Ok(secondary_scanners) } -fn extract_root_from_mainnet_logs(logs: &[Log]) -> Vec { +fn extract_roots_from_mainnet_logs(mainnet_logs: Vec) -> Vec { let mut roots = vec![]; + for log in mainnet_logs { + let Some(event) = raw_log_to_tree_changed(&log) else { + continue; + }; - for log in logs { - let raw_log = RawLog::from((log.topics.clone(), log.data.to_vec())); - if let Ok(event) = TreeChangedFilter::decode_log(&raw_log) { - roots.push(event.post_root); - } - } + let post_root = event.post_root; + roots.push(post_root); + } roots } +fn raw_log_to_tree_changed(log: &Log) -> Option { + let raw_log = RawLog::from((log.topics.clone(), log.data.to_vec())); + + TreeChangedFilter::decode_log(&raw_log).ok() +} + fn extract_roots_from_secondary_logs(logs: &[Log]) -> Vec { let mut roots = vec![]; @@ -225,3 +266,57 @@ fn extract_roots_from_secondary_logs(logs: &[Log]) -> Vec { roots } + +use crate::identity_tree::Hash; + +async fn update_eligible_recoveries( + database: &Database, + identity_manager: &IdentityManager, + processed_tree: &TreeVersion, + log: &Log, +) -> anyhow::Result<()> { + let tx_hash = log.transaction_hash.context("Missing tx hash")?; + let commitments = identity_manager + .fetch_deletion_indices_from_tx(tx_hash) + .await + .context("Could not fetch deletion indices from tx")?; + + let commitments = processed_tree.commitments_by_indices(commitments.iter().copied()); + let commitments: Vec = commitments.into_iter().map(|c| c.into()).collect(); + + // Check if any deleted commitments correspond with entries in the + // recoveries table and insert the new commitment into the unprocessed + // identities table with the proper eligibility timestamp + let recoveries = database + .get_recoveries() + .await? + .iter() + .map(|f| (f.existing_commitment, f.new_commitment)) + .collect::>(); + + // Fetch the root history expiry time on chain + let root_history_expiry = identity_manager.root_history_expiry().await?; + + // Use the root history expiry to calcuate the eligibility timestamp for the new + // insertion + let eligibility_timestamp = DateTime::from_utc( + chrono::NaiveDateTime::from_timestamp_opt( + Utc::now().timestamp() + root_history_expiry.as_u64() as i64, + 0, + ) + .context("Could not convert eligibility timestamp to NaiveDateTime")?, + Utc, + ); + + // For each deletion, if there is a corresponding recovery, insert a new + // identity with the specified eligibility timestamp + for prev_commitment in commitments { + if let Some(new_commitment) = recoveries.get(&prev_commitment.into()) { + database + .insert_new_identity(*new_commitment, eligibility_timestamp) + .await?; + } + } + + Ok(()) +} diff --git a/src/task_monitor/tasks/insert_identities.rs b/src/task_monitor/tasks/insert_identities.rs index 0d990568..cd052d79 100644 --- a/src/task_monitor/tasks/insert_identities.rs +++ b/src/task_monitor/tasks/insert_identities.rs @@ -42,7 +42,9 @@ async fn insert_identities_loop( ) -> AnyhowResult<()> { loop { // get commits from database - let unprocessed = database.get_unprocessed_commitments(Status::New).await?; + let unprocessed = database + .get_eligible_unprocessed_commitments(Status::New) + .await?; if unprocessed.is_empty() { sleep(Duration::from_secs(5)).await; continue; diff --git a/src/task_monitor/tasks/mine_identities.rs b/src/task_monitor/tasks/mine_identities.rs deleted file mode 100644 index b64e9982..00000000 --- a/src/task_monitor/tasks/mine_identities.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::sync::Arc; - -use anyhow::Result as AnyhowResult; -use tracing::{info, instrument}; - -use crate::contracts::{IdentityManager, SharedIdentityManager}; -use crate::database::Database; -use crate::identity_tree::{Intermediate, TreeVersion, TreeWithNextVersion}; -use crate::task_monitor::{PendingBatchSubmission, TaskMonitor}; -use crate::utils::async_queue::{AsyncPopGuard, AsyncQueue}; - -pub struct MineIdentities { - database: Arc, - identity_manager: SharedIdentityManager, - mined_tree: TreeVersion, - pending_batch_submissions_queue: AsyncQueue, -} - -impl MineIdentities { - pub fn new( - database: Arc, - identity_manager: SharedIdentityManager, - mined_tree: TreeVersion, - pending_batch_submissions_queue: AsyncQueue, - ) -> Arc { - Arc::new(Self { - database, - identity_manager, - mined_tree, - pending_batch_submissions_queue, - }) - } - - pub async fn run(self: Arc) -> anyhow::Result<()> { - mine_identities_loop( - &self.database, - &self.identity_manager, - &self.mined_tree, - &self.pending_batch_submissions_queue, - ) - .await - } -} - -async fn mine_identities_loop( - database: &Database, - identity_manager: &IdentityManager, - mined_tree: &TreeVersion, - pending_batch_submissions_queue: &AsyncQueue, -) -> AnyhowResult<()> { - loop { - let pending_identity = pending_batch_submissions_queue.pop().await; - - mine_identities(&pending_identity, database, identity_manager, mined_tree).await?; - - pending_identity.commit().await; - } -} - -#[instrument(level = "info", skip_all)] -async fn mine_identities( - pending_identity: &AsyncPopGuard<'_, PendingBatchSubmission>, - database: &Database, - identity_manager: &IdentityManager, - mined_tree: &TreeVersion, -) -> AnyhowResult<()> { - let PendingBatchSubmission { - transaction_id, - pre_root, - post_root, - start_index, - } = pending_identity.read().await; - - info!( - start_index, - ?pre_root, - ?post_root, - ?transaction_id, - "Mining batch" - ); - - if !identity_manager - .mine_identities(transaction_id.clone()) - .await? - { - panic!( - "Transaction {} failed on chain - sequencer will crash and restart", - transaction_id - ); - } - - // With this done, all that remains is to mark them as submitted to the - // blockchain in the source-of-truth database, and also update the mined tree to - // agree with the database and chain. - database.mark_root_as_processed(&post_root.into()).await?; - - info!(start_index, ?pre_root, ?post_root, "Batch mined"); - - let updates_count = mined_tree.apply_updates_up_to(post_root.into()); - - info!( - start_index, - updates_count, - ?pre_root, - ?post_root, - "Mined tree updated" - ); - - TaskMonitor::log_identities_queues(database).await?; - - Ok(()) -} diff --git a/src/task_monitor/tasks/mod.rs b/src/task_monitor/tasks/mod.rs index 8ad56242..b3f3569b 100644 --- a/src/task_monitor/tasks/mod.rs +++ b/src/task_monitor/tasks/mod.rs @@ -1,4 +1,4 @@ +pub mod delete_identities; pub mod finalize_identities; pub mod insert_identities; -pub mod mine_identities; pub mod process_identities; diff --git a/src/task_monitor/tasks/process_identities.rs b/src/task_monitor/tasks/process_identities.rs index 244f2e61..e35493d9 100644 --- a/src/task_monitor/tasks/process_identities.rs +++ b/src/task_monitor/tasks/process_identities.rs @@ -1,10 +1,10 @@ use std::sync::Arc; use std::time::{Duration, SystemTime}; -use anyhow::Result as AnyhowResult; +use anyhow::{Context, Result as AnyhowResult}; use ethers::types::U256; -use once_cell::sync::Lazy; -use prometheus::{register_histogram, Histogram}; +use ruint::Uint; +use semaphore::merkle_tree::Proof; use semaphore::poseidon_tree::Branch; use tokio::sync::Notify; use tokio::{select, time}; @@ -13,32 +13,23 @@ use tracing::{debug, error, info, instrument, warn}; use crate::contracts::{IdentityManager, SharedIdentityManager}; use crate::database::Database; use crate::identity_tree::{ - AppliedTreeUpdate, Intermediate, TreeVersion, TreeVersionReadOps, TreeWithNextVersion, + AppliedTreeUpdate, Hash, Intermediate, TreeVersion, TreeVersionReadOps, TreeWithNextVersion, }; -use crate::prover::batch_insertion::Identity; -use crate::prover::map::ReadOnlyInsertionProver; -use crate::task_monitor::{PendingBatchSubmission, TaskMonitor}; -use crate::utils::async_queue::AsyncQueue; +use crate::prover::identity::Identity; +use crate::prover::{Prover, ReadOnlyProver}; +use crate::task_monitor::TaskMonitor; +use crate::utils::index_packing::pack_indices; /// The number of seconds either side of the timer tick to treat as enough to /// trigger a forced batch insertion. const DEBOUNCE_THRESHOLD_SECS: u64 = 1; -static PENDING_IDENTITIES_CHANNEL_CAPACITY: Lazy = Lazy::new(|| { - register_histogram!( - "pending_identities_channel_capacity", - "Pending identities channel capacity" - ) - .unwrap() -}); - pub struct ProcessIdentities { - database: Arc, - identity_manager: SharedIdentityManager, - batching_tree: TreeVersion, + database: Arc, + identity_manager: SharedIdentityManager, + batching_tree: TreeVersion, batch_insert_timeout_secs: u64, - pending_batch_submissions_queue: AsyncQueue, - wake_up_notify: Arc, + wake_up_notify: Arc, } impl ProcessIdentities { @@ -47,7 +38,6 @@ impl ProcessIdentities { identity_manager: SharedIdentityManager, batching_tree: TreeVersion, batch_insert_timeout_secs: u64, - pending_batch_submissions_queue: AsyncQueue, wake_up_notify: Arc, ) -> Arc { Arc::new(Self { @@ -55,7 +45,6 @@ impl ProcessIdentities { identity_manager, batching_tree, batch_insert_timeout_secs, - pending_batch_submissions_queue, wake_up_notify, }) } @@ -66,7 +55,6 @@ impl ProcessIdentities { &self.identity_manager, &self.batching_tree, &self.wake_up_notify, - &self.pending_batch_submissions_queue, self.batch_insert_timeout_secs, ) .await @@ -78,7 +66,6 @@ async fn process_identities( identity_manager: &IdentityManager, batching_tree: &TreeVersion, wake_up_notify: &Notify, - pending_batch_submissions_queue: &AsyncQueue, timeout_secs: u64, ) -> AnyhowResult<()> { info!("Awaiting for a clean slate"); @@ -119,21 +106,11 @@ async fn process_identities( continue; } - let prover = identity_manager.get_suitable_prover(updates.len()).await?; - - info!( - "Sending timed-out batch with {}/{} updates.", - updates.len(), - prover.batch_size() - ); - commit_identities( database, identity_manager, batching_tree, - pending_batch_submissions_queue, &updates, - prover ).await?; last_batch_time = SystemTime::now(); @@ -141,7 +118,7 @@ async fn process_identities( // Also wake up if woken up due to a tick wake_up_notify.notify_one(); } - _ = wake_up_notify.notified() => { + () = wake_up_notify.notified() => { tracing::trace!("Identity batch insertion woken due to request."); // Capture the time difference since the last batch, and compute @@ -179,15 +156,11 @@ async fn process_identities( continue; } - let prover = identity_manager.get_suitable_prover(updates.len()).await?; - commit_identities( database, identity_manager, batching_tree, - pending_batch_submissions_queue, &updates, - prover ).await?; // We've inserted the identities, so we want to ensure that @@ -203,14 +176,55 @@ async fn process_identities( } } -#[instrument(level = "info", skip_all)] async fn commit_identities( database: &Database, identity_manager: &IdentityManager, batching_tree: &TreeVersion, - pending_batch_submissions_queue: &AsyncQueue, updates: &[AppliedTreeUpdate], - insertion_prover: ReadOnlyInsertionProver<'_>, +) -> AnyhowResult<()> { + // If the update is an insertion + if updates + .first() + .context("Updates should be > 1")? + .update + .element + != Hash::ZERO + { + let prover = identity_manager + .get_suitable_insertion_prover(updates.len()) + .await?; + + info!( + "Sending timed-out insertion batch with {}/{} updates.", + updates.len(), + prover.batch_size() + ); + + insert_identities(database, identity_manager, batching_tree, updates, prover).await?; + } else { + let prover = identity_manager + .get_suitable_deletion_prover(updates.len()) + .await?; + + info!( + "Sending timed-out deletion batch with {}/{} updates.", + updates.len(), + prover.batch_size() + ); + + delete_identities(database, identity_manager, batching_tree, updates, prover).await?; + } + + Ok(()) +} + +#[instrument(level = "info", skip_all)] +pub async fn insert_identities( + database: &Database, + identity_manager: &IdentityManager, + batching_tree: &TreeVersion, + updates: &[AppliedTreeUpdate], + prover: ReadOnlyProver<'_, Prover>, ) -> AnyhowResult<()> { TaskMonitor::log_identities_queues(database).await?; @@ -221,14 +235,13 @@ async fn commit_identities( debug!("Starting identity commit for {} identities.", updates.len()); - // Sanity check that the insertions are to consecutive leaves in the tree. let mut last_index = updates .first() .expect("Updates is non empty.") .update .leaf_index; - for update in updates[1..].iter() { + for update in &updates[1..] { assert_eq!( last_index + 1, update.update.leaf_index, @@ -238,6 +251,7 @@ async fn commit_identities( } // Grab the initial conditions before the updates are applied to the tree. + let start_index = updates[0].update.leaf_index; let pre_root: U256 = batching_tree.get_root().into(); let mut commitments: Vec = updates @@ -273,7 +287,7 @@ async fn commit_identities( "Number of identities does not match the number of merkle proofs." ); - let batch_size = insertion_prover.batch_size(); + let batch_size = prover.batch_size(); // The verifier and prover can only work with a given batch size, so we need to // ensure that our batches match that size. We do this by padding with @@ -328,28 +342,21 @@ async fn commit_identities( identity_manager.validate_merkle_proofs(&identity_commitments)?; // We prepare the proof before reserving a slot in the pending identities - let proof = IdentityManager::prepare_proof( - insertion_prover, + let proof = IdentityManager::prepare_insertion_proof( + prover, start_index, pre_root, - post_root, &identity_commitments, + post_root, ) - .await - .map_err(|e| { - error!(?e, "Failed to prepare proof."); - e - })?; - - #[allow(clippy::cast_precision_loss)] - PENDING_IDENTITIES_CHANNEL_CAPACITY.observe(pending_batch_submissions_queue.len().await as f64); + .await?; - // This queue's capacity provides us with a natural back-pressure mechanism - // to ensure that we don't overwhelm the identity manager with too many - // identities to mine. - let permit = pending_batch_submissions_queue.reserve().await; - - info!(start_index, ?pre_root, ?post_root, "Submitting batch"); + info!( + start_index, + ?pre_root, + ?post_root, + "Submitting insertion batch" + ); // With all the data prepared we can submit the identities to the on-chain // identity manager and wait for that transaction to be mined. @@ -372,23 +379,166 @@ async fn commit_identities( ?pre_root, ?post_root, ?transaction_id, - "Batch submitted" + "Insertion batch submitted" ); - // The transaction will be awaited on asynchronously - permit - .send(PendingBatchSubmission { - transaction_id, + // Update the batching tree only after submitting the identities to the chain + batching_tree.apply_updates_up_to(post_root.into()); + + info!(start_index, ?pre_root, ?post_root, "Tree updated"); + + TaskMonitor::log_batch_size(updates.len()); + + Ok(()) +} + +pub async fn delete_identities( + database: &Database, + identity_manager: &IdentityManager, + batching_tree: &TreeVersion, + updates: &[AppliedTreeUpdate], + prover: ReadOnlyProver<'_, Prover>, +) -> AnyhowResult<()> { + TaskMonitor::log_identities_queues(database).await?; + + if updates.is_empty() { + warn!("Identity commit requested with zero identities. Continuing."); + return Ok(()); + } + + debug!("Starting identity commit for {} identities.", updates.len()); + + // Grab the initial conditions before the updates are applied to the tree. + let pre_root: U256 = batching_tree.get_root().into(); + + let mut deletion_indices = updates + .iter() + .map(|f| f.update.leaf_index as u32) + .collect::>(); + + let commitments = + batching_tree.commitments_by_indices(deletion_indices.iter().map(|x| *x as usize)); + let mut commitments: Vec = commitments.into_iter().map(U256::from).collect(); + + let latest_tree_from_updates = updates + .last() + .expect("Updates is non empty.") + .result + .clone(); + + // Next get merkle proofs for each update - note the proofs are acquired from + // intermediate versions of the tree + let mut merkle_proofs: Vec<_> = updates + .iter() + .map(|update_with_tree| { + update_with_tree + .result + .proof(update_with_tree.update.leaf_index) + }) + .collect(); + + // Grab some variables for sizes to make querying easier. + let commitment_count = updates.len(); + + // If these aren't equal then something has gone terribly wrong and is a + // programmer bug, so we abort. + assert_eq!( + commitment_count, + merkle_proofs.len(), + "Number of identities does not match the number of merkle proofs." + ); + + let batch_size = prover.batch_size(); + + // The verifier and prover can only work with a given batch size, so we need to + // ensure that our batches match that size. We do this by padding deletion + // indices with tree.depth() ^ 2. The deletion prover will skip the proof for + // any deletion with an index greater than the max tree depth + let pad_index = 2_u32.pow(latest_tree_from_updates.depth() as u32); + + if commitment_count != batch_size { + let padding = batch_size - commitment_count; + commitments.extend(vec![U256::zero(); padding]); + deletion_indices.extend(vec![pad_index; padding]); + + let zeroed_proof = Proof(vec![ + Branch::Left(Uint::ZERO); + latest_tree_from_updates.depth() + ]); + + merkle_proofs.extend(vec![zeroed_proof; padding]); + } + + assert_eq!( + deletion_indices.len(), + batch_size, + "Mismatch between deletion indices length and batch size." + ); + + // With the updates applied we can grab the value of the tree's new root and + // build our identities for sending to the identity manager. + let post_root: U256 = latest_tree_from_updates.root().into(); + + // Get the previous identity + let identity_commitments: Vec = commitments + .iter() + .zip(merkle_proofs) + .map(|(id, prf)| { + let commitment: U256 = id.into(); + let proof: Vec = prf + .0 + .iter() + .map(|branch| match branch { + Branch::Left(v) | Branch::Right(v) => U256::from(*v), + }) + .collect(); + Identity::new(commitment, proof) + }) + .collect(); + + identity_manager.validate_merkle_proofs(&identity_commitments)?; + + let packed_deletion_indices = pack_indices(&deletion_indices); + + // We prepare the proof before reserving a slot in the pending identities + let proof = IdentityManager::prepare_deletion_proof( + prover, + pre_root, + packed_deletion_indices.clone(), + identity_commitments, + post_root, + ) + .await?; + + info!(?pre_root, ?post_root, "Submitting deletion batch"); + + // With all the data prepared we can submit the identities to the on-chain + // identity manager and wait for that transaction to be mined. + let transaction_id = identity_manager + .delete_identities( + proof, + batch_size as u32, + packed_deletion_indices, pre_root, post_root, - start_index, - }) - .await; + ) + .await + .map_err(|e| { + error!(?e, "Failed to insert identity to contract."); + e + })?; + + info!( + ?pre_root, + ?post_root, + ?transaction_id, + "Deletion batch submitted" + ); // Update the batching tree only after submitting the identities to the chain batching_tree.apply_updates_up_to(post_root.into()); - info!(start_index, ?pre_root, ?post_root, "Tree updated"); + info!(?pre_root, ?post_root, "Tree updated"); TaskMonitor::log_batch_size(updates.len()); diff --git a/src/utils.rs b/src/utils.rs index cd5cb489..0734e973 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,7 +8,7 @@ use tokio::sync::broadcast; use tokio::task::JoinHandle; use tracing::{error, info}; -pub mod async_queue; +pub mod index_packing; pub trait Any { fn any(self) -> AnyhowResult; diff --git a/src/utils/async_queue.rs b/src/utils/async_queue.rs deleted file mode 100644 index 477b9e4d..00000000 --- a/src/utils/async_queue.rs +++ /dev/null @@ -1,314 +0,0 @@ -use std::collections::VecDeque; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use tokio::sync::{Mutex, Notify}; - -#[derive(Clone)] -pub struct AsyncQueue { - inner: Arc>, -} - -struct AsyncQueueInner { - items: Mutex>, - capacity: usize, - push_notify: Notify, - pop_notify: Notify, - pop_guard_exists: AtomicBool, - push_guard_exists: AtomicBool, -} - -impl AsyncQueue { - pub fn new(capacity: usize) -> Self { - AsyncQueue { - inner: Arc::new(AsyncQueueInner { - capacity, - items: Mutex::new(VecDeque::with_capacity(capacity)), - push_notify: Notify::new(), - pop_notify: Notify::new(), - pop_guard_exists: AtomicBool::new(false), - push_guard_exists: AtomicBool::new(false), - }), - } - } - - pub async fn len(&self) -> usize { - self.inner.items.lock().await.len() - } - - /// Creates a guard that will block any other producer from submitting to - /// this queue - /// - /// Blocks until the queue has space for a new item. - /// - /// If there exists another guard at that time - blocks. - /// - /// Doesn't yet send the item, instead the caller should call - /// `guard.send(value)` to send the item. - pub async fn reserve(&self) -> AsyncPushGuard<'_, T> { - loop { - let items = self.inner.items.lock().await; - - let another_guard_exists = self.inner.push_guard_exists.load(Ordering::SeqCst); - - if !another_guard_exists && items.len() < self.inner.capacity { - self.inner.push_guard_exists.store(true, Ordering::SeqCst); - return AsyncPushGuard { queue: self }; - } - - drop(items); - - // Either could trigger the pop guard to be available - tokio::select! { - _ = self.inner.push_notify.notified() => {} - _ = self.inner.pop_notify.notified() => {} - } - } - } - - /// Pushes an item to the queue - /// - /// Blocks until the queue has space for a new item - pub async fn _push(&self, item: T) { - loop { - let mut items = self.inner.items.lock().await; - - if items.len() < self.inner.capacity { - items.push_back(item); - - self.inner.push_notify.notify_one(); - - return; - } - - drop(items); - - self.inner.pop_notify.notified(); - } - } - - pub async fn pop(&self) -> AsyncPopGuard { - loop { - let no_other_guards_exist = !self.inner.pop_guard_exists.load(Ordering::SeqCst); - let queue_is_not_empty = self.inner.items.lock().await.front().is_some(); - - if no_other_guards_exist && queue_is_not_empty { - self.inner.pop_guard_exists.store(true, Ordering::SeqCst); - - return AsyncPopGuard { queue: self }; - } - - // Either could trigger the pop guard to be available - tokio::select! { - _ = self.inner.push_notify.notified() => {} - _ = self.inner.pop_notify.notified() => {} - } - } - } -} - -pub struct AsyncPopGuard<'a, T> { - queue: &'a AsyncQueue, -} - -impl<'a, T> AsyncPopGuard<'a, T> -where - T: Clone, -{ - pub async fn read(&self) -> T { - let items = self.queue.inner.items.lock().await; - items.front().unwrap().clone() - } - - pub async fn commit(self) { - let mut items = self.queue.inner.items.lock().await; - self.queue.inner.pop_notify.notify_one(); - items.pop_front(); - } -} - -impl<'a, T> Drop for AsyncPopGuard<'a, T> { - fn drop(&mut self) { - self.queue - .inner - .pop_guard_exists - .store(false, Ordering::Relaxed); - } -} - -pub struct AsyncPushGuard<'a, T> { - queue: &'a AsyncQueue, -} - -impl<'a, T> AsyncPushGuard<'a, T> { - pub async fn send(self, value: T) { - let mut items = self.queue.inner.items.lock().await; - items.push_back(value); - self.queue.inner.push_notify.notify_one(); - } -} - -impl<'a, T> Drop for AsyncPushGuard<'a, T> { - fn drop(&mut self) { - self.queue - .inner - .push_guard_exists - .store(false, Ordering::Relaxed); - } -} - -#[cfg(test)] -mod tests { - use tokio::time::{timeout, Duration}; - - use super::*; - - #[tokio::test] - async fn pop_on_empty_queue() { - let queue: AsyncQueue = AsyncQueue::new(2); - - let pop_guard = timeout(Duration::from_secs_f32(0.5), queue.pop()).await; - - assert!(pop_guard.is_err(), "Pop on empty queue should timeout"); - } - - #[tokio::test] - async fn read_and_commit_single_item() { - let queue: AsyncQueue = AsyncQueue::new(2); - - queue._push(1).await; - - let pop_guard = queue.pop().await; - - queue._push(2).await; - - assert_eq!(pop_guard.read().await, 1); - - pop_guard.commit().await; - - let pop_guard = queue.pop().await; - - assert_eq!(pop_guard.read().await, 2); - } - - #[tokio::test] - async fn drop_without_commit_does_not_remove_item() { - let queue: AsyncQueue = AsyncQueue::new(2); - - queue._push(1).await; - - let pop_guard = queue.pop().await; - - queue._push(2).await; - - assert_eq!(pop_guard.read().await, 1); - - // Drop without committing - drop(pop_guard); - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 1); - } - - #[tokio::test] - async fn only_a_single_pop_guard_can_exist() { - let queue: AsyncQueue = AsyncQueue::new(2); - - queue._push(1).await; - - let first_guard = queue.pop().await; - assert_eq!(first_guard.read().await, 1); - - let second_guard = timeout(Duration::from_secs_f32(0.5), queue.pop()).await; - - assert!(second_guard.is_err(), "Pop on empty queue should timeout"); - - drop(first_guard); - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 1); - } - - #[tokio::test] - async fn pushing_over_capacity_blocks() { - let queue: AsyncQueue = AsyncQueue::new(2); - - queue._push(1).await; - queue._push(2).await; - - let result = timeout(Duration::from_secs_f32(0.5), queue._push(3)).await; - - assert!(result.is_err(), "Push on full queue should timeout"); - } - - #[tokio::test] - async fn reserve_blocks_until_queue_has_space() { - let queue: AsyncQueue = AsyncQueue::new(2); - - queue._push(1).await; - queue._push(2).await; - - let reserve_guard = timeout(Duration::from_secs_f32(0.5), queue.reserve()).await; - assert!( - reserve_guard.is_err(), - "Reserve on full queue should timeout" - ); - - queue.pop().await.commit().await; - - let reserve_guard = queue.reserve().await; - reserve_guard.send(3).await; - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 2); - - pop_guard.commit().await; - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 3); - } - - #[tokio::test] - async fn queue_is_fifo() { - let queue: AsyncQueue = AsyncQueue::new(2); - - queue._push(1).await; - queue._push(2).await; - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 1); - pop_guard.commit().await; - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 2); - } - - #[tokio::test] - async fn only_one_push_guard_can_exist() { - let queue: AsyncQueue = AsyncQueue::new(2); - - let push_guard = queue.reserve().await; - - let result = timeout(Duration::from_secs_f32(0.5), queue.reserve()).await; - - assert!( - result.is_err(), - "Reserve when another guard exists should timeout" - ); - - drop(push_guard); - - let push_guard = queue.reserve().await; - push_guard.send(1).await; - - let push_guard = queue.reserve().await; - push_guard.send(2).await; - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 1); - pop_guard.commit().await; - - let pop_guard = queue.pop().await; - assert_eq!(pop_guard.read().await, 2); - } -} diff --git a/src/utils/index_packing.rs b/src/utils/index_packing.rs new file mode 100644 index 00000000..7873a40b --- /dev/null +++ b/src/utils/index_packing.rs @@ -0,0 +1,39 @@ +pub fn pack_indices(indices: &[u32]) -> Vec { + let mut packed = Vec::with_capacity(indices.len() * 4); + + for index in indices { + packed.extend_from_slice(&index.to_be_bytes()); + } + + packed +} + +pub fn unpack_indices(packed: &[u8]) -> Vec { + let mut indices = Vec::with_capacity(packed.len() / 4); + + for packed_index in packed.chunks_exact(4) { + let index = u32::from_be_bytes(packed_index.try_into().expect("Invalid index length")); + + indices.push(index); + } + + indices +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pack_indices() { + let indices = vec![1, 2, 3, 4, 5, 6, 7, 8]; + + let packed = pack_indices(&indices); + + assert_eq!(packed.len(), 32); + + let unpacked = unpack_indices(&packed); + + assert_eq!(unpacked, indices); + } +} diff --git a/tests/common/abi.rs b/tests/common/abi.rs index 2f43f7fc..f857132e 100644 --- a/tests/common/abi.rs +++ b/tests/common/abi.rs @@ -18,7 +18,9 @@ abigen!( error NoSuchVerifier() error MismatchedInputLengths() constructor(address _logic, bytes memory data) payable - function initialize(uint8 treeDepth, uint256 initialRoot, address _batchInsertionVerifiers, address _batchUpdateVerifiers, address _semaphoreVerifier, bool _enableStateBridge, address stateBridge) public virtual + function initialize(uint8 treeDepth, uint256 initialRoot, address _batchInsertionVerifiers, address _batchUpdateVerifiers, address _semaphoreVerifier) public virtual + function initializeV2(address _batchDeletionVerifiers) public virtual + function deleteIdentities(uint256[8] calldata deletionProof, uint256 preRoot, bytes calldata deletionIndices, uint256 postRoot) public virtual function registerIdentities(uint256[8] calldata insertionProof, uint256 preRoot, uint32 startIndex, uint256[] calldata identityCommitments, uint256 postRoot) public virtual function updateIdentities(uint256[8] calldata updateProof, uint256 preRoot, uint32[] calldata leafIndices, uint256[] calldata oldIdentities, uint256[] calldata newIdentities, uint256 postRoot) public virtual function calculateIdentityRegistrationInputHash(uint32 startIndex, uint256 preRoot, uint256 postRoot, uint256[] identityCommitments) public view virtual returns (bytes32 hash) diff --git a/tests/common/chain_mock.rs b/tests/common/chain_mock.rs index 9c7ff0ed..2f6ddd97 100644 --- a/tests/common/chain_mock.rs +++ b/tests/common/chain_mock.rs @@ -29,7 +29,8 @@ pub struct MockChain { #[instrument(skip_all)] pub async fn spawn_mock_chain( initial_root: U256, - batch_sizes: &[usize], + insertion_batch_sizes: &[usize], + deletion_batch_sizes: &[usize], tree_depth: u8, ) -> anyhow::Result { let chain = Anvil::new().block_time(2u64).spawn(); @@ -95,16 +96,6 @@ pub async fn spawn_mock_chain( .send() .await?; - // The rest of the contracts can be deployed to the mock chain normally. - let mock_state_bridge_factory = - load_and_build_contract("./sol/SimpleStateBridge.json", client.clone())?; - - let mock_state_bridge = mock_state_bridge_factory - .deploy(())? - .confirmations(0usize) - .send() - .await?; - let mock_verifier_factory = load_and_build_contract("./sol/SequencerVerifier.json", client.clone())?; @@ -126,32 +117,34 @@ pub async fn spawn_mock_chain( let verifier_lookup_table_factory = load_and_build_contract("./sol/VerifierLookupTable.json", client.clone())?; - let first_batch_size = batch_sizes[0]; + let first_insertion_batch_size = insertion_batch_sizes.first().copied().unwrap_or(1); + let first_deletion_batch_size = deletion_batch_sizes.first().copied().unwrap_or(1); let insert_verifiers = verifier_lookup_table_factory .clone() - .deploy((first_batch_size as u64, mock_verifier.address()))? + .deploy((first_insertion_batch_size as u64, mock_verifier.address()))? .confirmations(0usize) .send() .await?; let update_verifiers = verifier_lookup_table_factory - .deploy((first_batch_size as u64, unimplemented_verifier.address()))? + .clone() + .deploy(( + first_insertion_batch_size as u64, + unimplemented_verifier.address(), + ))? .confirmations(0usize) .send() .await?; - let identity_manager_impl_factory = - load_and_build_contract("./sol/WorldIDIdentityManagerImplV1.json", client.clone())?; - - let identity_manager_impl = identity_manager_impl_factory - .deploy(())? + let delete_verifiers = verifier_lookup_table_factory + .deploy((first_deletion_batch_size as u64, mock_verifier.address()))? .confirmations(0usize) .send() .await?; - for batch_size in &batch_sizes[1..] { - let batch_size = *batch_size as u64; + for batch_size in insertion_batch_sizes.iter().skip(1).copied() { + let batch_size = batch_size as u64; info!("Adding verifier for batch size {}", batch_size); insert_verifiers @@ -161,10 +154,29 @@ pub async fn spawn_mock_chain( .await?; } + for batch_size in deletion_batch_sizes.iter().skip(1).copied() { + let batch_size = batch_size as u64; + + info!("Adding verifier for batch size {}", batch_size); + delete_verifiers + .method::<_, ()>("addVerifier", (batch_size, mock_verifier.address()))? + .send() + .await? + .await?; + } + + let identity_manager_impl_factory = + load_and_build_contract("./sol/WorldIDIdentityManagerImplV2.json", client.clone())?; + + let identity_manager_impl = identity_manager_impl_factory + .deploy(())? + .confirmations(0usize) + .send() + .await?; + let identity_manager_factory = load_and_build_contract("./sol/WorldIDIdentityManager.json", client.clone())?; - let state_bridge_address = mock_state_bridge.address(); - let enable_state_bridge = true; + let identity_manager_impl_address = identity_manager_impl.address(); let init_call_data = ContractAbi::InitializeCall { @@ -173,8 +185,6 @@ pub async fn spawn_mock_chain( batch_insertion_verifiers: insert_verifiers.address(), batch_update_verifiers: update_verifiers.address(), semaphore_verifier: semaphore_verifier.address(), - enable_state_bridge, - state_bridge: state_bridge_address, }; let init_call_encoded: Bytes = Bytes::from(init_call_data.encode()); @@ -190,6 +200,12 @@ pub async fn spawn_mock_chain( client.clone(), ); + identity_manager + .method::<_, ()>("initializeV2", delete_verifiers.address())? + .send() + .await? + .await?; + Ok(MockChain { anvil: chain, private_key, diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 182a3e35..a530a014 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -48,21 +48,25 @@ pub mod prelude { pub use super::prover_mock::ProverService; pub use super::{ abi as ContractAbi, generate_reference_proof_json, generate_test_identities, - init_tracing_subscriber, spawn_app, spawn_deps, spawn_mock_prover, test_inclusion_proof, - test_insert_identity, test_verify_proof, test_verify_proof_on_chain, + init_tracing_subscriber, spawn_app, spawn_deps, spawn_mock_deletion_prover, + spawn_mock_insertion_prover, test_inclusion_proof, test_insert_identity, test_verify_proof, + test_verify_proof_on_chain, }; } use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}; +use std::str::FromStr; use std::sync::Arc; use futures::stream::FuturesUnordered; use futures::StreamExt; use hyper::StatusCode; +use signup_sequencer::identity_tree::Status; use self::chain_mock::{spawn_mock_chain, MockChain, SpecialisedContract}; use self::prelude::*; +use self::prover_mock::ProverType; #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] @@ -270,19 +274,150 @@ pub async fn test_inclusion_proof( } } +#[instrument(skip_all)] +pub async fn test_inclusion_status( + uri: &str, + client: &Client, + leaf: &Hash, + expected_status: Status, +) { + for _i in 1..21 { + let body = construct_inclusion_proof_body(leaf); + info!(?uri, "Contacting"); + let req = Request::builder() + .method("POST") + .uri(uri.to_owned() + "/inclusionProof") + .header("Content-Type", "application/json") + .body(body) + .expect("Failed to create inclusion proof hyper::Body"); + + let mut response = client + .request(req) + .await + .expect("Failed to execute request."); + + let bytes = hyper::body::to_bytes(response.body_mut()) + .await + .expect("Failed to convert response body to bytes"); + let result = String::from_utf8(bytes.into_iter().collect()) + .expect("Could not parse response bytes to utf-8"); + let result_json = serde_json::from_str::(&result) + .expect("Failed to parse response as json"); + let status = result_json["status"] + .as_str() + .expect("Failed to get status"); + + assert_eq!( + expected_status, + Status::from_str(status).expect("Could not convert str to Status") + ); + } +} + +#[instrument(skip_all)] +pub async fn test_delete_identity( + uri: &str, + client: &Client, + ref_tree: &mut PoseidonTree, + test_leaves: &[Field], + leaf_index: usize, + expect_failure: bool, +) -> (merkle_tree::Proof, Field) { + let body = construct_delete_identity_body(&test_leaves[leaf_index]); + + let req = Request::builder() + .method("POST") + .uri(uri.to_owned() + "/deleteIdentity") + .header("Content-Type", "application/json") + .body(body) + .expect("Failed to create insert identity hyper::Body"); + + let mut response = client + .request(req) + .await + .expect("Failed to execute request."); + let bytes = hyper::body::to_bytes(response.body_mut()) + .await + .expect("Failed to convert response body to bytes"); + + if expect_failure { + assert!(!response.status().is_success()); + } else { + assert!(response.status().is_success()); + assert!(bytes.is_empty()); + } + + ref_tree.set(leaf_index, Hash::ZERO); + (ref_tree.proof(leaf_index).unwrap(), ref_tree.root()) +} + +#[instrument(skip_all)] +pub async fn test_recover_identity( + uri: &str, + client: &Client, + ref_tree: &mut PoseidonTree, + test_leaves: &[Field], + previous_leaf_index: usize, + new_leaf: Field, + new_leaf_index: usize, + expect_failure: bool, +) -> (merkle_tree::Proof, Field) { + let previous_leaf = test_leaves[previous_leaf_index]; + + let body = construct_recover_identity_body(&previous_leaf, &new_leaf); + + let req = Request::builder() + .method("POST") + .uri(uri.to_owned() + "/recoverIdentity") + .header("Content-Type", "application/json") + .body(body) + .expect("Failed to create insert identity hyper::Body"); + + let mut response = client + .request(req) + .await + .expect("Failed to execute request."); + + let bytes = hyper::body::to_bytes(response.body_mut()) + .await + .expect("Failed to convert response body to bytes"); + + if expect_failure { + assert!(!response.status().is_success()); + } else { + assert!(response.status().is_success()); + assert!(bytes.is_empty()); + } + + // TODO: Note that recovery order is non-deterministic and therefore we cannot + // easily keep the ref_tree in sync with the sequencer's version of the + // tree. In the future, we could consider tracking updates to the tree in a + // different way like listening to event emission. + ref_tree.set(previous_leaf_index, Hash::ZERO); + // Continuing on the note above, while the replacement identity is be + // inserted as a new identity, it is not deterministic and if there are multiple + // recovery requests, it is possible that the sequencer tree is ordered in a + // different way than the ref_tree + ref_tree.set(new_leaf_index, new_leaf); + (ref_tree.proof(new_leaf_index).unwrap(), ref_tree.root()) +} + #[instrument(skip_all)] pub async fn test_add_batch_size( uri: impl Into, prover_url: impl Into, batch_size: u64, + prover_type: ProverType, client: &Client, ) -> anyhow::Result<()> { let prover_url_string: String = prover_url.into(); + let body = Body::from( json!({ "url": prover_url_string, "batchSize": batch_size, - "timeoutSeconds": 3 + "timeoutSeconds": 3, + "proverType": prover_type }) .to_string(), ); @@ -306,9 +441,11 @@ pub async fn test_remove_batch_size( uri: impl Into, batch_size: u64, client: &Client, + prover_type: ProverType, expect_failure: bool, ) -> anyhow::Result<()> { - let body = Body::from(json!({ "batchSize": batch_size }).to_string()); + let body = + Body::from(json!({ "batchSize": batch_size, "proverType": prover_type }).to_string()); let request = Request::builder() .method("POST") .uri(uri.into() + "/removeBatchSize") @@ -376,6 +513,28 @@ fn construct_inclusion_proof_body(identity_commitment: &Hash) -> Body { ) } +fn construct_delete_identity_body(identity_commitment: &Hash) -> Body { + Body::from( + json!({ + "identityCommitment": identity_commitment, + }) + .to_string(), + ) +} + +fn construct_recover_identity_body( + prev_identity_commitment: &Hash, + new_identity_commitment: &Hash, +) -> Body { + Body::from( + json!({ + "previousIdentityCommitment":prev_identity_commitment , + "newIdentityCommitment": new_identity_commitment, + }) + .to_string(), + ) +} + fn construct_insert_identity_body(identity_commitment: &Field) -> Body { Body::from( json!({ @@ -440,38 +599,72 @@ struct CompiledContract { pub async fn spawn_deps( initial_root: U256, - batch_sizes: &[usize], + insertion_batch_sizes: &[usize], + deletion_batch_sizes: &[usize], tree_depth: u8, ) -> anyhow::Result<( MockChain, DockerContainerGuard, HashMap, + HashMap, micro_oz::ServerHandle, )> { - let chain = spawn_mock_chain(initial_root, batch_sizes, tree_depth); + let chain = spawn_mock_chain( + initial_root, + insertion_batch_sizes, + deletion_batch_sizes, + tree_depth, + ); + let db_container = spawn_db(); - let prover_futures = FuturesUnordered::new(); - for batch_size in batch_sizes { - prover_futures.push(spawn_mock_prover(*batch_size)); + let insertion_prover_futures = FuturesUnordered::new(); + for batch_size in insertion_batch_sizes { + insertion_prover_futures.push(spawn_mock_insertion_prover(*batch_size, tree_depth)); + } + + let deletion_prover_futures = FuturesUnordered::new(); + for batch_size in deletion_batch_sizes { + deletion_prover_futures.push(spawn_mock_deletion_prover(*batch_size, tree_depth)); } - let (chain, db_container, provers) = - tokio::join!(chain, db_container, prover_futures.collect::>()); + let (chain, db_container, insertion_provers, deletion_provers) = tokio::join!( + chain, + db_container, + insertion_prover_futures.collect::>(), + deletion_prover_futures.collect::>() + ); let chain = chain?; let signing_key = SigningKey::from_bytes(chain.private_key.as_bytes())?; let micro_oz = micro_oz::spawn(chain.anvil.endpoint(), signing_key).await?; - let provers = provers.into_iter().collect::, _>>()?; + let insertion_provers = insertion_provers + .into_iter() + .collect::, _>>()?; - let prover_map = provers + let insertion_prover_map = insertion_provers .into_iter() .map(|prover| (prover.batch_size(), prover)) - .collect(); + .collect::>(); + + let deletion_provers = deletion_provers + .into_iter() + .collect::, _>>()?; - Ok((chain, db_container?, prover_map, micro_oz)) + let deletion_prover_map = deletion_provers + .into_iter() + .map(|prover| (prover.batch_size(), prover)) + .collect::>(); + + Ok(( + chain, + db_container?, + insertion_prover_map, + deletion_prover_map, + micro_oz, + )) } async fn spawn_db() -> anyhow::Result { @@ -480,8 +673,24 @@ async fn spawn_db() -> anyhow::Result { Ok(db_container) } -pub async fn spawn_mock_prover(batch_size: usize) -> anyhow::Result { - let mock_prover_service = prover_mock::ProverService::new(batch_size).await?; +pub async fn spawn_mock_insertion_prover( + batch_size: usize, + tree_depth: u8, +) -> anyhow::Result { + let mock_prover_service = + prover_mock::ProverService::new(batch_size, tree_depth, prover_mock::ProverType::Insertion) + .await?; + + Ok(mock_prover_service) +} + +pub async fn spawn_mock_deletion_prover( + batch_size: usize, + tree_depth: u8, +) -> anyhow::Result { + let mock_prover_service = + prover_mock::ProverService::new(batch_size, tree_depth, prover_mock::ProverType::Deletion) + .await?; Ok(mock_prover_service) } diff --git a/tests/common/prover_mock.rs b/tests/common/prover_mock.rs index d0bf5c33..6aaa4fb8 100644 --- a/tests/common/prover_mock.rs +++ b/tests/common/prover_mock.rs @@ -36,7 +36,7 @@ impl Display for ProverError { /// The input to the prover. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -struct ProofInput { +struct InsertionProofInput { input_hash: U256, start_index: u32, pre_root: U256, @@ -45,6 +45,22 @@ struct ProofInput { merkle_proofs: Vec>, } +// TODO: ideally we just import the InsertionProofInput and DeletionProofInput +// from the signup sequencer so that we can know e2e breaks when any interface +// changes occur + +/// The input to the prover. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct DeletionProofInput { + input_hash: U256, + pre_root: U256, + post_root: U256, + packed_deletion_indices: Vec, + identity_commitments: Vec, + merkle_proofs: Vec>, +} + /// The proof response from the prover. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Proof { @@ -91,14 +107,35 @@ impl ProveResponse { /// The mock prover service. pub struct ProverService { - server: Handle, - inner: Arc>, - address: SocketAddr, - batch_size: usize, + server: Handle, + inner: Arc>, + address: SocketAddr, + batch_size: usize, + prover_type: ProverType, +} + +// TODO: we could just import this from the sequencer +#[derive(Debug, Copy, Clone, sqlx::Type, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +#[sqlx(type_name = "prover_enum", rename_all = "PascalCase")] +pub enum ProverType { + #[default] + Insertion, + Deletion, +} + +impl std::fmt::Display for ProverType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + ProverType::Insertion => write!(f, "insertion"), + ProverType::Deletion => write!(f, "deletion"), + } + } } struct Prover { is_available: bool, + tree_depth: u8, } impl ProverService { @@ -108,17 +145,41 @@ impl ProverService { /// It provides only a single endpoint for now, `/prove` in order to match /// the full service (`semaphore-mtb`). This can be extended in the future /// if needed. - pub async fn new(batch_size: usize) -> anyhow::Result { + pub async fn new( + batch_size: usize, + tree_depth: u8, + prover_type: ProverType, + ) -> anyhow::Result { async fn prove( - State(state): State>>, - Json(input): Json, + state: State>>, + Json(input): Json, ) -> Result, StatusCode> { let state = state.lock().await; - state.prove(input).map(Json) + // Attempt to deserialize into InsertionProofInput + if let Ok(deserialized_insertion_input) = + serde_json::from_value::(input.clone()) + { + return state + .prove_insertion(deserialized_insertion_input) + .map(Json); + } + + // If the above fails, attempt to deserialize into DeletionProofInput + if let Ok(deserialized_deletion_input) = + serde_json::from_value::(input) + { + return state.prove_deletion(deserialized_deletion_input).map(Json); + } + + // If both fail, return an error + Err(StatusCode::BAD_REQUEST) } - let inner = Arc::new(Mutex::new(Prover { is_available: true })); + let inner = Arc::new(Mutex::new(Prover { + is_available: true, + tree_depth, + })); let state = inner.clone(); let app = Router::new().route("/prove", post(prove)).with_state(state); @@ -146,6 +207,7 @@ impl ProverService { inner, address, batch_size, + prover_type, }; Ok(service) @@ -169,6 +231,10 @@ impl ProverService { self.batch_size } + pub fn prover_type(&self) -> ProverType { + self.prover_type + } + /// Produces an arg string that's compatible with this prover - can be used /// as is in the CLI args /// @@ -180,18 +246,19 @@ impl ProverService { /// Produces an arg string that's compatible with this prover - needs to be /// wrapped in an array /// - /// e.g. `{"url": "http://localhost:3001","batch_size": 3,"timeout_s": 30}` + /// e.g. `{"url": "http://localhost:3001","batch_size": 3,"timeout_s": 30,"prover_type": "insertion"}` pub fn arg_string_single(&self) -> String { format!( - r#"{{"url": "{}","batch_size": {},"timeout_s": 30}}"#, + r#"{{"url": "{}","batch_size": {},"timeout_s": 30, "prover_type": "{}"}}"#, self.url(), - self.batch_size + self.batch_size, + self.prover_type ) } } impl Prover { - fn prove(&self, input: ProofInput) -> Result { + fn prove_insertion(&self, input: InsertionProofInput) -> Result { if !self.is_available { return Err(StatusCode::SERVICE_UNAVAILABLE); } @@ -245,6 +312,66 @@ impl Prover { ])) } + fn prove_deletion(&self, input: DeletionProofInput) -> Result { + if !self.is_available { + return Err(StatusCode::SERVICE_UNAVAILABLE); + } + + // Calculate the input hash based on the prover parameters. + let input_hash = Self::compute_deletion_proof_input_hash( + input.packed_deletion_indices.clone(), + input.pre_root, + input.post_root, + ); + + // If the hashes aren't the same something's wrong so we return an error. + if input_hash != input.input_hash { + return Ok(ProveResponse::failure("42", "Input hash mismatch.")); + } + + // Next we verify the merkle proofs. + let empty_leaf = U256::zero(); + let mut last_root = input.pre_root; + + let mut deletion_indices = vec![]; + + for bytes in input.packed_deletion_indices.chunks(4) { + let mut val: [u8; 4] = Default::default(); + val.copy_from_slice(bytes); + deletion_indices.push(u32::from_be_bytes(val)); + } + + for (leaf_index, merkle_proof) in deletion_indices.iter().zip(input.merkle_proofs) { + if *leaf_index == 2u32.pow(self.tree_depth as u32) { + continue; + } + + let proof = + Self::reconstruct_proof_with_directions(*leaf_index as usize, &merkle_proof); + + last_root = proof.root(empty_leaf.into()).into(); + } + + // If the final root doesn't match the post root something's broken so we error. + if last_root != input.post_root { + return Ok(ProveResponse::failure( + "43", + "Merkle proof verification failure.", + )); + } + + Ok(ProveResponse::success([ + "0x2".into(), + input_hash, + "0x2413396a2af3add6fbe8137cfe7657917e31a5cdab0b7d1d645bd5eeb47ba601".into(), + "0x1ad029539528b32ba70964ce43dbf9bba2501cdb3aaa04e4d58982e2f6c34752".into(), + "0x5bb975296032b135458bd49f92d5e9d363367804440d4692708de92e887cf17".into(), + "0x14932600f53a1ceb11d79a7bdd9688a2f8d1919176f257f132587b2b3274c41e".into(), + "0x13d7b19c7b67bf5d3adf2ac2d3885fd5d49435b6069c0656939cd1fb7bef9dc9".into(), + "0x142e14f90c49c79b4edf5f6b7acbcdb0b0f376a4311fc036f1006679bd53ca9e".into(), + ])) + } + /// Reconstructs the proof with directions as required by `semaphore-rs`. /// /// This allows us to utilise the proof verification procedure from that @@ -282,7 +409,7 @@ impl Prover { /// StartIndex || PreRoot || PostRoot || IdComms[0] || IdComms[1] || ... || IdComms[batchSize-1] /// 32 || 256 || 256 || 256 || 256 || ... || 256 bits /// ``` - fn calculate_identity_registration_input_hash(input: &ProofInput) -> U256 { + fn calculate_identity_registration_input_hash(input: &InsertionProofInput) -> U256 { // Calculate the input hash as described by the prover. let mut hashable_bytes: Vec = vec![]; let mut buffer: [u8; size_of::()] = Default::default(); @@ -299,4 +426,37 @@ impl Prover { keccak256(hashable_bytes).into() } + + /// Calculates the input hash based on the `input` parameters to the prover. + /// + /// We keccak hash all input to save verification gas. Inputs are arranged + /// as follows: + /// ``` + /// PackedDeletionIndices || PreRoot || PostRoot + /// 32 bits * batchSize || 256 || 256 + /// ``` + pub fn compute_deletion_proof_input_hash( + packed_deletion_indices: Vec, + pre_root: U256, + post_root: U256, + ) -> U256 { + // Convert pre_root and post_root to bytes + let mut pre_root_bytes = vec![0u8; 32]; + pre_root.to_big_endian(&mut pre_root_bytes); + + let mut post_root_bytes = vec![0u8; 32]; + post_root.to_big_endian(&mut post_root_bytes); + + let mut bytes = vec![]; + + // Append packed_deletion_indices + bytes.extend_from_slice(&packed_deletion_indices); + + // Append pre_root and post_root bytes + bytes.extend_from_slice(&pre_root_bytes); + bytes.extend_from_slice(&post_root_bytes); + + // Compute and return the Keccak-256 hash + keccak256(bytes).into() + } } diff --git a/tests/delete_identities.rs b/tests/delete_identities.rs new file mode 100644 index 00000000..3cf97ed6 --- /dev/null +++ b/tests/delete_identities.rs @@ -0,0 +1,160 @@ +mod common; + +use common::prelude::*; + +use crate::common::test_delete_identity; + +const SUPPORTED_DEPTH: usize = 18; +const IDLE_TIME: u64 = 7; + +#[tokio::test] +#[serial_test::serial] +async fn delete_identities() -> anyhow::Result<()> { + // Initialize logging for the test. + init_tracing_subscriber(); + info!("Starting integration test"); + + let insertion_batch_size: usize = 8; + let deletion_batch_size: usize = 3; + let batch_deletion_timeout_seconds: usize = 10; + + #[allow(clippy::cast_possible_truncation)] + let tree_depth: u8 = SUPPORTED_DEPTH as u8; + + let mut ref_tree = PoseidonTree::new(SUPPORTED_DEPTH + 1, ruint::Uint::ZERO); + let initial_root: U256 = ref_tree.root().into(); + + let (mock_chain, db_container, insertion_prover_map, deletion_prover_map, micro_oz) = + spawn_deps( + initial_root, + &[insertion_batch_size], + &[deletion_batch_size], + tree_depth, + ) + .await?; + + let mock_insertion_prover = &insertion_prover_map[&insertion_batch_size]; + let mock_deletion_prover = &deletion_prover_map[&deletion_batch_size]; + + let port = db_container.port(); + let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); + + let mut options = Options::try_parse_from([ + "signup-sequencer", + "--identity-manager-address", + "0x0000000000000000000000000000000000000000", // placeholder, updated below + "--database", + &db_url, + "--database-max-connections", + "1", + "--tree-depth", + &format!("{tree_depth}"), + "--prover-urls", + &format!( + "[{}, {}]", + mock_insertion_prover.arg_string_single(), + mock_deletion_prover.arg_string_single() + ), + "--batch-timeout-seconds", + "10", + "--batch-deletion-timeout-seconds", + &format!("{batch_deletion_timeout_seconds}"), + "--min-batch-deletion-size", + &format!("{deletion_batch_size}"), + "--dense-tree-prefix-depth", + "10", + "--tree-gc-threshold", + "1", + "--oz-api-key", + "", + "--oz-api-secret", + "", + "--oz-api-url", + µ_oz.endpoint(), + "--oz-address", + &format!("{:?}", micro_oz.address()), + ]) + .context("Failed to create options")?; + + options.server.server = Url::parse("http://127.0.0.1:0/").expect("Failed to parse URL"); + + options.app.contracts.identity_manager_address = mock_chain.identity_manager.address(); + options.app.ethereum.ethereum_provider = Url::parse(&mock_chain.anvil.endpoint()).expect( + " + Failed to parse Anvil url", + ); + + let (app, local_addr) = spawn_app(options.clone()) + .await + .expect("Failed to spawn app."); + + let test_identities = generate_test_identities(insertion_batch_size * 3); + let identities_ref: Vec = test_identities + .iter() + .map(|i| Hash::from_str_radix(i, 16).unwrap()) + .collect(); + + let uri = "http://".to_owned() + &local_addr.to_string(); + let client = Client::new(); + + // Insert enough identities to trigger an batch to be sent to the blockchain. + for i in 0..insertion_batch_size { + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, i).await; + } + + tokio::time::sleep(Duration::from_secs(IDLE_TIME)).await; + + // Check that we can also get these inclusion proofs back. + for i in 0..insertion_batch_size { + test_inclusion_proof( + &uri, + &client, + i, + &ref_tree, + &Hash::from_str_radix(&test_identities[i], 16) + .expect("Failed to parse Hash from test leaf"), + false, + ) + .await; + } + + // Delete enough identities to trigger a batch + for i in 0..deletion_batch_size { + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, i, false).await; + } + + tokio::time::sleep(Duration::from_secs(IDLE_TIME * 8)).await; + + // Ensure that identities have been deleted + for i in 0..deletion_batch_size { + test_inclusion_proof( + &uri, + &client, + i, + &ref_tree, + &Hash::from_str_radix(&test_identities[i], 16) + .expect("Failed to parse Hash from test leaf"), + true, + ) + .await; + } + + // Expect failure when deleting an identity that has already been deleted + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, 0, true).await; + + // Expect failure when deleting an identity that can not be found + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, 12, true).await; + + // Shutdown the app properly for the final time + shutdown(); + app.await.unwrap(); + for (_, prover) in insertion_prover_map.into_iter() { + prover.stop(); + } + for (_, prover) in deletion_prover_map.into_iter() { + prover.stop(); + } + reset_shutdown(); + + Ok(()) +} diff --git a/tests/delete_padded_identity.rs b/tests/delete_padded_identity.rs new file mode 100644 index 00000000..298b8832 --- /dev/null +++ b/tests/delete_padded_identity.rs @@ -0,0 +1,182 @@ +mod common; + +use common::prelude::*; + +use crate::common::test_delete_identity; + +const SUPPORTED_DEPTH: u8 = 18; +const IDLE_TIME: u64 = 7; + +#[tokio::test] +#[serial_test::serial] +async fn delete_padded_identity() -> anyhow::Result<()> { + // Initialize logging for the test. + init_tracing_subscriber(); + info!("Starting integration test"); + + let insertion_batch_size: usize = 8; + let deletion_batch_size: usize = 3; + let batch_deletion_timeout_seconds: usize = 10; + + #[allow(clippy::cast_possible_truncation)] + let tree_depth: u8 = SUPPORTED_DEPTH; + + let mut ref_tree = PoseidonTree::new((SUPPORTED_DEPTH + 1).into(), ruint::Uint::ZERO); + let initial_root: U256 = ref_tree.root().into(); + + let (mock_chain, db_container, insertion_prover_map, deletion_prover_map, micro_oz) = + spawn_deps( + initial_root, + &[insertion_batch_size], + &[deletion_batch_size], + tree_depth, + ) + .await?; + + let mock_insertion_prover = &insertion_prover_map[&insertion_batch_size]; + let mock_deletion_prover = &deletion_prover_map[&deletion_batch_size]; + + let port = db_container.port(); + let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); + + let mut options = Options::try_parse_from([ + "signup-sequencer", + "--identity-manager-address", + "0x0000000000000000000000000000000000000000", // placeholder, updated below + "--database", + &db_url, + "--database-max-connections", + "1", + "--tree-depth", + &format!("{tree_depth}"), + "--prover-urls", + &format!( + "[{}, {}]", + mock_insertion_prover.arg_string_single(), + mock_deletion_prover.arg_string_single() + ), + "--batch-timeout-seconds", + "10", + "--batch-deletion-timeout-seconds", + &format!("{batch_deletion_timeout_seconds}"), + "--min-batch-deletion-size", + &format!("{deletion_batch_size}"), + "--dense-tree-prefix-depth", + "10", + "--tree-gc-threshold", + "1", + "--oz-api-key", + "", + "--oz-api-secret", + "", + "--oz-api-url", + µ_oz.endpoint(), + "--oz-address", + &format!("{:?}", micro_oz.address()), + ]) + .context("Failed to create options")?; + + options.server.server = Url::parse("http://127.0.0.1:0/").expect("Failed to parse URL"); + + options.app.contracts.identity_manager_address = mock_chain.identity_manager.address(); + options.app.ethereum.ethereum_provider = Url::parse(&mock_chain.anvil.endpoint()).expect( + " + Failed to parse Anvil url", + ); + + let (app, local_addr) = spawn_app(options.clone()) + .await + .expect("Failed to spawn app."); + + let test_identities = generate_test_identities(insertion_batch_size * 3); + let identities_ref: Vec = test_identities + .iter() + .map(|i| Hash::from_str_radix(i, 16).unwrap()) + .collect(); + + let uri = "http://".to_owned() + &local_addr.to_string(); + let client = Client::new(); + + // Insert enough identities to trigger an batch to be sent to the blockchain. + for i in 0..insertion_batch_size { + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, i).await; + } + + tokio::time::sleep(Duration::from_secs(IDLE_TIME)).await; + + // Check that we can also get these inclusion proofs back. + for i in 0..insertion_batch_size { + test_inclusion_proof( + &uri, + &client, + i, + &ref_tree, + &Hash::from_str_radix(&test_identities[i], 16) + .expect("Failed to parse Hash from test leaf"), + false, + ) + .await; + } + + // delete only the first and second identities + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, 0, false).await; + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, 1, false).await; + + tokio::time::sleep(Duration::from_secs( + batch_deletion_timeout_seconds as u64 * 3, + )) + .await; + + // make sure that identity 3 wasn't deleted + test_inclusion_proof( + &uri, + &client, + 2, + &ref_tree, + &Hash::from_str_radix(&test_identities[2], 16) + .expect("Failed to parse Hash from test leaf"), + false, + ) + .await; + + // Ensure that the first and second identities were deleted + test_inclusion_proof( + &uri, + &client, + 0, + &ref_tree, + &Hash::from_str_radix(&test_identities[0], 16) + .expect("Failed to parse Hash from test leaf"), + true, + ) + .await; + test_inclusion_proof( + &uri, + &client, + 1, + &ref_tree, + &Hash::from_str_radix(&test_identities[1], 16) + .expect("Failed to parse Hash from test leaf"), + true, + ) + .await; + + // Expect failure when deleting an identity that has already been deleted + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, 0, true).await; + + // Expect failure when deleting an identity that can not be found + test_delete_identity(&uri, &client, &mut ref_tree, &identities_ref, 12, true).await; + + // Shutdown the app properly for the final time + shutdown(); + app.await.unwrap(); + for (_, prover) in insertion_prover_map.into_iter() { + prover.stop(); + } + for (_, prover) in deletion_prover_map.into_iter() { + prover.stop(); + } + reset_shutdown(); + + Ok(()) +} diff --git a/tests/dynamic_batch_sizes.rs b/tests/dynamic_batch_sizes.rs index 5905a1a3..8947b23f 100644 --- a/tests/dynamic_batch_sizes.rs +++ b/tests/dynamic_batch_sizes.rs @@ -25,10 +25,10 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { let mut ref_tree = PoseidonTree::new(SUPPORTED_DEPTH + 1, ruint::Uint::ZERO); let initial_root: U256 = ref_tree.root().into(); - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size, second_batch_size], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], tree_depth).await?; - let prover_mock = &prover_map[&batch_size]; + let prover_mock = &insertion_prover_map[&batch_size]; let port = db_container.port(); let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); @@ -127,10 +127,17 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { .await; // Add a new prover for batch sizes of two. - let second_prover = spawn_mock_prover(second_batch_size).await?; - test_add_batch_size(&uri, second_prover.url(), second_batch_size as u64, &client) - .await - .expect("Failed to add batch size."); + let second_prover = spawn_mock_insertion_prover(second_batch_size, tree_depth).await?; + + test_add_batch_size( + &uri, + second_prover.url(), + second_batch_size as u64, + second_prover.prover_type(), + &client, + ) + .await + .expect("Failed to add batch size."); // Query for the available provers. let batch_sizes_uri: Uri = @@ -153,11 +160,14 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { "url": second_prover.url() + "/", "timeout_s": 3, "batch_size": second_batch_size, + "prover_type": "insertion", }, { "url": prover_mock.url() + "/", "timeout_s": 30, "batch_size": batch_size, + "prover_type": "insertion", + } ]) ); @@ -195,7 +205,14 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { .await; // Now if we remove the original prover, things should still work. - test_remove_batch_size(&uri, batch_size as u64, &client, false).await?; + test_remove_batch_size( + &uri, + batch_size as u64, + &client, + prover_mock.prover_type(), + false, + ) + .await?; // We should be able to insert less than a full batch successfully. test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, 5).await; @@ -216,7 +233,14 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { .await; // We should be unable to remove _all_ of the provers, however. - test_remove_batch_size(&uri, second_batch_size as u64, &client, true).await?; + test_remove_batch_size( + &uri, + second_batch_size as u64, + &client, + second_prover.prover_type(), + true, + ) + .await?; // So we should still be able to run a batch. test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, 6).await; @@ -239,7 +263,7 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); app.await.unwrap(); - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown(); diff --git a/tests/insert_identity_and_proofs.rs b/tests/insert_identity_and_proofs.rs index 5caaa9ef..71cfca83 100644 --- a/tests/insert_identity_and_proofs.rs +++ b/tests/insert_identity_and_proofs.rs @@ -19,10 +19,10 @@ async fn insert_identity_and_proofs() -> anyhow::Result<()> { let mut ref_tree = PoseidonTree::new(SUPPORTED_DEPTH + 1, ruint::Uint::ZERO); let initial_root: U256 = ref_tree.root().into(); - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], tree_depth).await?; - let prover_mock = &prover_map[&batch_size]; + let prover_mock = &insertion_prover_map[&batch_size]; let port = db_container.port(); let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); @@ -243,7 +243,7 @@ async fn insert_identity_and_proofs() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); app.await.unwrap(); - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown(); diff --git a/tests/malformed_payload.rs b/tests/malformed_payload.rs index 64d459a9..396fb093 100644 --- a/tests/malformed_payload.rs +++ b/tests/malformed_payload.rs @@ -17,10 +17,10 @@ async fn malformed_payload() -> anyhow::Result<()> { let batch_size: usize = 3; - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], tree_depth).await?; - let prover_mock = &prover_map[&batch_size]; + let prover_mock = &insertion_prover_map[&batch_size]; let port = db_container.port(); let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); @@ -97,7 +97,7 @@ async fn malformed_payload() -> anyhow::Result<()> { shutdown(); app.await?; - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown(); diff --git a/tests/multi_prover.rs b/tests/multi_prover.rs index ba282392..39f95497 100644 --- a/tests/multi_prover.rs +++ b/tests/multi_prover.rs @@ -19,11 +19,16 @@ async fn multi_prover() -> anyhow::Result<()> { let batch_size_3: usize = 3; let batch_size_10: usize = 10; - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size_3, batch_size_10], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = spawn_deps( + initial_root, + &[batch_size_3, batch_size_10], + &[], + tree_depth, + ) + .await?; - let prover_mock_batch_size_3 = &prover_map[&batch_size_3]; - let prover_mock_batch_size_10 = &prover_map[&batch_size_10]; + let prover_mock_batch_size_3 = &insertion_prover_map[&batch_size_3]; + let prover_mock_batch_size_10 = &insertion_prover_map[&batch_size_10]; let prover_arg_string = format!( "[{},{}]", @@ -132,7 +137,7 @@ async fn multi_prover() -> anyhow::Result<()> { shutdown(); app.await?; - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown(); diff --git a/tests/recover_identities.rs b/tests/recover_identities.rs new file mode 100644 index 00000000..f3e1c5da --- /dev/null +++ b/tests/recover_identities.rs @@ -0,0 +1,201 @@ +mod common; + +use common::prelude::*; +use signup_sequencer::identity_tree::Status; + +use crate::common::{test_inclusion_status, test_recover_identity}; +const SUPPORTED_DEPTH: usize = 18; +const IDLE_TIME: u64 = 7; + +#[tokio::test] +#[serial_test::serial] +async fn recover_identities() -> anyhow::Result<()> { + // Initialize logging for the test. + init_tracing_subscriber(); + info!("Starting integration test"); + + let insertion_batch_size: usize = 8; + let deletion_batch_size: usize = 3; + let batch_deletion_timeout_seconds: usize = 10; + + #[allow(clippy::cast_possible_truncation)] + let tree_depth: u8 = SUPPORTED_DEPTH as u8; + + let mut ref_tree = PoseidonTree::new(SUPPORTED_DEPTH + 1, ruint::Uint::ZERO); + let initial_root: U256 = ref_tree.root().into(); + + let (mock_chain, db_container, insertion_prover_map, deletion_prover_map, micro_oz) = + spawn_deps( + initial_root, + &[insertion_batch_size], + &[deletion_batch_size], + tree_depth, + ) + .await?; + + // Set the root history expirty to 15 seconds + let updated_root_history_expiry = U256::from(30); + mock_chain + .identity_manager + .method::<_, ()>("setRootHistoryExpiry", updated_root_history_expiry)? + .send() + .await? + .await?; + + let mock_insertion_prover = &insertion_prover_map[&insertion_batch_size]; + let mock_deletion_prover = &deletion_prover_map[&deletion_batch_size]; + + let port = db_container.port(); + let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); + + let mut options = Options::try_parse_from([ + "signup-sequencer", + "--identity-manager-address", + "0x0000000000000000000000000000000000000000", // placeholder, updated below + "--database", + &db_url, + "--database-max-connections", + "1", + "--tree-depth", + &format!("{tree_depth}"), + "--prover-urls", + &format!( + "[{}, {}]", + mock_insertion_prover.arg_string_single(), + mock_deletion_prover.arg_string_single() + ), + "--batch-timeout-seconds", + "10", + "--batch-deletion-timeout-seconds", + &format!("{batch_deletion_timeout_seconds}"), + "--min-batch-deletion-size", + &format!("{deletion_batch_size}"), + "--dense-tree-prefix-depth", + "10", + "--tree-gc-threshold", + "1", + "--oz-api-key", + "", + "--oz-api-secret", + "", + "--oz-api-url", + µ_oz.endpoint(), + "--oz-address", + &format!("{:?}", micro_oz.address()), + ]) + .context("Failed to create options")?; + + options.server.server = Url::parse("http://127.0.0.1:0/").expect("Failed to parse URL"); + + options.app.contracts.identity_manager_address = mock_chain.identity_manager.address(); + options.app.ethereum.ethereum_provider = Url::parse(&mock_chain.anvil.endpoint()).expect( + " + Failed to parse Anvil url", + ); + + let (app, local_addr) = spawn_app(options.clone()) + .await + .expect("Failed to spawn app."); + + let test_identities = generate_test_identities(insertion_batch_size * 3); + let identities_ref: Vec = test_identities + .iter() + .map(|i| Hash::from_str_radix(i, 16).unwrap()) + .collect(); + + let uri = "http://".to_owned() + &local_addr.to_string(); + let client = Client::new(); + + let mut next_leaf_index = 0; + // Insert enough identities to trigger an batch to be sent to the blockchain. + for i in 0..insertion_batch_size { + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, i).await; + + next_leaf_index += 1; + } + + tokio::time::sleep(Duration::from_secs(IDLE_TIME)).await; + // Check that we can also get these inclusion proofs back. + for i in 0..insertion_batch_size { + test_inclusion_proof(&uri, &client, i, &ref_tree, &identities_ref[i], false).await; + } + + // Insert enough recoveries to trigger a batch + for i in 0..deletion_batch_size { + // Delete the identity at i and replace it with an identity at the back of the + // test identities array + // TODO: we should update to a much cleaner approach + let recovery_leaf_index = test_identities.len() - i - 1; + + test_recover_identity( + &uri, + &client, + &mut ref_tree, + &identities_ref, + i, + identities_ref[recovery_leaf_index], + next_leaf_index, + false, + ) + .await; + + next_leaf_index += 1; + } + + tokio::time::sleep(Duration::from_secs(IDLE_TIME * 6)).await; + + // Ensure that identities have been deleted + for i in 0..deletion_batch_size { + let recovery_leaf_index = test_identities.len() - i - 1; + + test_inclusion_proof(&uri, &client, i, &ref_tree, &identities_ref[i], true).await; + + // Check that the replacement identity has not been inserted yet + test_inclusion_status( + &uri, + &client, + &identities_ref[recovery_leaf_index], + Status::New, + ) + .await; + } + + // Sleep for root expiry + tokio::time::sleep(Duration::from_secs(updated_root_history_expiry.as_u64())).await; + + // Insert enough identities to trigger an batch to be sent to the blockchain. + for i in insertion_batch_size..insertion_batch_size * 2 { + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, i).await; + next_leaf_index += 1; + } + + tokio::time::sleep(Duration::from_secs(IDLE_TIME * 8)).await; + + // Check that the replacement identities have been inserted + for i in 0..deletion_batch_size { + let recovery_leaf_index = test_identities.len() - i - 1; + + // Check that the replacement identity has a mined status after an insertion + // batch has completed + test_inclusion_status( + &uri, + &client, + &identities_ref[recovery_leaf_index], + Status::Mined, + ) + .await; + } + + // Shutdown the app properly for the final time + shutdown(); + app.await.unwrap(); + for (_, prover) in insertion_prover_map.into_iter() { + prover.stop(); + } + for (_, prover) in deletion_prover_map.into_iter() { + prover.stop(); + } + reset_shutdown(); + + Ok(()) +} diff --git a/tests/unavailable_prover.rs b/tests/unavailable_prover.rs index 18a852b0..db9f520c 100644 --- a/tests/unavailable_prover.rs +++ b/tests/unavailable_prover.rs @@ -16,10 +16,10 @@ async fn unavailable_prover() -> anyhow::Result<()> { let batch_size: usize = 3; - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], tree_depth).await?; - let prover_mock = &prover_map[&batch_size]; + let prover_mock = &insertion_prover_map[&batch_size]; prover_mock.set_availability(false).await; @@ -98,7 +98,7 @@ async fn unavailable_prover() -> anyhow::Result<()> { shutdown(); app.await?; - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown(); diff --git a/tests/validate_proof_with_age.rs b/tests/validate_proof_with_age.rs index db401113..2d51c9dc 100644 --- a/tests/validate_proof_with_age.rs +++ b/tests/validate_proof_with_age.rs @@ -21,10 +21,10 @@ async fn validate_proof_with_age() -> anyhow::Result<()> { let tree_depth: u8 = SUPPORTED_DEPTH as u8; let batch_size = 3; - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _deletion_prover_map, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], tree_depth).await?; - let prover_mock = &prover_map[&batch_size]; + let prover_mock = &insertion_prover_map[&batch_size]; let port = db_container.port(); let db_url = format!("postgres://postgres:postgres@localhost:{port}/database"); @@ -155,7 +155,7 @@ async fn validate_proof_with_age() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); app.await.unwrap(); - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown(); diff --git a/tests/validate_proofs.rs b/tests/validate_proofs.rs index 3a5b0278..5b501b37 100644 --- a/tests/validate_proofs.rs +++ b/tests/validate_proofs.rs @@ -19,10 +19,10 @@ async fn validate_proofs() -> anyhow::Result<()> { let tree_depth: u8 = SUPPORTED_DEPTH as u8; let batch_size = 3; - let (mock_chain, db_container, prover_map, micro_oz) = - spawn_deps(initial_root, &[batch_size], tree_depth).await?; + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], tree_depth).await?; - let prover_mock = &prover_map[&batch_size]; + let prover_mock = &insertion_prover_map[&batch_size]; let identity_manager = mock_chain.identity_manager.clone(); @@ -224,7 +224,7 @@ async fn validate_proofs() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); app.await.unwrap(); - for (_, prover) in prover_map.into_iter() { + for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } reset_shutdown();